Trait IntoBytes

unsafe trait IntoBytes

Types that can be converted to an immutable slice of initialized bytes.

Any IntoBytes type can be converted to a slice of initialized bytes of the same size. This is useful for efficiently serializing structured data as raw bytes.

Implementation

Do not implement this trait yourself! Instead, use #[derive(IntoBytes)]; e.g.:

# use zerocopy_derive::IntoBytes;
#[derive(IntoBytes)]
#[repr(C)]
struct MyStruct {
# /*
    ...
# */
}

#[derive(IntoBytes)]
#[repr(u8)]
enum MyEnum {
#   Variant0,
# /*
    ...
# */
}

This derive performs a sophisticated, compile-time safety analysis to determine whether a type is IntoBytes. See the derive documentation for guidance on how to interpret error messages produced by the derive's analysis.

Safety

This section describes what is required in order for T: IntoBytes, and what unsafe code may assume of such types. If you don't plan on implementing IntoBytes manually, and you don't plan on writing unsafe code that operates on IntoBytes types, then you don't need to read this section.

If T: IntoBytes, then unsafe code may assume that it is sound to treat any t: T as an immutable [u8] of length size_of_val(t). If a type is marked as IntoBytes which violates this contract, it may cause undefined behavior.

#[derive(IntoBytes)] only permits types which satisfy these requirements.

Provided Methods

fn as_bytes(self: &Self) -> &[u8]
where
    Self: Immutable

Gets the bytes of this value.

Examples

use zerocopy::IntoBytes;
# use zerocopy_derive::*;

#[derive(IntoBytes, Immutable)]
#[repr(C)]
struct PacketHeader {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
}

let header = PacketHeader {
    src_port: [0, 1],
    dst_port: [2, 3],
    length: [4, 5],
    checksum: [6, 7],
};

let bytes = header.as_bytes();

assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
fn as_mut_bytes(self: &mut Self) -> &mut [u8]
where
    Self: FromBytes

Gets the bytes of this value mutably.

Examples

use zerocopy::IntoBytes;
# use zerocopy_derive::*;

# #[derive(Eq, PartialEq, Debug)]
#[derive(FromBytes, IntoBytes, Immutable)]
#[repr(C)]
struct PacketHeader {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
}

let mut header = PacketHeader {
    src_port: [0, 1],
    dst_port: [2, 3],
    length: [4, 5],
    checksum: [6, 7],
};

let bytes = header.as_mut_bytes();

assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);

bytes.reverse();

assert_eq!(header, PacketHeader {
    src_port: [7, 6],
    dst_port: [5, 4],
    length: [3, 2],
    checksum: [1, 0],
});
fn write_to(self: &Self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>>
where
    Self: Immutable

Writes a copy of self to dst.

If dst.len() != size_of_val(self), write_to returns Err.

Examples

use zerocopy::IntoBytes;
# use zerocopy_derive::*;

#[derive(IntoBytes, Immutable)]
#[repr(C)]
struct PacketHeader {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
}

let header = PacketHeader {
    src_port: [0, 1],
    dst_port: [2, 3],
    length: [4, 5],
    checksum: [6, 7],
};

let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0];

header.write_to(&mut bytes[..]);

assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);

If too many or too few target bytes are provided, write_to returns Err and leaves the target bytes unmodified:

# use zerocopy::IntoBytes;
# let header = u128::MAX;
let mut excessive_bytes = &mut [0u8; 128][..];

let write_result = header.write_to(excessive_bytes);

assert!(write_result.is_err());
assert_eq!(excessive_bytes, [0u8; 128]);
fn write_to_prefix(self: &Self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>>
where
    Self: Immutable

Writes a copy of self to the prefix of dst.

write_to_prefix writes self to the first size_of_val(self) bytes of dst. If dst.len() < size_of_val(self), it returns Err.

Examples

use zerocopy::IntoBytes;
# use zerocopy_derive::*;

#[derive(IntoBytes, Immutable)]
#[repr(C)]
struct PacketHeader {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
}

let header = PacketHeader {
    src_port: [0, 1],
    dst_port: [2, 3],
    length: [4, 5],
    checksum: [6, 7],
};

let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

header.write_to_prefix(&mut bytes[..]);

assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

If insufficient target bytes are provided, write_to_prefix returns Err and leaves the target bytes unmodified:

# use zerocopy::IntoBytes;
# let header = u128::MAX;
let mut insufficient_bytes = &mut [0, 0][..];

let write_result = header.write_to_suffix(insufficient_bytes);

assert!(write_result.is_err());
assert_eq!(insufficient_bytes, [0, 0]);
fn write_to_suffix(self: &Self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>>
where
    Self: Immutable

Writes a copy of self to the suffix of dst.

write_to_suffix writes self to the last size_of_val(self) bytes of dst. If dst.len() < size_of_val(self), it returns Err.

Examples

use zerocopy::IntoBytes;
# use zerocopy_derive::*;

#[derive(IntoBytes, Immutable)]
#[repr(C)]
struct PacketHeader {
    src_port: [u8; 2],
    dst_port: [u8; 2],
    length: [u8; 2],
    checksum: [u8; 2],
}

let header = PacketHeader {
    src_port: [0, 1],
    dst_port: [2, 3],
    length: [4, 5],
    checksum: [6, 7],
};

let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

header.write_to_suffix(&mut bytes[..]);

assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]);

let mut insufficient_bytes = &mut [0, 0][..];

let write_result = header.write_to_suffix(insufficient_bytes);

assert!(write_result.is_err());
assert_eq!(insufficient_bytes, [0, 0]);

If insufficient target bytes are provided, write_to_suffix returns Err and leaves the target bytes unmodified:

# use zerocopy::IntoBytes;
# let header = u128::MAX;
let mut insufficient_bytes = &mut [0, 0][..];

let write_result = header.write_to_suffix(insufficient_bytes);

assert!(write_result.is_err());
assert_eq!(insufficient_bytes, [0, 0]);

Implementors