EN VI

Rust - Why is Copy a supertrait of Pod in the bytemuck crate?

2024-03-10 18:30:08
Rust - Why is Copy a supertrait of Pod in the bytemuck crate?

According to bytemuck's doc here, Pod is only a marker trait. Its definition is as following:

pub unsafe trait Pod: Zeroable + Copy + 'static { }

My understanding of a "marker trait" is that: its purpose is to declare some types to have some traits (here I mean "trait" in English, a synonym of "characteristics") that cannot be described by functions/methods. In this way, others (especially the consumers of these types) know how to properly handle these types. For example, Copy is a marker trait. When marking a type as Copy, the Rust compiler knows when dealing a = b for this type, it should do a bitwise copy. Send is a also a marker trait. When marking, the compiler knows this type could be sent to another thread.

Come back to Pod. If I declare that my type is a Pod, why should I at least make my type a Copy? When I mark my type as Pod, I'm saying to bytemuck, "Hey, my type is a Pod. You can trust me without any doubt. My type is absolutely a Pod. You can now reinterpret some bytes as my type."

Is it because bytemuck wants to make sure any type that contains non-Copy types can't be marked as Pod? Since "A type is Copy" is indeed a necessary but not sufficient condition of "A type is Pod" (After all, how can a type be plain old data if it's even not Copy). In this way, for example, the developer won't accidentally include a non-Copy type (like Vec<u8> and String) in the custom struct.

If this is actually the reason, I'm still confused. I still need to mark an extremely large type as Copy only to mark it as Pod. The following struct is an example.

struct MyStruct {
    data: [u8; 10000000],
}

This is somewhat ridiculous. What if I accidentally trigger a bitwise copy of this type?

Isn't it a better idea not to make Copy a supertrait of Pod? I (as the code author) will take the full responsibility for every type that I mark as Pod.

Solution:

I am not familiar with bytemuck's internals, but I would guess this is a soundness requirement, as bytemuck certainly works with unsafe code to perform bit fiddling.

The actual specification of the Copy trait is that a type T can be Copy if a value x: T only "owns its bits" (as in Rust's ownership system). For instance, an integer is Copy because when you own an integer, you just own the bits that represent this integer, whereas when you own a Box<i32>, you don't just own the bits used to represent the box (which, in the end, is just a pointer). You also own what is pointed by the pointer.

A corollary of being Copy is that any value of a Copy type is that moving it is the same operation as cloneing it (which is why Clone is a supertrait of Copy). This is because moving a value in Rust is defined as a bitwise copy of the bits of the underlying representation, from one location to an other.

In particular, it is not true that having a type not being Copy prevents it from being bitwise copied: every value can be implicitely bitwise-copied whenever it is moved. So having your type which is a huge blob of data not being Copy does not prevent it from being bitwise copied around.

However, it is true that it is expected that Copy types are cheap to copy, because otherwise Rust prefers users having to explicitly write clone, to ensure that they consciously know they are doing an expensive operation.

For this reason, you might indeed not want to tag your type as Copy. To solve that problem, you could use the newtype pattern: create a type struct MyPublicStructure(MyStructure), which does not implement Copy. Implement Copy and Pod for the inner type. Then, simply use that type when you need to do some bit fiddling, and convert back to MyPublicStructure when you don't need to do bit fiddling anymore. This way, you can explicitly highlight the parts of your code where you need pay attention that you might accidentally implicitly perform an expensive copy, and your public API is clean.

Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login