zerocopy

Derive Macro IntoBytes

#[derive(IntoBytes)]
Expand description

Analyzes whether a type is IntoBytes.

This derive analyzes, at compile time, whether the annotated type satisfies the safety conditions of IntoBytes and implements IntoBytes if it is sound to do so. This derive can be applied to structs and enums (see below for union support); e.g.:

#[derive(IntoBytes)]
#[repr(C)]
struct MyStruct {
    ...
}

#[derive(IntoBytes)]
#[repr(u8)]
enum MyEnum {
    ...
}

§Error Messages

On Rust toolchains prior to 1.78.0, due to the way that the custom derive for IntoBytes is implemented, you may get an error like this:

error[E0277]: the trait bound `(): PaddingFree<Foo, true>` is not satisfied
  --> lib.rs:23:10
   |
 1 | #[derive(IntoBytes)]
   |          ^^^^^^^^^ the trait `PaddingFree<Foo, true>` is not implemented for `()`
   |
   = help: the following implementations were found:
                  <() as PaddingFree<T, false>>

This error indicates that the type being annotated has padding bytes, which is illegal for IntoBytes types. Consider reducing the alignment of some fields by using types in the byteorder module, wrapping field types in Unalign, adding explicit struct fields where those padding bytes would be, or using #[repr(packed)]. See the Rust Reference’s page on type layout for more information about type layout and padding.

§Unions

Currently, union bit validity is up in the air, and so zerocopy does not support #[derive(IntoBytes)] on unions by default. However, implementing IntoBytes on a union type is likely sound on all existing Rust toolchains - it’s just that it may become unsound in the future. You can opt-in to #[derive(IntoBytes)] support on unions by passing the unstable zerocopy_derive_union_into_bytes cfg:

$ RUSTFLAGS='--cfg zerocopy_derive_union_into_bytes' cargo build

However, it is your responsibility to ensure that this derive is sound on the specific versions of the Rust toolchain you are using! We make no stability or soundness guarantees regarding this cfg, and may remove it at any point.

We are actively working with Rust to stabilize the necessary language guarantees to support this in a forwards-compatible way, which will enable us to remove the cfg gate. As part of this effort, we need to know how much demand there is for this feature. If you would like to use IntoBytes on unions, please let us know.

§Analysis

This section describes, roughly, the analysis performed by this derive to determine whether it is sound to implement IntoBytes for a given type. Unless you are modifying the implementation of this derive, or attempting to manually implement IntoBytes for a type yourself, you don’t need to read this section.

If a type has the following properties, then this derive can implement IntoBytes for that type:

  • If the type is a struct, its fields must be IntoBytes. Additionally:
    • if the type is repr(transparent) or repr(packed), it is IntoBytes if its fields are IntoBytes; else,
    • if the type is repr(C) with at most one field, it is IntoBytes if its field is IntoBytes; else,
    • if the type has no generic parameters, it is IntoBytes if the type is sized and has no padding bytes; else,
    • if the type is repr(C), its fields must be Unaligned.
  • If the type is an enum:
    • It must have a defined representation (reprs C, u8, u16, u32, u64, usize, i8, i16, i32, i64, or isize).
    • It must have no padding bytes.
    • Its fields must be IntoBytes.

This analysis is subject to change. Unsafe code may only rely on the documented safety conditions of FromBytes, and must not rely on the implementation details of this derive.