Trait FromBytes
pub unsafe trait FromBytes: FromZeros
Types for which any bit pattern is valid.
Any memory region of the appropriate length which contains initialized bytes
can be viewed as any FromBytes type with no runtime overhead. This is
useful for efficiently parsing bytes as structured data.
Warning: Padding bytes
Note that, when a value is moved or copied, only the non-padding bytes of that value are guaranteed to be preserved. It is unsound to assume that values written to padding bytes are preserved after a move or copy. For example, the following is unsound:
use ;
use FromZeros;
# use *;
// Assume `Foo` is a type with padding bytes.
let mut foo: Foo = default;
zero;
// UNSOUND: Although `FromZeros::zero` writes zeros to all bytes of `foo`,
// those writes are not guaranteed to be preserved in padding bytes when
// `foo` is moved, so this may expose padding bytes as `u8`s.
let foo_bytes: = unsafe ;
Implementation
Do not implement this trait yourself! Instead, use
#[derive(FromBytes)]; e.g.:
# use ;
union MyUnion
This derive performs a sophisticated, compile-time safety analysis to
determine whether a type is FromBytes.
Safety
This section describes what is required in order for T: FromBytes, and
what unsafe code may assume of such types. If you don't plan on implementing
FromBytes manually, and you don't plan on writing unsafe code that
operates on FromBytes types, then you don't need to read this section.
If T: FromBytes, then unsafe code may assume that it is sound to produce a
T whose bytes are initialized to any sequence of valid u8s (in other
words, any byte value which is not uninitialized). If a type is marked as
FromBytes which violates this contract, it may cause undefined behavior.
#[derive(FromBytes)] only permits types which satisfy these
requirements.
Provided Methods
fn ref_from_bytes(source: &[u8]) -> Result<&Self, CastError<&[u8], Self>> where Self: KnownLayout + Immutable,Interprets the given
sourceas a&Self.This method attempts to return a reference to
sourceinterpreted as aSelf. If the length ofsourceis not a valid size ofSelf, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. Attempting to use this method on such types results in a compile-time assertion error; e.g.:
use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These bytes encode a `Packet`. let bytes = &; let packet = ref_from_bytes.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_bytes_static_size(source: &[u8]) -> Option<&format::LocoPacket> { zerocopy::FromBytes::ref_from_bytes(source).ok() }Assembly
bench_ref_from_bytes_static_size: mov ecx, edi and ecx, 1 xor rsi, 6 xor eax, eax or rsi, rcx cmove rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 700 Total Cycles: 240 Total uOps: 800 Dispatch Width: 4 uOps Per Cycle: 3.33 IPC: 2.92 Block RThroughput: 2.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 mov ecx, edi 1 1 0.33 and ecx, 1 1 1 0.33 xor rsi, 6 1 0 0.25 xor eax, eax 1 1 0.33 or rsi, rcx 2 2 0.67 cmove rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 2.33 2.33 - 2.34 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.01 0.98 - 0.01 - - mov ecx, edi - - 0.02 0.66 - 0.32 - - and ecx, 1 - - 0.33 0.66 - 0.01 - - xor rsi, 6 - - - - - - - - xor eax, eax - - 0.98 0.02 - - - - or rsi, rcx - - 0.99 0.01 - 1.00 - - cmove rax, rdi - - - - - 1.00 - - retUnsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_bytes_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> { zerocopy::FromBytes::ref_from_bytes(source).ok() }Assembly
bench_ref_from_bytes_dynamic_size: mov rdx, rsi cmp rsi, 4 setb al or al, dil test al, 1 je .LBB5_2 xor eax, eax ret .LBB5_2: lea rcx, [rdx - 4] mov rsi, rcx and rsi, -2 add rsi, 4 shr rcx xor eax, eax cmp rdx, rsi cmove rdx, rcx cmove rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 1800 Total Cycles: 704 Total uOps: 2000 Dispatch Width: 4 uOps Per Cycle: 2.84 IPC: 2.56 Block RThroughput: 5.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 mov rdx, rsi 1 1 0.33 cmp rsi, 4 1 1 0.50 setb al 1 1 0.33 or al, dil 1 1 0.33 test al, 1 1 1 1.00 je .LBB5_2 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.50 lea rcx, [rdx - 4] 1 1 0.33 mov rsi, rcx 1 1 0.33 and rsi, -2 1 1 0.33 add rsi, 4 1 1 0.50 shr rcx 1 0 0.25 xor eax, eax 1 1 0.33 cmp rdx, rsi 2 2 0.67 cmove rdx, rcx 2 2 0.67 cmove rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 5.97 5.98 - 6.05 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.97 0.01 - 0.02 - - mov rdx, rsi - - 0.01 0.02 - 0.97 - - cmp rsi, 4 - - 0.03 - - 0.97 - - setb al - - 0.01 0.02 - 0.97 - - or al, dil - - - 0.98 - 0.02 - - test al, 1 - - - - - 1.00 - - je .LBB5_2 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.98 0.02 - - - - lea rcx, [rdx - 4] - - 0.01 0.99 - - - - mov rsi, rcx - - - 0.98 - 0.02 - - and rsi, -2 - - 0.98 0.01 - 0.01 - - add rsi, 4 - - 0.99 - - 0.01 - - shr rcx - - - - - - - - xor eax, eax - - 0.02 0.97 - 0.01 - - cmp rdx, rsi - - 0.99 0.99 - 0.02 - - cmove rdx, rcx - - 0.98 0.99 - 0.03 - - cmove rax, rdi - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_bytes_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> { zerocopy::FromBytes::ref_from_bytes(source).ok() }Assembly
bench_ref_from_bytes_dynamic_padding: test dil, 3 jne .LBB5_3 movabs rax, 9223372036854775804 and rax, rsi cmp rax, 9 jb .LBB5_3 add rax, -9 movabs rcx, -6148914691236517205 mul rcx shr rdx lea rax, [rdx + 2*rdx] or rax, 3 add rax, 9 cmp rsi, rax je .LBB5_4 .LBB5_3: xor edi, edi mov rdx, rsi .LBB5_4: mov rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 645 Total uOps: 2000 Dispatch Width: 4 uOps Per Cycle: 3.10 IPC: 2.95 Block RThroughput: 5.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 test dil, 3 1 1 1.00 jne .LBB5_3 1 1 0.33 movabs rax, 9223372036854775804 1 1 0.33 and rax, rsi 1 1 0.33 cmp rax, 9 1 1 1.00 jb .LBB5_3 1 1 0.33 add rax, -9 1 1 0.33 movabs rcx, -6148914691236517205 2 4 1.00 mul rcx 1 1 0.50 shr rdx 1 1 0.50 lea rax, [rdx + 2*rdx] 1 1 0.33 or rax, 3 1 1 0.33 add rax, 9 1 1 0.33 cmp rsi, rax 1 1 1.00 je .LBB5_4 1 0 0.25 xor edi, edi 1 1 0.33 mov rdx, rsi 1 1 0.33 mov rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 6.32 6.33 - 6.35 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.64 0.35 - 0.01 - - test dil, 3 - - - - - 1.00 - - jne .LBB5_3 - - 0.34 0.65 - 0.01 - - movabs rax, 9223372036854775804 - - 0.35 0.65 - - - - and rax, rsi - - 0.33 0.34 - 0.33 - - cmp rax, 9 - - - - - 1.00 - - jb .LBB5_3 - - 0.35 - - 0.65 - - add rax, -9 - - 0.97 0.01 - 0.02 - - movabs rcx, -6148914691236517205 - - 1.00 1.00 - - - - mul rcx - - 0.99 - - 0.01 - - shr rdx - - 0.33 0.67 - - - - lea rax, [rdx + 2*rdx] - - 0.34 0.66 - - - - or rax, 3 - - 0.33 0.66 - 0.01 - - add rax, 9 - - 0.01 0.99 - - - - cmp rsi, rax - - - - - 1.00 - - je .LBB5_4 - - - - - - - - xor edi, edi - - 0.32 0.01 - 0.67 - - mov rdx, rsi - - 0.02 0.34 - 0.64 - - mov rax, rdi - - - - - 1.00 - - retfn ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> where Self: KnownLayout + Immutable,Interprets the prefix of the given
sourceas a&Selfwithout copying.This method computes the largest possible size of
Selfthat can fit in the leading bytes ofsource, then attempts to return both a reference to those bytes interpreted as aSelf, and a reference to the remaining bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. See
ref_from_prefix_with_elems, which does support such types. Attempting to use this method on such types results in a compile-time assertion error; e.g.:use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `Packet`. let bytes = &; let = ref_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_prefix_static_size(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_ref_from_prefix_static_size: xor eax, eax cmp rsi, 6 mov rcx, rdi cmovb rcx, rax test dil, 1 cmove rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 700 Total Cycles: 274 Total uOps: 900 Dispatch Width: 4 uOps Per Cycle: 3.28 IPC: 2.55 Block RThroughput: 2.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 0 0.25 xor eax, eax 1 1 0.33 cmp rsi, 6 1 1 0.33 mov rcx, rdi 2 2 0.67 cmovb rcx, rax 1 1 0.33 test dil, 1 2 2 0.67 cmove rax, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 2.66 2.67 - 2.67 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - - - - - xor eax, eax - - - 0.01 - 0.99 - - cmp rsi, 6 - - 0.01 0.67 - 0.32 - - mov rcx, rdi - - 1.00 0.99 - 0.01 - - cmovb rcx, rax - - 0.66 0.01 - 0.33 - - test dil, 1 - - 0.99 0.99 - 0.02 - - cmove rax, rcx - - - - - 1.00 - - retUnsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_prefix_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_ref_from_prefix_dynamic_size: xor edx, edx mov eax, 0 test dil, 1 jne .LBB5_4 cmp rsi, 4 jae .LBB5_3 mov edx, 1 xor eax, eax ret .LBB5_3: add rsi, -4 shr rsi mov rdx, rsi mov rax, rdi .LBB5_4: retMachine Code Analysis
Iterations: 100 Instructions: 1400 Total Cycles: 405 Total uOps: 1400 Dispatch Width: 4 uOps Per Cycle: 3.46 IPC: 3.46 Block RThroughput: 4.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 0 0.25 xor edx, edx 1 1 0.33 mov eax, 0 1 1 0.33 test dil, 1 1 1 1.00 jne .LBB5_4 1 1 0.33 cmp rsi, 4 1 1 1.00 jae .LBB5_3 1 1 0.33 mov edx, 1 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.33 add rsi, -4 1 1 0.50 shr rsi 1 1 0.33 mov rdx, rsi 1 1 0.33 mov rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 3.99 3.99 - 4.02 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - - - - - xor edx, edx - - 0.01 0.98 - 0.01 - - mov eax, 0 - - 0.98 0.02 - - - - test dil, 1 - - - - - 1.00 - - jne .LBB5_4 - - 0.02 0.98 - - - - cmp rsi, 4 - - - - - 1.00 - - jae .LBB5_3 - - 0.98 0.01 - 0.01 - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.01 0.99 - - - - add rsi, -4 - - 1.00 - - - - - shr rsi - - - 1.00 - - - - mov rdx, rsi - - 0.99 0.01 - - - - mov rax, rdi - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_prefix_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_ref_from_prefix_dynamic_padding: xor edx, edx mov eax, 0 test dil, 3 je .LBB5_1 ret .LBB5_1: movabs rax, 9223372036854775804 and rsi, rax cmp rsi, 9 jae .LBB5_3 mov edx, 1 xor eax, eax ret .LBB5_3: add rsi, -9 movabs rcx, -6148914691236517205 mov rax, rsi mul rcx shr rdx mov rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 608 Total uOps: 2000 Dispatch Width: 4 uOps Per Cycle: 3.29 IPC: 3.13 Block RThroughput: 5.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 0 0.25 xor edx, edx 1 1 0.33 mov eax, 0 1 1 0.33 test dil, 3 1 1 1.00 je .LBB5_1 1 1 1.00 U ret 1 1 0.33 movabs rax, 9223372036854775804 1 1 0.33 and rsi, rax 1 1 0.33 cmp rsi, 9 1 1 1.00 jae .LBB5_3 1 1 0.33 mov edx, 1 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.33 add rsi, -9 1 1 0.33 movabs rcx, -6148914691236517205 1 1 0.33 mov rax, rsi 2 4 1.00 mul rcx 1 1 0.50 shr rdx 1 1 0.33 mov rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 6.00 6.00 - 6.00 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - - - - - xor edx, edx - - 0.01 0.98 - 0.01 - - mov eax, 0 - - 0.98 0.01 - 0.01 - - test dil, 3 - - - - - 1.00 - - je .LBB5_1 - - - - - 1.00 - - ret - - 0.01 0.99 - - - - movabs rax, 9223372036854775804 - - - 1.00 - - - - and rsi, rax - - - 1.00 - - - - cmp rsi, 9 - - - - - 1.00 - - jae .LBB5_3 - - 1.00 - - - - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.02 0.02 - 0.96 - - add rsi, -9 - - 0.99 0.01 - - - - movabs rcx, -6148914691236517205 - - 0.01 0.99 - - - - mov rax, rsi - - 1.00 1.00 - - - - mul rcx - - 1.00 - - - - - shr rdx - - 0.98 - - 0.02 - - mov rax, rdi - - - - - 1.00 - - retfn ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), CastError<&[u8], Self>> where Self: Immutable + KnownLayout,Interprets the suffix of the given bytes as a
&Self.This method computes the largest possible size of
Selfthat can fit in the trailing bytes ofsource, then attempts to return both a reference to those bytes interpreted as aSelf, and a reference to the preceding bytes. If there are insufficient bytes, or if that suffix ofsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. See
ref_from_suffix_with_elems, which does support such types. Attempting to use this method on such types results in a compile-time assertion error; e.g.:use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `PacketTrailer`. let bytes = &; let = ref_from_suffix.unwrap; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_suffix_static_size(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_ref_from_suffix_static_size: lea eax, [rsi + rdi] cmp rsi, 6 setb cl or cl, al test cl, 1 je .LBB5_2 xor eax, eax ret .LBB5_2: lea rax, [rdi + rsi] add rax, -6 retMachine Code Analysis
Iterations: 100 Instructions: 1100 Total Cycles: 338 Total uOps: 1100 Dispatch Width: 4 uOps Per Cycle: 3.25 IPC: 3.25 Block RThroughput: 3.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.50 lea eax, [rsi + rdi] 1 1 0.33 cmp rsi, 6 1 1 0.50 setb cl 1 1 0.33 or cl, al 1 1 0.33 test cl, 1 1 1 1.00 je .LBB5_2 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.50 lea rax, [rdi + rsi] 1 1 0.33 add rax, -6 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 3.32 3.33 - 3.35 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.97 0.03 - - - - lea eax, [rsi + rdi] - - 0.33 0.32 - 0.35 - - cmp rsi, 6 - - 1.00 - - - - - setb cl - - - 1.00 - - - - or cl, al - - - 1.00 - - - - test cl, 1 - - - - - 1.00 - - je .LBB5_2 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.34 0.66 - - - - lea rax, [rdi + rsi] - - 0.68 0.32 - - - - add rax, -6 - - - - - 1.00 - - retUnsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_suffix_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_ref_from_suffix_dynamic_size: mov rdx, rsi lea ecx, [rsi + rdi] mov eax, edx and eax, 1 add rax, rdi xor esi, esi sub rdx, 4 cmovb rax, rsi shr rdx test cl, 1 cmovne rax, rsi retMachine Code Analysis
Iterations: 100 Instructions: 1200 Total Cycles: 439 Total uOps: 1400 Dispatch Width: 4 uOps Per Cycle: 3.19 IPC: 2.73 Block RThroughput: 3.5 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 mov rdx, rsi 1 1 0.50 lea ecx, [rsi + rdi] 1 1 0.33 mov eax, edx 1 1 0.33 and eax, 1 1 1 0.33 add rax, rdi 1 0 0.25 xor esi, esi 1 1 0.33 sub rdx, 4 2 2 0.67 cmovb rax, rsi 1 1 0.50 shr rdx 1 1 0.33 test cl, 1 2 2 0.67 cmovne rax, rsi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 4.33 4.33 - 4.34 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.02 0.32 - 0.66 - - mov rdx, rsi - - 0.32 0.68 - - - - lea ecx, [rsi + rdi] - - 0.66 - - 0.34 - - mov eax, edx - - 0.02 0.33 - 0.65 - - and eax, 1 - - - 0.99 - 0.01 - - add rax, rdi - - - - - - - - xor esi, esi - - 0.65 - - 0.35 - - sub rdx, 4 - - 1.00 1.00 - - - - cmovb rax, rsi - - 0.66 - - 0.34 - - shr rdx - - - 0.01 - 0.99 - - test cl, 1 - - 1.00 1.00 - - - - cmovne rax, rsi - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_suffix_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_ref_from_suffix_dynamic_padding: lea eax, [rsi + rdi] test al, 3 jne .LBB5_1 movabs rax, 9223372036854775804 and rax, rsi cmp rax, 9 jae .LBB5_3 .LBB5_1: xor eax, eax ret .LBB5_3: add rax, -9 movabs rcx, -6148914691236517205 mul rcx shr rdx lea rax, [rdx + 2*rdx] sub rsi, rax or rax, -4 add rsi, rdi add rax, rsi add rax, -8 retMachine Code Analysis
Iterations: 100 Instructions: 2000 Total Cycles: 682 Total uOps: 2100 Dispatch Width: 4 uOps Per Cycle: 3.08 IPC: 2.93 Block RThroughput: 5.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.50 lea eax, [rsi + rdi] 1 1 0.33 test al, 3 1 1 1.00 jne .LBB5_1 1 1 0.33 movabs rax, 9223372036854775804 1 1 0.33 and rax, rsi 1 1 0.33 cmp rax, 9 1 1 1.00 jae .LBB5_3 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.33 add rax, -9 1 1 0.33 movabs rcx, -6148914691236517205 2 4 1.00 mul rcx 1 1 0.50 shr rdx 1 1 0.50 lea rax, [rdx + 2*rdx] 1 1 0.33 sub rsi, rax 1 1 0.33 or rax, -4 1 1 0.33 add rsi, rdi 1 1 0.33 add rax, rsi 1 1 0.33 add rax, -8 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 6.65 6.67 - 6.68 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.90 0.10 - - - - lea eax, [rsi + rdi] - - 0.93 - - 0.07 - - test al, 3 - - - - - 1.00 - - jne .LBB5_1 - - 0.51 0.47 - 0.02 - - movabs rax, 9223372036854775804 - - - - - 1.00 - - and rax, rsi - - - 0.09 - 0.91 - - cmp rax, 9 - - - - - 1.00 - - jae .LBB5_3 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.43 0.47 - 0.10 - - add rax, -9 - - 0.42 0.39 - 0.19 - - movabs rcx, -6148914691236517205 - - 1.00 1.00 - - - - mul rcx - - 0.69 - - 0.31 - - shr rdx - - 0.54 0.46 - - - - lea rax, [rdx + 2*rdx] - - 0.07 0.91 - 0.02 - - sub rsi, rax - - 0.91 0.05 - 0.04 - - or rax, -4 - - 0.08 0.90 - 0.02 - - add rsi, rdi - - 0.09 0.91 - - - - add rax, rsi - - 0.08 0.92 - - - - add rax, -8 - - - - - 1.00 - - retfn mut_from_bytes(source: &mut [u8]) -> Result<&mut Self, CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout,Interprets the given
sourceas a&mut Self.This method attempts to return a reference to
sourceinterpreted as aSelf. If the length ofsourceis not a valid size ofSelf, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. See
mut_from_prefix_with_elems, which does support such types. Attempting to use this method on such types results in a compile-time assertion error; e.g.:use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: [u8; 2], trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::mut_from_bytes(&mut source[..]); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These bytes encode a `PacketHeader`. let bytes = &mut ; let header = mut_from_bytes.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; header.checksum = ; assert_eq!;§ Code Generation
fn mut_from_prefix(source: &mut [u8]) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout,Interprets the prefix of the given
sourceas a&mut Selfwithout copying.This method computes the largest possible size of
Selfthat can fit in the leading bytes ofsource, then attempts to return both a reference to those bytes interpreted as aSelf, and a reference to the remaining bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. See
mut_from_suffix_with_elems, which does support such types. Attempting to use this method on such types results in a compile-time assertion error; e.g.:use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: [u8; 2], trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::mut_from_prefix(&mut source[..]); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `PacketHeader`. let bytes = &mut ; let = mut_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; header.checksum = ; body.fill; assert_eq!;§ Code Generation
fn mut_from_suffix(source: &mut [u8]) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout,Interprets the suffix of the given
sourceas a&mut Selfwithout copying.This method computes the largest possible size of
Selfthat can fit in the trailing bytes ofsource, then attempts to return both a reference to those bytes interpreted as aSelf, and a reference to the preceding bytes. If there are insufficient bytes, or if that suffix ofsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Selfmay be a sized type, a slice, or a slice DST.Compile-Time Assertions
This method cannot yet be used on unsized types whose dynamically-sized component is zero-sized. Attempting to use this method on such types results in a compile-time assertion error; e.g.:
use zerocopy::*; # use zerocopy_derive::*; #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: [u8; 2], trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::mut_from_suffix(&mut source[..]); // ⚠ Compile Error!Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `PacketTrailer`. let bytes = &mut ; let = mut_from_suffix.unwrap; assert_eq!; assert_eq!; prefix.fill; trailer.frame_check_sequence.fill; assert_eq!;§ Code Generation
fn ref_from_bytes_with_elems(source: &[u8], count: usize) -> Result<&Self, CastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Interprets the given
sourceas a&Selfwith a DST length equal tocount.This method attempts to return a reference to
sourceinterpreted as aSelfwithcounttrailing elements. If the length ofsourceis not equal to the size ofSelfwithcountelements, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # let bytes = &; let pixels = ref_from_bytes_with_elems.unwrap; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asref_from_byteswhich do not take an explicit count do not support such types.use *; # use *; let src = &; let zsty = ref_from_bytes_with_elems.unwrap; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Unsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_bytes_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { zerocopy::FromBytes::ref_from_bytes_with_elems(source, count).ok() }Assembly
bench_ref_from_bytes_with_elems_dynamic_size: movabs rax, 4611686018427387901 cmp rdx, rax seta cl mov rax, rdi or dil, cl test dil, 1 jne .LBB5_2 lea rcx, [2*rdx + 4] cmp rsi, rcx je .LBB5_3 .LBB5_2: xor eax, eax mov rdx, rsi .LBB5_3: retMachine Code Analysis
Iterations: 100 Instructions: 1300 Total Cycles: 439 Total uOps: 1400 Dispatch Width: 4 uOps Per Cycle: 3.19 IPC: 2.96 Block RThroughput: 3.5 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 4611686018427387901 1 1 0.33 cmp rdx, rax 2 2 1.00 seta cl 1 1 0.33 mov rax, rdi 1 1 0.33 or dil, cl 1 1 0.33 test dil, 1 1 1 1.00 jne .LBB5_2 1 1 0.50 lea rcx, [2*rdx + 4] 1 1 0.33 cmp rsi, rcx 1 1 1.00 je .LBB5_3 1 0 0.25 xor eax, eax 1 1 0.33 mov rdx, rsi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 4.32 4.33 - 4.35 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - movabs rax, 4611686018427387901 - - 0.33 0.67 - - - - cmp rdx, rax - - 1.98 - - 0.02 - - seta cl - - 0.01 0.99 - - - - mov rax, rdi - - 1.00 - - - - - or dil, cl - - 0.99 0.01 - - - - test dil, 1 - - - - - 1.00 - - jne .LBB5_2 - - - 1.00 - - - - lea rcx, [2*rdx + 4] - - 0.01 - - 0.99 - - cmp rsi, rcx - - - - - 1.00 - - je .LBB5_3 - - - - - - - - xor eax, eax - - - 0.67 - 0.33 - - mov rdx, rsi - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_bytes_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { zerocopy::FromBytes::ref_from_bytes_with_elems(source, count).ok() }Assembly
bench_ref_from_bytes_with_elems_dynamic_padding: movabs rax, 3074457345618258598 cmp rdx, rax seta cl mov rax, rdi test al, 3 setne dil or dil, cl jne .LBB5_2 lea rcx, [rdx + 2*rdx] or rcx, 3 add rcx, 9 cmp rsi, rcx je .LBB5_3 .LBB5_2: xor eax, eax mov rdx, rsi .LBB5_3: retMachine Code Analysis
Iterations: 100 Instructions: 1600 Total Cycles: 539 Total uOps: 1700 Dispatch Width: 4 uOps Per Cycle: 3.15 IPC: 2.97 Block RThroughput: 4.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 3074457345618258598 1 1 0.33 cmp rdx, rax 2 2 1.00 seta cl 1 1 0.33 mov rax, rdi 1 1 0.33 test al, 3 1 1 0.50 setne dil 1 1 0.33 or dil, cl 1 1 1.00 jne .LBB5_2 1 1 0.50 lea rcx, [rdx + 2*rdx] 1 1 0.33 or rcx, 3 1 1 0.33 add rcx, 9 1 1 0.33 cmp rsi, rcx 1 1 1.00 je .LBB5_3 1 0 0.25 xor eax, eax 1 1 0.33 mov rdx, rsi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 5.33 5.32 - 5.35 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.01 0.98 - 0.01 - - movabs rax, 3074457345618258598 - - - 1.00 - - - - cmp rdx, rax - - 1.98 - - 0.02 - - seta cl - - 0.02 0.98 - - - - mov rax, rdi - - - 0.67 - 0.33 - - test al, 3 - - 0.67 - - 0.33 - - setne dil - - 0.99 - - 0.01 - - or dil, cl - - - - - 1.00 - - jne .LBB5_2 - - 0.01 0.99 - - - - lea rcx, [rdx + 2*rdx] - - - 0.01 - 0.99 - - or rcx, 3 - - 0.65 0.02 - 0.33 - - add rcx, 9 - - 0.99 0.01 - - - - cmp rsi, rcx - - - - - 1.00 - - je .LBB5_3 - - - - - - - - xor eax, eax - - 0.01 0.66 - 0.33 - - mov rdx, rsi - - - - - 1.00 - - retfn ref_from_prefix_with_elems(source: &[u8], count: usize) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Interprets the prefix of the given
sourceas a DST&Selfwith length equal tocount.This method attempts to return a reference to the prefix of
sourceinterpreted as aSelfwithcounttrailing elements, and a reference to the remaining bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # // These are more bytes than are needed to encode two `Pixel`s. let bytes = &; let = ref_from_prefix_with_elems.unwrap; assert_eq!; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asref_from_prefixwhich do not take an explicit count do not support such types.use *; # use *; let src = &; let = ref_from_prefix_with_elems.unwrap; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Unsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_prefix_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_prefix_with_elems(source, count) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_ref_from_prefix_with_elems_dynamic_size: movabs rax, 4611686018427387901 cmp rdx, rax ja .LBB5_1 mov rcx, rdx xor edx, edx mov eax, 0 test dil, 1 jne .LBB5_4 lea rax, [2*rcx + 4] xor r8d, r8d cmp rax, rsi mov edx, 1 cmovbe rdx, rcx cmova rdi, r8 mov rax, rdi .LBB5_4: ret .LBB5_1: mov edx, 1 xor eax, eax retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 672 Total uOps: 2300 Dispatch Width: 4 uOps Per Cycle: 3.42 IPC: 2.83 Block RThroughput: 5.8 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 4611686018427387901 1 1 0.33 cmp rdx, rax 1 1 1.00 ja .LBB5_1 1 1 0.33 mov rcx, rdx 1 0 0.25 xor edx, edx 1 1 0.33 mov eax, 0 1 1 0.33 test dil, 1 1 1 1.00 jne .LBB5_4 1 1 0.50 lea rax, [2*rcx + 4] 1 0 0.25 xor r8d, r8d 1 1 0.33 cmp rax, rsi 1 1 0.33 mov edx, 1 3 3 1.00 cmovbe rdx, rcx 3 3 1.00 cmova rdi, r8 1 1 0.33 mov rax, rdi 1 1 1.00 U ret 1 1 0.33 mov edx, 1 1 0 0.25 xor eax, eax 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 6.66 6.66 - 6.68 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - movabs rax, 4611686018427387901 - - 0.37 0.63 - - - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - 0.63 0.37 - - - - mov rcx, rdx - - - - - - - - xor edx, edx - - 0.01 0.98 - 0.01 - - mov eax, 0 - - 0.98 0.02 - - - - test dil, 1 - - - - - 1.00 - - jne .LBB5_4 - - 0.01 0.99 - - - - lea rax, [2*rcx + 4] - - - - - - - - xor r8d, r8d - - 1.00 - - - - - cmp rax, rsi - - - 0.67 - 0.33 - - mov edx, 1 - - 0.73 0.98 - 1.29 - - cmovbe rdx, rcx - - 1.60 0.36 - 1.04 - - cmova rdi, r8 - - 0.99 0.01 - - - - mov rax, rdi - - - - - 1.00 - - ret - - 0.34 0.66 - - - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_prefix_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_prefix_with_elems(source, count) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_ref_from_prefix_with_elems_dynamic_padding: movabs rax, 3074457345618258598 cmp rdx, rax ja .LBB5_1 xor ecx, ecx mov eax, 0 test dil, 3 je .LBB5_3 mov rdx, rcx ret .LBB5_1: mov edx, 1 xor eax, eax ret .LBB5_3: lea rax, [rdx + 2*rdx] or rax, 3 add rax, 9 xor r8d, r8d cmp rax, rsi mov ecx, 1 cmovbe rcx, rdx cmova rdi, r8 mov rax, rdi mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2300 Total Cycles: 807 Total uOps: 2700 Dispatch Width: 4 uOps Per Cycle: 3.35 IPC: 2.85 Block RThroughput: 6.8 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 3074457345618258598 1 1 0.33 cmp rdx, rax 1 1 1.00 ja .LBB5_1 1 0 0.25 xor ecx, ecx 1 1 0.33 mov eax, 0 1 1 0.33 test dil, 3 1 1 1.00 je .LBB5_3 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret 1 1 0.33 mov edx, 1 1 0 0.25 xor eax, eax 1 1 1.00 U ret 1 1 0.50 lea rax, [rdx + 2*rdx] 1 1 0.33 or rax, 3 1 1 0.33 add rax, 9 1 0 0.25 xor r8d, r8d 1 1 0.33 cmp rax, rsi 1 1 0.33 mov ecx, 1 3 3 1.00 cmovbe rcx, rdx 3 3 1.00 cmova rdi, r8 1 1 0.33 mov rax, rdi 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 7.99 7.99 - 8.02 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.47 0.52 - 0.01 - - movabs rax, 3074457345618258598 - - 0.94 0.01 - 0.05 - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - - - - - - - xor ecx, ecx - - 0.03 0.97 - - - - mov eax, 0 - - 0.01 0.52 - 0.47 - - test dil, 3 - - - - - 1.00 - - je .LBB5_3 - - 0.03 0.51 - 0.46 - - mov rdx, rcx - - - - - 1.00 - - ret - - 0.04 0.96 - - - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.01 0.99 - - - - lea rax, [rdx + 2*rdx] - - 0.52 0.48 - - - - or rax, 3 - - 0.51 0.49 - - - - add rax, 9 - - - - - - - - xor r8d, r8d - - 0.97 0.03 - - - - cmp rax, rsi - - 0.01 0.99 - - - - mov ecx, 1 - - 1.04 0.97 - 0.99 - - cmovbe rcx, rdx - - 1.44 0.54 - 1.02 - - cmova rdi, r8 - - 0.97 0.01 - 0.02 - - mov rax, rdi - - 1.00 - - - - - mov rdx, rcx - - - - - 1.00 - - retfn ref_from_suffix_with_elems(source: &[u8], count: usize) -> Result<(&[u8], &Self), CastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Interprets the suffix of the given
sourceas a DST&Selfwith length equal tocount.This method attempts to return a reference to the suffix of
sourceinterpreted as aSelfwithcounttrailing elements, and a reference to the preceding bytes. If there are insufficient bytes, or if that suffix ofsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # // These are more bytes than are needed to encode two `Pixel`s. let bytes = &; let = ref_from_suffix_with_elems.unwrap; assert_eq!; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asref_from_suffixwhich do not take an explicit count do not support such types.use *; # use *; let src = &; let = ref_from_suffix_with_elems.unwrap; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Unsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_suffix_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_suffix_with_elems(source, count) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_ref_from_suffix_with_elems_dynamic_size: movabs rax, 4611686018427387901 cmp rdx, rax ja .LBB5_1 lea r8d, [rsi + rdi] xor ecx, ecx mov eax, 0 test r8b, 1 jne .LBB5_5 lea rax, [2*rdx + 4] sub rsi, rax jae .LBB5_4 .LBB5_1: xor eax, eax mov edx, 1 ret .LBB5_4: add rdi, rsi mov rcx, rdx mov rax, rdi .LBB5_5: mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 571 Total uOps: 1900 Dispatch Width: 4 uOps Per Cycle: 3.33 IPC: 3.33 Block RThroughput: 5.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 4611686018427387901 1 1 0.33 cmp rdx, rax 1 1 1.00 ja .LBB5_1 1 1 0.50 lea r8d, [rsi + rdi] 1 0 0.25 xor ecx, ecx 1 1 0.33 mov eax, 0 1 1 0.33 test r8b, 1 1 1 1.00 jne .LBB5_5 1 1 0.50 lea rax, [2*rdx + 4] 1 1 0.33 sub rsi, rax 1 1 1.00 jae .LBB5_4 1 0 0.25 xor eax, eax 1 1 0.33 mov edx, 1 1 1 1.00 U ret 1 1 0.33 add rdi, rsi 1 1 0.33 mov rcx, rdx 1 1 0.33 mov rax, rdi 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 5.66 5.66 - 5.68 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.66 0.33 - 0.01 - - movabs rax, 4611686018427387901 - - 0.01 0.99 - - - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - 0.99 0.01 - - - - lea r8d, [rsi + rdi] - - - - - - - - xor ecx, ecx - - 0.33 0.33 - 0.34 - - mov eax, 0 - - 0.33 0.34 - 0.33 - - test r8b, 1 - - - - - 1.00 - - jne .LBB5_5 - - 0.34 0.66 - - - - lea rax, [2*rdx + 4] - - - 1.00 - - - - sub rsi, rax - - - - - 1.00 - - jae .LBB5_4 - - - - - - - - xor eax, eax - - 1.00 - - - - - mov edx, 1 - - - - - 1.00 - - ret - - - 1.00 - - - - add rdi, rsi - - 1.00 - - - - - mov rcx, rdx - - 0.32 0.68 - - - - mov rax, rdi - - 0.68 0.32 - - - - mov rdx, rcx - - - - - 1.00 - - retDynamically Padded
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } #[derive(FromBytes, KnownLayout, Immutable, SplitAt)] #[repr(C, align(4))] pub struct Packet<Magic> { magic_number: Magic, milk: u8, mug_size: u8, temperature: [u8; 5], marshmallows: [[u8; 3]], } /// A packet begining with the magic number `0xC0C0`. pub type CocoPacket = Packet<C0C0>; /// A packet beginning with any two initialized bytes. pub type LocoPacket = Packet<[u8; 2]>;Benchmark
#[path = "formats/coco_dynamic_padding.rs"] mod format; #[unsafe(no_mangle)] fn bench_ref_from_suffix_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::LocoPacket> { match zerocopy::FromBytes::ref_from_suffix_with_elems(source, count) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_ref_from_suffix_with_elems_dynamic_padding: movabs rax, 3074457345618258598 cmp rdx, rax ja .LBB5_1 lea r8d, [rsi + rdi] xor ecx, ecx mov eax, 0 test r8b, 3 je .LBB5_3 mov rdx, rcx ret .LBB5_3: lea rax, [rdx + 2*rdx] or rax, 3 add rax, 9 sub rsi, rax jae .LBB5_4 .LBB5_1: xor eax, eax mov edx, 1 ret .LBB5_4: add rdi, rsi mov rcx, rdx mov rax, rdi mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2300 Total Cycles: 706 Total uOps: 2300 Dispatch Width: 4 uOps Per Cycle: 3.26 IPC: 3.26 Block RThroughput: 6.0 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 movabs rax, 3074457345618258598 1 1 0.33 cmp rdx, rax 1 1 1.00 ja .LBB5_1 1 1 0.50 lea r8d, [rsi + rdi] 1 0 0.25 xor ecx, ecx 1 1 0.33 mov eax, 0 1 1 0.33 test r8b, 3 1 1 1.00 je .LBB5_3 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret 1 1 0.50 lea rax, [rdx + 2*rdx] 1 1 0.33 or rax, 3 1 1 0.33 add rax, 9 1 1 0.33 sub rsi, rax 1 1 1.00 jae .LBB5_4 1 0 0.25 xor eax, eax 1 1 0.33 mov edx, 1 1 1 1.00 U ret 1 1 0.33 add rdi, rsi 1 1 0.33 mov rcx, rdx 1 1 0.33 mov rax, rdi 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 6.99 7.00 - 7.01 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - movabs rax, 3074457345618258598 - - 0.01 0.50 - 0.49 - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - - 1.00 - - - - lea r8d, [rsi + rdi] - - - - - - - - xor ecx, ecx - - 0.50 0.49 - 0.01 - - mov eax, 0 - - 0.49 0.51 - - - - test r8b, 3 - - - - - 1.00 - - je .LBB5_3 - - 0.51 0.49 - - - - mov rdx, rcx - - - - - 1.00 - - ret - - 0.50 0.50 - - - - lea rax, [rdx + 2*rdx] - - 1.00 - - - - - or rax, 3 - - 1.00 - - - - - add rax, 9 - - 0.99 0.01 - - - - sub rsi, rax - - - - - 1.00 - - jae .LBB5_4 - - - - - - - - xor eax, eax - - - 1.00 - - - - mov edx, 1 - - - - - 1.00 - - ret - - 1.00 - - - - - add rdi, rsi - - - 1.00 - - - - mov rcx, rdx - - 0.99 0.01 - - - - mov rax, rdi - - - 0.50 - 0.50 - - mov rdx, rcx - - - - - 1.00 - - retfn mut_from_bytes_with_elems(source: &mut [u8], count: usize) -> Result<&mut Self, CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout<PointerMetadata = usize> + Immutable,Interprets the given
sourceas a&mut Selfwith a DST length equal tocount.This method attempts to return a reference to
sourceinterpreted as aSelfwithcounttrailing elements. If the length ofsourceis not equal to the size ofSelfwithcountelements, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # let bytes = &mut ; let pixels = mut_from_bytes_with_elems.unwrap; assert_eq!; pixels = Pixel ; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asmut_from_byteswhich do not take an explicit count do not support such types.use *; # use *; let src = &mut ; let zsty = mut_from_bytes_with_elems.unwrap; assert_eq!;§ Code Generation
fn mut_from_prefix_with_elems(source: &mut [u8], count: usize) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout<PointerMetadata = usize>,Interprets the prefix of the given
sourceas a&mut Selfwith DST length equal tocount.This method attempts to return a reference to the prefix of
sourceinterpreted as aSelfwithcounttrailing elements, and a reference to the preceding bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # // These are more bytes than are needed to encode two `Pixel`s. let bytes = &mut ; let = mut_from_prefix_with_elems.unwrap; assert_eq!; assert_eq!; pixels = Pixel ; suffix.fill; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asmut_from_prefixwhich do not take an explicit count do not support such types.use *; # use *; let src = &mut ; let = mut_from_prefix_with_elems.unwrap; assert_eq!;§ Code Generation
fn mut_from_suffix_with_elems(source: &mut [u8], count: usize) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout<PointerMetadata = usize>,Interprets the suffix of the given
sourceas a&mut Selfwith DST length equal tocount.This method attempts to return a reference to the suffix of
sourceinterpreted as aSelfwithcounttrailing elements, and a reference to the remaining bytes. If there are insufficient bytes, or if that suffix ofsourceis not appropriately aligned, this returnsErr. IfSelf: Unaligned, you can infallibly discard the alignment error.Examples
use FromBytes; # use *; # // These are more bytes than are needed to encode two `Pixel`s. let bytes = &mut ; let = mut_from_suffix_with_elems.unwrap; assert_eq!; assert_eq!; prefix.fill; pixels = Pixel ; assert_eq!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such asmut_from_suffixwhich do not take an explicit count do not support such types.use *; # use *; let src = &mut ; let = mut_from_suffix_with_elems.unwrap; assert_eq!;§ Code Generation
fn read_from_bytes(source: &[u8]) -> Result<Self, SizeError<&[u8], Self>> where Self: Sized,Reads a copy of
Selffrom the givensource.If
source.len() != size_of::<Self>(),read_from_bytesreturnsErr.Examples
use FromBytes; # use *; // These bytes encode a `PacketHeader`. let bytes = &; let header = read_from_bytes.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_read_from_bytes_static_size(source: &[u8]) -> Option<format::LocoPacket> { zerocopy::FromBytes::read_from_bytes(source).ok() }Assembly
bench_read_from_bytes_static_size: mov rcx, rsi cmp rsi, 6 jne .LBB5_2 mov eax, dword ptr [rdi] movzx ecx, word ptr [rdi + 4] shl rcx, 32 or rcx, rax .LBB5_2: shl rcx, 16 inc rcx xor eax, eax cmp rsi, 6 cmove rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 1300 Total Cycles: 377 Total uOps: 1400 Dispatch Width: 4 uOps Per Cycle: 3.71 IPC: 3.45 Block RThroughput: 3.5 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 mov rcx, rsi 1 1 0.33 cmp rsi, 6 1 1 1.00 jne .LBB5_2 1 5 0.50 * mov eax, dword ptr [rdi] 1 5 0.50 * movzx ecx, word ptr [rdi + 4] 1 1 0.50 shl rcx, 32 1 1 0.33 or rcx, rax 1 1 0.50 shl rcx, 16 1 1 0.33 inc rcx 1 0 0.25 xor eax, eax 1 1 0.33 cmp rsi, 6 2 2 0.67 cmove rax, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 3.66 3.67 - 3.67 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.63 0.36 - 0.01 - - mov rcx, rsi - - 0.05 0.05 - 0.90 - - cmp rsi, 6 - - - - - 1.00 - - jne .LBB5_2 - - - - - - - 1.00 mov eax, dword ptr [rdi] - - - - - - 1.00 - movzx ecx, word ptr [rdi + 4] - - 0.97 - - 0.03 - - shl rcx, 32 - - 0.02 0.35 - 0.63 - - or rcx, rax - - 0.98 - - 0.02 - - shl rcx, 16 - - - 0.98 - 0.02 - - inc rcx - - - - - - - - xor eax, eax - - 0.03 0.93 - 0.04 - - cmp rsi, 6 - - 0.98 1.00 - 0.02 - - cmove rax, rcx - - - - - 1.00 - - retfn read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), SizeError<&[u8], Self>> where Self: Sized,Reads a copy of
Selffrom the prefix of the givensource.This attempts to read a
Selffrom the firstsize_of::<Self>()bytes ofsource, returning thatSelfand any remaining bytes. Ifsource.len() < size_of::<Self>(), it returnsErr.Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `PacketHeader`. let bytes = &; let = read_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_read_from_prefix_static_size(source: &[u8]) -> Option<format::LocoPacket> { match zerocopy::FromBytes::read_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_read_from_prefix_static_size: cmp rsi, 5 jbe .LBB5_2 mov eax, dword ptr [rdi] movzx edi, word ptr [rdi + 4] shl rdi, 32 or rdi, rax .LBB5_2: shl rdi, 16 inc rdi xor eax, eax cmp rsi, 6 cmovae rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 1200 Total Cycles: 905 Total uOps: 1300 Dispatch Width: 4 uOps Per Cycle: 1.44 IPC: 1.33 Block RThroughput: 3.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 cmp rsi, 5 1 1 1.00 jbe .LBB5_2 1 5 0.50 * mov eax, dword ptr [rdi] 1 5 0.50 * movzx edi, word ptr [rdi + 4] 1 1 0.50 shl rdi, 32 1 1 0.33 or rdi, rax 1 1 0.50 shl rdi, 16 1 1 0.33 inc rdi 1 0 0.25 xor eax, eax 1 1 0.33 cmp rsi, 6 2 2 0.67 cmovae rax, rdi 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 3.32 3.32 - 3.36 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.05 0.94 - 0.01 - - cmp rsi, 5 - - - - - 1.00 - - jbe .LBB5_2 - - - - - - - 1.00 mov eax, dword ptr [rdi] - - - - - - 1.00 - movzx edi, word ptr [rdi + 4] - - 0.71 - - 0.29 - - shl rdi, 32 - - - 0.64 - 0.36 - - or rdi, rax - - 1.00 - - - - - shl rdi, 16 - - 0.31 0.40 - 0.29 - - inc rdi - - - - - - - - xor eax, eax - - 0.34 0.35 - 0.31 - - cmp rsi, 6 - - 0.91 0.99 - 0.10 - - cmovae rax, rdi - - - - - 1.00 - - retfn read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), SizeError<&[u8], Self>> where Self: Sized,Reads a copy of
Selffrom the suffix of the givensource.This attempts to read a
Selffrom the lastsize_of::<Self>()bytes ofsource, returning thatSelfand any preceding bytes. Ifsource.len() < size_of::<Self>(), it returnsErr.Examples
use FromBytes; # use *; // These are more bytes than are needed to encode a `PacketTrailer`. let bytes = &; let = read_from_suffix.unwrap; assert_eq!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
#[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_read_from_suffix_static_size(source: &[u8]) -> Option<format::LocoPacket> { match zerocopy::FromBytes::read_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_read_from_suffix_static_size: mov rcx, rsi cmp rsi, 6 jb .LBB5_2 mov eax, dword ptr [rdi + rsi - 6] movzx ecx, word ptr [rdi + rsi - 2] shl rcx, 32 or rcx, rax .LBB5_2: shl rcx, 16 inc rcx xor eax, eax cmp rsi, 6 cmovae rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 1300 Total Cycles: 377 Total uOps: 1400 Dispatch Width: 4 uOps Per Cycle: 3.71 IPC: 3.45 Block RThroughput: 3.5 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 mov rcx, rsi 1 1 0.33 cmp rsi, 6 1 1 1.00 jb .LBB5_2 1 5 0.50 * mov eax, dword ptr [rdi + rsi - 6] 1 5 0.50 * movzx ecx, word ptr [rdi + rsi - 2] 1 1 0.50 shl rcx, 32 1 1 0.33 or rcx, rax 1 1 0.50 shl rcx, 16 1 1 0.33 inc rcx 1 0 0.25 xor eax, eax 1 1 0.33 cmp rsi, 6 2 2 0.67 cmovae rax, rcx 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 3.66 3.67 - 3.67 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.63 0.36 - 0.01 - - mov rcx, rsi - - 0.05 0.05 - 0.90 - - cmp rsi, 6 - - - - - 1.00 - - jb .LBB5_2 - - - - - - - 1.00 mov eax, dword ptr [rdi + rsi - 6] - - - - - - 1.00 - movzx ecx, word ptr [rdi + rsi - 2] - - 0.97 - - 0.03 - - shl rcx, 32 - - 0.02 0.35 - 0.63 - - or rcx, rax - - 0.98 - - 0.02 - - shl rcx, 16 - - - 0.98 - 0.02 - - inc rcx - - - - - - - - xor eax, eax - - 0.03 0.93 - 0.04 - - cmp rsi, 6 - - 0.98 1.00 - 0.02 - - cmovae rax, rcx - - - - - 1.00 - - ret
Implementors
impl FromBytes for ()impl FromBytes for AtomicI16impl FromBytes for AtomicI32impl FromBytes for AtomicI64impl FromBytes for AtomicI8impl FromBytes for AtomicIsizeimpl FromBytes for AtomicU16impl FromBytes for AtomicU32impl FromBytes for AtomicU64impl FromBytes for AtomicU8impl FromBytes for AtomicUsizeimpl FromBytes for Option<NonZeroI128>impl FromBytes for Option<NonZeroI16>impl FromBytes for Option<NonZeroI32>impl FromBytes for Option<NonZeroI64>impl FromBytes for Option<NonZeroI8>impl FromBytes for Option<NonZeroIsize>impl FromBytes for Option<NonZeroU128>impl FromBytes for Option<NonZeroU16>impl FromBytes for Option<NonZeroU32>impl FromBytes for Option<NonZeroU64>impl FromBytes for Option<NonZeroU8>impl FromBytes for Option<NonZeroUsize>impl FromBytes for __m128impl FromBytes for __m128dimpl FromBytes for __m128iimpl FromBytes for __m256impl FromBytes for __m256dimpl FromBytes for __m256iimpl FromBytes for __m512impl FromBytes for __m512bhimpl FromBytes for __m512dimpl FromBytes for __m512iimpl FromBytes for f32impl FromBytes for f64impl FromBytes for i128impl FromBytes for i16impl FromBytes for i32impl FromBytes for i64impl FromBytes for i8impl FromBytes for isizeimpl FromBytes for u128impl FromBytes for u16impl FromBytes for u32impl FromBytes for u64impl FromBytes for u8impl FromBytes for usizeimpl<A: FromBytes> FromBytes for (A,)impl<A: FromBytes, B: FromBytes> FromBytes for (A, B)impl<A: FromBytes, B: FromBytes, C: FromBytes> FromBytes for (A, B, C)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes> FromBytes for (A, B, C, D)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes> FromBytes for (A, B, C, D, E)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes> FromBytes for (A, B, C, D, E, F)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes> FromBytes for (A, B, C, D, E, F, G)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes> FromBytes for (A, B, C, D, E, F, G, H)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes, V: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes, V: FromBytes, W: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes, V: FromBytes, W: FromBytes, X: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes, V: FromBytes, W: FromBytes, X: FromBytes, Y: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y)impl<A: FromBytes, B: FromBytes, C: FromBytes, D: FromBytes, E: FromBytes, F: FromBytes, G: FromBytes, H: FromBytes, I: FromBytes, J: FromBytes, K: FromBytes, L: FromBytes, M: FromBytes, N: FromBytes, O: FromBytes, P: FromBytes, Q: FromBytes, R: FromBytes, S: FromBytes, T: FromBytes, U: FromBytes, V: FromBytes, W: FromBytes, X: FromBytes, Y: FromBytes, Z: FromBytes> FromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z)impl<O> FromBytes for F32<O> where [u8; 4]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for F64<O> where [u8; 8]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for I128<O> where [u8; 16]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for I16<O> where [u8; 2]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for I32<O> where [u8; 4]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for I64<O> where [u8; 8]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for Isize<O> where [u8; 8]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for U128<O> where [u8; 16]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for U16<O> where [u8; 2]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for U32<O> where [u8; 4]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for U64<O> where [u8; 8]: FromBytes, PhantomData<O>: FromBytes,impl<O> FromBytes for Usize<O> where [u8; 8]: FromBytes, PhantomData<O>: FromBytes,impl<T> FromBytes for CoreMaybeUninit<T>impl<T> FromBytes for Unalign<T> where T: FromBytes,impl<T: ?Sized + FromBytes> FromBytes for Cell<T>impl<T: ?Sized + FromBytes> FromBytes for ManuallyDrop<T>impl<T: ?Sized + FromBytes> FromBytes for ReadOnly<T>impl<T: ?Sized + FromBytes> FromBytes for UnsafeCell<T>impl<T: ?Sized> FromBytes for PhantomData<T>impl<T: FromBytes> FromBytes for Wrapping<T>impl<T: FromBytes> FromBytes for [T]impl<T: FromBytes, const N: usize> FromBytes for [T; N]