Trait TryFromBytes
pub unsafe trait TryFromBytes
Types for which some bit patterns are valid.
A memory region of the appropriate length which contains initialized bytes
can be viewed as a TryFromBytes type so long as the runtime value of those
bytes corresponds to a valid instance of that type. For example,
bool is TryFromBytes, so zerocopy can transmute a u8 into a
bool so long as it first checks that the value of the u8 is 0 or
1.
Implementation
Do not implement this trait yourself! Instead, use
#[derive(TryFromBytes)]; e.g.:
# use ;
union MyUnion
This derive ensures that the runtime check of whether bytes correspond to a valid instance is sound. You must implement this trait via the derive.
What is a "valid instance"?
In Rust, each type has bit validity, which refers to the set of bit
patterns which may appear in an instance of that type. It is impossible for
safe Rust code to produce values which violate bit validity (ie, values
outside of the "valid" set of bit patterns). If unsafe code produces an
invalid value, this is considered undefined behavior.
Rust's bit validity rules are currently being decided, which means that some types have three classes of bit patterns: those which are definitely valid, and whose validity is documented in the language; those which may or may not be considered valid at some point in the future; and those which are definitely invalid.
Zerocopy takes a conservative approach, and only considers a bit pattern to be valid if its validity is a documented guarantee provided by the language.
For most use cases, Rust's current guarantees align with programmers' intuitions about what ought to be valid. As a result, zerocopy's conservatism should not affect most users.
If you are negatively affected by lack of support for a particular type, we encourage you to let us know by filing an issue.
TryFromBytes is not symmetrical with IntoBytes
There are some types which implement both TryFromBytes and IntoBytes,
but for which TryFromBytes is not guaranteed to accept all byte sequences
produced by IntoBytes. In other words, for some T: TryFromBytes + IntoBytes, there exist values of t: T such that
TryFromBytes::try_ref_from_bytes(t.as_bytes()) == None. Code should not
generally assume that values produced by IntoBytes will necessarily be
accepted as valid by TryFromBytes.
Safety
On its own, T: TryFromBytes does not make any guarantees about the layout
or representation of T. It merely provides the ability to perform a
validity check at runtime via methods like try_ref_from_bytes.
You must not rely on the #[doc(hidden)] internals of TryFromBytes.
Future releases of zerocopy may make backwards-breaking changes to these
items, including changes that only affect soundness, which may cause code
which uses those items to silently become unsound.
Provided Methods
fn try_ref_from_bytes(source: &[u8]) -> Result<&Self, TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable,Attempts to interpret the given
sourceas a&Self.If the bytes of
sourceare a valid instance ofSelf, this method returns a reference to those bytes interpreted as aSelf. If the length ofsourceis not a valid size ofSelf, or ifsourceis not appropriately aligned, or ifsourceis not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::try_ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the byte sequence `0xC0C0`. ; let bytes = &; let packet = try_ref_from_bytes.unwrap; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;§ 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_try_ref_from_bytes_static_size(source: &[u8]) -> Option<&format::CocoPacket> { zerocopy::TryFromBytes::try_ref_from_bytes(source).ok() }Assembly
bench_try_ref_from_bytes_static_size: mov rax, rdi cmp rsi, 6 setne cl or cl, al test cl, 1 jne .LBB5_2 cmp word ptr [rax], -16192 je .LBB5_3 .LBB5_2: xor eax, eax .LBB5_3: retMachine Code Analysis
Iterations: 100 Instructions: 1000 Total Cycles: 308 Total uOps: 1100 Dispatch Width: 4 uOps Per Cycle: 3.57 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.33 mov rax, rdi 1 1 0.33 cmp rsi, 6 1 1 0.50 setne cl 1 1 0.33 or cl, al 1 1 0.33 test cl, 1 1 1 1.00 jne .LBB5_2 2 6 0.50 * cmp word ptr [rax], -16192 1 1 1.00 je .LBB5_3 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] - - 2.98 2.98 - 3.04 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.02 0.97 - 0.01 - - mov rax, rdi - - 0.02 0.98 - - - - cmp rsi, 6 - - 1.00 - - - - - setne cl - - 0.97 0.02 - 0.01 - - or cl, al - - 0.96 0.03 - 0.01 - - test cl, 1 - - - - - 1.00 - - jne .LBB5_2 - - 0.01 0.98 - 0.01 0.50 0.50 cmp word ptr [rax], -16192 - - - - - 1.00 - - je .LBB5_3 - - - - - - - - xor eax, eax - - - - - 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_try_ref_from_bytes_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> { zerocopy::TryFromBytes::try_ref_from_bytes(source).ok() }Assembly
bench_try_ref_from_bytes_dynamic_size: mov rdx, rsi mov rax, rdi cmp rsi, 4 setb cl or cl, al test cl, 1 jne .LBB5_4 lea rcx, [rdx - 4] mov rsi, rcx and rsi, -2 add rsi, 4 cmp rdx, rsi jne .LBB5_4 cmp word ptr [rax], -16192 jne .LBB5_4 shr rcx mov rdx, rcx ret .LBB5_4: xor eax, eax retMachine Code Analysis
Iterations: 100 Instructions: 2000 Total Cycles: 639 Total uOps: 2100 Dispatch Width: 4 uOps Per Cycle: 3.29 IPC: 3.13 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.33 mov rdx, rsi 1 1 0.33 mov rax, rdi 1 1 0.33 cmp rsi, 4 1 1 0.50 setb cl 1 1 0.33 or cl, al 1 1 0.33 test cl, 1 1 1 1.00 jne .LBB5_4 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.33 cmp rdx, rsi 1 1 1.00 jne .LBB5_4 2 6 0.50 * cmp word ptr [rax], -16192 1 1 1.00 jne .LBB5_4 1 1 0.50 shr rcx 1 1 0.33 mov rdx, rcx 1 1 1.00 U ret 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.32 6.32 - 6.36 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.33 0.66 - 0.01 - - mov rdx, rsi - - 0.66 0.34 - - - - mov rax, rdi - - 0.34 0.66 - - - - cmp rsi, 4 - - 0.99 - - 0.01 - - setb cl - - 0.01 0.99 - - - - or cl, al - - - 1.00 - - - - test cl, 1 - - - - - 1.00 - - jne .LBB5_4 - - 0.66 0.34 - - - - lea rcx, [rdx - 4] - - 0.33 0.66 - 0.01 - - mov rsi, rcx - - 1.00 - - - - - and rsi, -2 - - 0.66 0.34 - - - - add rsi, 4 - - - 1.00 - - - - cmp rdx, rsi - - - - - 1.00 - - jne .LBB5_4 - - - - - 1.00 0.50 0.50 cmp word ptr [rax], -16192 - - - - - 1.00 - - jne .LBB5_4 - - 0.67 - - 0.33 - - shr rcx - - 0.67 0.33 - - - - mov rdx, rcx - - - - - 1.00 - - ret - - - - - - - - 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_try_ref_from_bytes_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> { zerocopy::TryFromBytes::try_ref_from_bytes(source).ok() }Assembly
bench_try_ref_from_bytes_dynamic_padding: test dil, 3 jne .LBB5_4 movabs rax, 9223372036854775804 and rax, rsi cmp rax, 9 jb .LBB5_4 add rax, -9 movabs rcx, -6148914691236517205 mul rcx shr rdx lea rax, [rdx + 2*rdx] or rax, 3 add rax, 9 cmp rsi, rax jne .LBB5_4 cmp word ptr [rdi], -16192 je .LBB5_5 .LBB5_4: xor edi, edi mov rdx, rsi .LBB5_5: mov rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 2100 Total Cycles: 709 Total uOps: 2300 Dispatch Width: 4 uOps Per Cycle: 3.24 IPC: 2.96 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 test dil, 3 1 1 1.00 jne .LBB5_4 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_4 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 jne .LBB5_4 2 6 0.50 * cmp word ptr [rdi], -16192 1 1 1.00 je .LBB5_5 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.98 6.99 - 7.03 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.48 0.51 - 0.01 - - test dil, 3 - - - - - 1.00 - - jne .LBB5_4 - - 0.51 0.49 - - - - movabs rax, 9223372036854775804 - - 0.01 0.99 - - - - and rax, rsi - - 0.51 0.49 - - - - cmp rax, 9 - - - - - 1.00 - - jb .LBB5_4 - - 0.98 - - 0.02 - - add rax, -9 - - 0.98 0.02 - - - - movabs rcx, -6148914691236517205 - - 1.00 1.00 - - - - mul rcx - - 0.99 - - 0.01 - - shr rdx - - - 1.00 - - - - lea rax, [rdx + 2*rdx] - - - 0.51 - 0.49 - - or rax, 3 - - 0.01 0.49 - 0.50 - - add rax, 9 - - - 0.02 - 0.98 - - cmp rsi, rax - - - - - 1.00 - - jne .LBB5_4 - - 0.51 0.49 - - 0.50 0.50 cmp word ptr [rdi], -16192 - - - - - 1.00 - - je .LBB5_5 - - - - - - - - xor edi, edi - - 0.50 0.50 - - - - mov rdx, rsi - - 0.50 0.48 - 0.02 - - mov rax, rdi - - - - - 1.00 - - retfn try_ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable,Attempts to interpret the prefix of the given
sourceas a&Self.This method computes the largest possible size of
Selfthat can fit in the leading bytes ofsource. If that prefix is a valid instance ofSelf, this method returns a reference to those bytes interpreted asSelf, and a reference to the remaining bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, or if those bytes are not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::try_ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &; let = try_ref_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;§ 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_try_ref_from_prefix_static_size(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_ref_from_prefix_static_size: cmp rsi, 6 setb al or al, dil test al, 1 jne .LBB5_2 movzx eax, word ptr [rdi] cmp eax, 49344 mov eax, 2 cmove rax, rdi je .LBB5_3 .LBB5_2: xor eax, eax .LBB5_3: retMachine Code Analysis
Iterations: 100 Instructions: 1200 Total Cycles: 374 Total uOps: 1300 Dispatch Width: 4 uOps Per Cycle: 3.48 IPC: 3.21 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, 6 1 1 0.50 setb al 1 1 0.33 or al, dil 1 1 0.33 test al, 1 1 1 1.00 jne .LBB5_2 1 5 0.50 * movzx eax, word ptr [rdi] 1 1 0.33 cmp eax, 49344 1 1 0.33 mov eax, 2 2 2 0.67 cmove rax, rdi 1 1 1.00 je .LBB5_3 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] - - 3.66 3.65 - 3.69 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.35 0.64 - 0.01 - - cmp rsi, 6 - - 1.00 - - - - - setb al - - 0.02 0.66 - 0.32 - - or al, dil - - 0.03 0.65 - 0.32 - - test al, 1 - - - - - 1.00 - - jne .LBB5_2 - - - - - - 0.50 0.50 movzx eax, word ptr [rdi] - - 0.92 0.07 - 0.01 - - cmp eax, 49344 - - 0.37 0.63 - - - - mov eax, 2 - - 0.97 1.00 - 0.03 - - cmove rax, rdi - - - - - 1.00 - - je .LBB5_3 - - - - - - - - xor eax, eax - - - - - 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_try_ref_from_prefix_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_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 movzx ecx, word ptr [rdi] cmp ecx, 49344 mov edx, 2 cmove rdx, rsi xor eax, eax cmp cx, -16192 cmove rax, rdi .LBB5_4: retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 573 Total uOps: 2100 Dispatch Width: 4 uOps Per Cycle: 3.66 IPC: 3.32 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 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 5 0.50 * movzx ecx, word ptr [rdi] 1 1 0.33 cmp ecx, 49344 1 1 0.33 mov edx, 2 2 2 0.67 cmove rdx, rsi 1 0 0.25 xor eax, eax 1 1 0.33 cmp cx, -16192 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.66 5.67 - 5.67 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - - - - - xor edx, edx - - 0.30 0.37 - 0.33 - - mov eax, 0 - - 0.35 0.32 - 0.33 - - test dil, 1 - - - - - 1.00 - - jne .LBB5_4 - - 0.32 0.33 - 0.35 - - cmp rsi, 4 - - - - - 1.00 - - jae .LBB5_3 - - 0.33 0.35 - 0.32 - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.34 0.64 - 0.02 - - add rsi, -4 - - 1.00 - - - - - shr rsi - - - - - - 0.50 0.50 movzx ecx, word ptr [rdi] - - 0.60 0.40 - - - - cmp ecx, 49344 - - 0.05 0.95 - - - - mov edx, 2 - - 1.00 1.00 - - - - cmove rdx, rsi - - - - - - - - xor eax, eax - - 0.37 0.31 - 0.32 - - cmp cx, -16192 - - 1.00 1.00 - - - - 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_try_ref_from_prefix_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_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 mov rax, rdx shr rax movzx ecx, word ptr [rdi] cmp cx, -16192 mov edx, 2 cmove rdx, rax xor eax, eax cmp ecx, 49344 cmove rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 2600 Total Cycles: 843 Total uOps: 2900 Dispatch Width: 4 uOps Per Cycle: 3.44 IPC: 3.08 Block RThroughput: 7.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 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.33 mov rax, rdx 1 1 0.50 shr rax 1 5 0.50 * movzx ecx, word ptr [rdi] 1 1 0.33 cmp cx, -16192 1 1 0.33 mov edx, 2 2 2 0.67 cmove rdx, rax 1 0 0.25 xor eax, eax 1 1 0.33 cmp ecx, 49344 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] - - 8.33 8.33 - 8.34 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - - - - - xor edx, edx - - 0.32 0.34 - 0.34 - - mov eax, 0 - - 0.34 0.33 - 0.33 - - test dil, 3 - - - - - 1.00 - - je .LBB5_1 - - - - - 1.00 - - ret - - 0.35 0.65 - - - - movabs rax, 9223372036854775804 - - 0.96 0.03 - 0.01 - - and rsi, rax - - 0.01 0.97 - 0.02 - - cmp rsi, 9 - - - - - 1.00 - - jae .LBB5_3 - - 0.67 0.01 - 0.32 - - mov edx, 1 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.02 0.34 - 0.64 - - add rsi, -9 - - 0.33 0.66 - 0.01 - - movabs rcx, -6148914691236517205 - - 0.66 0.34 - - - - mov rax, rsi - - 1.00 1.00 - - - - mul rcx - - 0.01 0.99 - - - - mov rax, rdx - - 0.99 - - 0.01 - - shr rax - - - - - - 0.50 0.50 movzx ecx, word ptr [rdi] - - 0.33 0.03 - 0.64 - - cmp cx, -16192 - - 0.01 0.31 - 0.68 - - mov edx, 2 - - 1.00 1.00 - - - - cmove rdx, rax - - - - - - - - xor eax, eax - - 0.33 0.33 - 0.34 - - cmp ecx, 49344 - - 1.00 1.00 - - - - cmove rax, rdi - - - - - 1.00 - - retfn try_ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable,Attempts to interpret the suffix of the given
sourceas a&Self.This method computes the largest possible size of
Selfthat can fit in the trailing bytes ofsource. If that suffix is a valid instance ofSelf, this method returns a reference to those bytes interpreted asSelf, and a reference to the preceding bytes. If there are insufficient bytes, or if the suffix ofsourcewould not be appropriately aligned, or if the suffix is not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, Immutable, KnownLayout)] #[repr(C)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let _ = ZSTy::try_ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &; let = try_ref_from_suffix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;§ 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_try_ref_from_suffix_static_size(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_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 rcx, [rdi + rsi] add rcx, -6 xor eax, eax cmp word ptr [rdi + rsi - 6], -16192 cmove rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 1400 Total Cycles: 443 Total uOps: 1600 Dispatch Width: 4 uOps Per Cycle: 3.61 IPC: 3.16 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 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 rcx, [rdi + rsi] 1 1 0.33 add rcx, -6 1 0 0.25 xor eax, eax 2 6 0.50 * cmp word ptr [rdi + rsi - 6], -16192 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] - - 4.33 4.33 - 4.34 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.32 0.68 - - - - lea eax, [rsi + rdi] - - 0.05 0.94 - 0.01 - - cmp rsi, 6 - - 1.00 - - - - - setb cl - - 0.95 0.05 - - - - or cl, al - - 0.95 0.02 - 0.03 - - test cl, 1 - - - - - 1.00 - - je .LBB5_2 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.04 0.96 - - - - lea rcx, [rdi + rsi] - - 0.02 0.97 - 0.01 - - add rcx, -6 - - - - - - - - xor eax, eax - - 0.03 0.66 - 0.31 0.50 0.50 cmp word ptr [rdi + rsi - 6], -16192 - - 0.97 0.05 - 0.98 - - 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_try_ref_from_suffix_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_ref_from_suffix_dynamic_size: lea eax, [rsi + rdi] cmp rsi, 4 setb cl or cl, al test cl, 1 je .LBB5_2 xor eax, eax ret .LBB5_2: lea rdx, [rsi - 4] shr rdx and esi, 1 lea rcx, [rdi + rsi] xor eax, eax cmp word ptr [rdi + rsi], -16192 cmove rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 1600 Total Cycles: 510 Total uOps: 1800 Dispatch Width: 4 uOps Per Cycle: 3.53 IPC: 3.14 Block RThroughput: 4.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.50 lea eax, [rsi + rdi] 1 1 0.33 cmp rsi, 4 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 rdx, [rsi - 4] 1 1 0.50 shr rdx 1 1 0.33 and esi, 1 1 1 0.50 lea rcx, [rdi + rsi] 1 0 0.25 xor eax, eax 2 6 0.50 * cmp word ptr [rdi + rsi], -16192 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] - - 4.99 5.00 - 5.01 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.98 0.02 - - - - lea eax, [rsi + rdi] - - - 0.98 - 0.02 - - cmp rsi, 4 - - 1.00 - - - - - setb cl - - 0.01 0.99 - - - - or cl, al - - 0.01 0.07 - 0.92 - - test cl, 1 - - - - - 1.00 - - je .LBB5_2 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.93 0.07 - - - - lea rdx, [rsi - 4] - - 0.93 - - 0.07 - - shr rdx - - 0.06 0.93 - 0.01 - - and esi, 1 - - 0.07 0.93 - - - - lea rcx, [rdi + rsi] - - - - - - - - xor eax, eax - - - 0.01 - 0.99 0.50 0.50 cmp word ptr [rdi + rsi], -16192 - - 1.00 1.00 - - - - cmove rax, 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_try_ref_from_suffix_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_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 rcx, [rdx + 2*rdx] sub rsi, rcx or rcx, -4 add rsi, rdi lea rdi, [rcx + rsi] add rdi, -8 xor eax, eax cmp word ptr [rcx + rsi - 8], -16192 cmove rax, rdi retMachine Code Analysis
Iterations: 100 Instructions: 2300 Total Cycles: 791 Total uOps: 2600 Dispatch Width: 4 uOps Per Cycle: 3.29 IPC: 2.91 Block RThroughput: 6.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.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 rcx, [rdx + 2*rdx] 1 1 0.33 sub rsi, rcx 1 1 0.33 or rcx, -4 1 1 0.33 add rsi, rdi 1 1 0.50 lea rdi, [rcx + rsi] 1 1 0.33 add rdi, -8 1 0 0.25 xor eax, eax 2 6 0.50 * cmp word ptr [rcx + rsi - 8], -16192 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] - - 7.70 7.58 - 7.72 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.26 0.74 - - - - lea eax, [rsi + rdi] - - 0.19 0.28 - 0.53 - - test al, 3 - - - - - 1.00 - - jne .LBB5_1 - - 0.93 0.06 - 0.01 - - movabs rax, 9223372036854775804 - - 0.81 0.14 - 0.05 - - and rax, rsi - - 0.55 0.43 - 0.02 - - cmp rax, 9 - - - - - 1.00 - - jae .LBB5_3 - - - - - - - - xor eax, eax - - - - - 1.00 - - ret - - 0.42 0.56 - 0.02 - - add rax, -9 - - 0.67 0.30 - 0.03 - - movabs rcx, -6148914691236517205 - - 1.00 1.00 - - - - mul rcx - - 0.71 - - 0.29 - - shr rdx - - 0.32 0.68 - - - - lea rcx, [rdx + 2*rdx] - - 0.57 0.04 - 0.39 - - sub rsi, rcx - - 0.28 0.67 - 0.05 - - or rcx, -4 - - 0.29 0.29 - 0.42 - - add rsi, rdi - - 0.02 0.98 - - - - lea rdi, [rcx + rsi] - - 0.02 0.41 - 0.57 - - add rdi, -8 - - - - - - - - xor eax, eax - - 0.57 0.01 - 0.42 0.50 0.50 cmp word ptr [rcx + rsi - 8], -16192 - - 0.09 0.99 - 0.92 - - cmove rax, rdi - - - - - 1.00 - - retfn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes,Attempts to interpret the given
sourceas a&mut Selfwithout copying.If the bytes of
sourceare a valid instance ofSelf, this method returns a reference to those bytes interpreted as aSelf. If the length ofsourceis not a valid size ofSelf, or ifsourceis not appropriately aligned, or ifsourceis not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: [u8; 2], trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::try_mut_from_bytes(&mut source[..]); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &mut ; let packet = try_mut_from_bytes.unwrap; assert_eq!; assert_eq!; assert_eq!; packet.temperature = 111; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;§ Code Generation
fn try_mut_from_prefix(source: &mut [u8]) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes,Attempts to interpret the prefix of the given
sourceas a&mut Self.This method computes the largest possible size of
Selfthat can fit in the leading bytes ofsource. If that prefix is a valid instance ofSelf, this method returns a reference to those bytes interpreted asSelf, and a reference to the remaining bytes. If there are insufficient bytes, or ifsourceis not appropriately aligned, or if the bytes are not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: [u8; 2], trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::try_mut_from_prefix(&mut source[..]); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &mut ; let = try_mut_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; packet.temperature = 111; suffix = 222; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;§ Code Generation
fn try_mut_from_suffix(source: &mut [u8]) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes,Attempts to interpret the suffix of the given
sourceas a&mut Self.This method computes the largest possible size of
Selfthat can fit in the trailing bytes ofsource. If that suffix is a valid instance ofSelf, this method returns a reference to those bytes interpreted asSelf, and a reference to the preceding bytes. If there are insufficient bytes, or if the suffix ofsourcewould not be appropriately aligned, or if the suffix is not a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].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(TryFromBytes, IntoBytes, KnownLayout)] #[repr(C, packed)] struct ZSTy { leading_sized: u16, trailing_dst: [()], } let mut source = [85, 85]; let _ = ZSTy::try_mut_from_suffix(&mut source[..]); // ⚠ Compile Error!Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &mut ; let = try_mut_from_suffix.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; prefix = 111; packet.temperature = 222; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;§ Code Generation
fn try_ref_from_bytes_with_elems(source: &[u8], count: usize) -> Result<&Self, TryCastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Attempts to interpret 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, ifsourceis not appropriately aligned, or ifsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &; let packet = try_ref_from_bytes_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_ref_from_byteswhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let src = 0xCAFEu16.as_bytes; let zsty = try_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_try_ref_from_bytes_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { zerocopy::TryFromBytes::try_ref_from_bytes_with_elems(source, count).ok() }Assembly
bench_try_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_3 lea rcx, [2*rdx + 4] cmp rsi, rcx jne .LBB5_3 cmp word ptr [rax], -16192 je .LBB5_4 .LBB5_3: xor eax, eax mov rdx, rsi .LBB5_4: retMachine Code Analysis
Iterations: 100 Instructions: 1500 Total Cycles: 507 Total uOps: 1700 Dispatch Width: 4 uOps Per Cycle: 3.35 IPC: 2.96 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, 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_3 1 1 0.50 lea rcx, [2*rdx + 4] 1 1 0.33 cmp rsi, rcx 1 1 1.00 jne .LBB5_3 2 6 0.50 * cmp word ptr [rax], -16192 1 1 1.00 je .LBB5_4 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.98 4.99 - 5.03 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - movabs rax, 4611686018427387901 - - 0.50 0.50 - - - - cmp rdx, rax - - 1.96 - - 0.04 - - 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_3 - - 0.01 0.99 - - - - lea rcx, [2*rdx + 4] - - 0.02 0.49 - 0.49 - - cmp rsi, rcx - - - - - 1.00 - - jne .LBB5_3 - - - 0.51 - 0.49 0.50 0.50 cmp word ptr [rax], -16192 - - - - - 1.00 - - je .LBB5_4 - - - - - - - - xor eax, eax - - 0.49 0.51 - - - - 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_try_ref_from_bytes_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { zerocopy::TryFromBytes::try_ref_from_bytes_with_elems(source, count).ok() }Assembly
bench_try_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_3 lea rcx, [rdx + 2*rdx] or rcx, 3 add rcx, 9 cmp rsi, rcx jne .LBB5_3 cmp word ptr [rax], -16192 je .LBB5_4 .LBB5_3: xor eax, eax mov rdx, rsi .LBB5_4: retMachine Code Analysis
Iterations: 100 Instructions: 1800 Total Cycles: 607 Total uOps: 2000 Dispatch Width: 4 uOps Per Cycle: 3.29 IPC: 2.97 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, 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_3 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 jne .LBB5_3 2 6 0.50 * cmp word ptr [rax], -16192 1 1 1.00 je .LBB5_4 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.99 5.99 - 6.02 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - movabs rax, 3074457345618258598 - - - 1.00 - - - - cmp rdx, rax - - - - - 2.00 - - seta cl - - 1.00 - - - - - mov rax, rdi - - 0.99 0.01 - - - - test al, 3 - - 1.00 - - - - - setne dil - - - 0.99 - 0.01 - - or dil, cl - - - - - 1.00 - - jne .LBB5_3 - - 0.01 0.99 - - - - lea rcx, [rdx + 2*rdx] - - - 1.00 - - - - or rcx, 3 - - 0.99 0.01 - - - - add rcx, 9 - - - 1.00 - - - - cmp rsi, rcx - - - - - 1.00 - - jne .LBB5_3 - - 1.00 - - - 0.50 0.50 cmp word ptr [rax], -16192 - - - - - 1.00 - - je .LBB5_4 - - - - - - - - xor eax, eax - - 1.00 - - - - - mov rdx, rsi - - - - - 1.00 - - retfn try_ref_from_prefix_with_elems(source: &[u8], count: usize) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Attempts to interpret the prefix of the given
sourceas a&Selfwith a DST 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 the length ofsourceis less than the size ofSelfwithcountelements, ifsourceis not appropriately aligned, or if the prefix ofsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &; let = try_ref_from_prefix_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_ref_from_prefixwhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let src = 0xCAFEu16.as_bytes; let = try_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_try_ref_from_prefix_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_prefix_with_elems(source, count) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_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_5 lea rax, [2*rcx + 4] cmp rax, rsi jbe .LBB5_4 .LBB5_1: xor eax, eax mov edx, 1 ret .LBB5_4: movzx esi, word ptr [rdi] cmp si, -16192 mov edx, 2 cmove rdx, rcx xor eax, eax cmp esi, 49344 cmove rax, rdi .LBB5_5: retMachine Code Analysis
Iterations: 100 Instructions: 2200 Total Cycles: 674 Total uOps: 2400 Dispatch Width: 4 uOps Per Cycle: 3.56 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, 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_5 1 1 0.50 lea rax, [2*rcx + 4] 1 1 0.33 cmp rax, rsi 1 1 1.00 jbe .LBB5_4 1 0 0.25 xor eax, eax 1 1 0.33 mov edx, 1 1 1 1.00 U ret 1 5 0.50 * movzx esi, word ptr [rdi] 1 1 0.33 cmp si, -16192 1 1 0.33 mov edx, 2 2 2 0.67 cmove rdx, rcx 1 0 0.25 xor eax, eax 1 1 0.33 cmp esi, 49344 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] - - 6.65 6.66 - 6.69 0.50 0.50 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.02 0.66 - 0.32 - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - 0.66 0.33 - 0.01 - - mov rcx, rdx - - - - - - - - xor edx, edx - - 0.33 0.01 - 0.66 - - mov eax, 0 - - 0.34 0.65 - 0.01 - - test dil, 1 - - - - - 1.00 - - jne .LBB5_5 - - 0.65 0.35 - - - - lea rax, [2*rcx + 4] - - - 1.00 - - - - cmp rax, rsi - - - - - 1.00 - - jbe .LBB5_4 - - - - - - - - xor eax, eax - - 0.34 0.01 - 0.65 - - mov edx, 1 - - - - - 1.00 - - ret - - - - - - 0.50 0.50 movzx esi, word ptr [rdi] - - 0.65 0.34 - 0.01 - - cmp si, -16192 - - 0.66 0.34 - - - - mov edx, 2 - - 1.00 0.99 - 0.01 - - cmove rdx, rcx - - - - - - - - xor eax, eax - - 0.34 0.66 - - - - cmp esi, 49344 - - 1.00 0.99 - 0.01 - - 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_try_ref_from_prefix_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_prefix_with_elems(source, count) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_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_3: lea rax, [rdx + 2*rdx] or rax, 3 add rax, 9 cmp rax, rsi jbe .LBB5_4 .LBB5_1: xor eax, eax mov edx, 1 ret .LBB5_4: movzx esi, word ptr [rdi] cmp si, -16192 mov ecx, 2 cmove rcx, rdx xor eax, eax cmp esi, 49344 cmove rax, rdi mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2600 Total Cycles: 806 Total uOps: 2800 Dispatch Width: 4 uOps Per Cycle: 3.47 IPC: 3.23 Block RThroughput: 7.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 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.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 rax, rsi 1 1 1.00 jbe .LBB5_4 1 0 0.25 xor eax, eax 1 1 0.33 mov edx, 1 1 1 1.00 U ret 1 5 0.50 * movzx esi, word ptr [rdi] 1 1 0.33 cmp si, -16192 1 1 0.33 mov ecx, 2 2 2 0.67 cmove rcx, rdx 1 0 0.25 xor eax, eax 1 1 0.33 cmp esi, 49344 2 2 0.67 cmove 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.98 7.99 - 8.03 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.98 - - 0.02 - - movabs rax, 3074457345618258598 - - - 1.00 - - - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - - - - - - - xor ecx, ecx - - 0.99 0.01 - - - - mov eax, 0 - - 0.01 0.96 - 0.03 - - test dil, 3 - - - - - 1.00 - - je .LBB5_3 - - 0.97 0.01 - 0.02 - - mov rdx, rcx - - - - - 1.00 - - ret - - 0.03 0.97 - - - - lea rax, [rdx + 2*rdx] - - 0.03 0.97 - - - - or rax, 3 - - 0.01 0.99 - - - - add rax, 9 - - - 1.00 - - - - cmp rax, rsi - - - - - 1.00 - - jbe .LBB5_4 - - - - - - - - xor eax, eax - - 0.98 0.01 - 0.01 - - mov edx, 1 - - - - - 1.00 - - ret - - - - - - 0.50 0.50 movzx esi, word ptr [rdi] - - 0.97 0.03 - - - - cmp si, -16192 - - 0.98 0.01 - 0.01 - - mov ecx, 2 - - 1.00 0.03 - 0.97 - - cmove rcx, rdx - - - - - - - - xor eax, eax - - 0.03 0.97 - - - - cmp esi, 49344 - - 1.00 1.00 - - - - cmove rax, rdi - - - 0.03 - 0.97 - - mov rdx, rcx - - - - - 1.00 - - retfn try_ref_from_suffix_with_elems(source: &[u8], count: usize) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + Immutable,Attempts to interpret the suffix of the given
sourceas a&Selfwith a DST 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 the length ofsourceis less than the size ofSelfwithcountelements, if the suffix ofsourceis not appropriately aligned, or if the suffix ofsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &; let = try_ref_from_suffix_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_ref_from_prefixwhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let src = 0xCAFEu16.as_bytes; let = try_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_try_ref_from_suffix_with_elems_dynamic_size( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_suffix_with_elems(source, count) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_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: lea r8, [rdi + rsi] movzx esi, word ptr [rdi + rsi] cmp si, -16192 mov ecx, 2 cmove rcx, rdx xor eax, eax cmp esi, 49344 cmove rax, r8 .LBB5_5: mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2400 Total Cycles: 1107 Total uOps: 2600 Dispatch Width: 4 uOps Per Cycle: 2.35 IPC: 2.17 Block RThroughput: 6.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 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.50 lea r8, [rdi + rsi] 1 5 0.50 * movzx esi, word ptr [rdi + rsi] 1 1 0.33 cmp si, -16192 1 1 0.33 mov ecx, 2 2 2 0.67 cmove rcx, rdx 1 0 0.25 xor eax, eax 1 1 0.33 cmp esi, 49344 2 2 0.67 cmove rax, r8 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 - 8.01 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.02 0.95 - 0.03 - - movabs rax, 4611686018427387901 - - 0.93 0.04 - 0.03 - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - 0.96 0.04 - - - - lea r8d, [rsi + rdi] - - - - - - - - xor ecx, ecx - - 0.95 0.02 - 0.03 - - mov eax, 0 - - 0.95 0.05 - - - - test r8b, 1 - - - - - 1.00 - - jne .LBB5_5 - - 0.06 0.94 - - - - lea rax, [2*rdx + 4] - - 0.93 0.07 - - - - sub rsi, rax - - - - - 1.00 - - jae .LBB5_4 - - - - - - - - xor eax, eax - - 0.03 0.95 - 0.02 - - mov edx, 1 - - - - - 1.00 - - ret - - 0.97 0.03 - - - - lea r8, [rdi + rsi] - - - - - - 0.50 0.50 movzx esi, word ptr [rdi + rsi] - - 0.03 0.97 - - - - cmp si, -16192 - - 0.05 0.94 - 0.01 - - mov ecx, 2 - - 0.06 0.98 - 0.96 - - cmove rcx, rdx - - - - - - - - xor eax, eax - - 0.97 0.03 - - - - cmp esi, 49344 - - 0.06 0.96 - 0.98 - - cmove rax, r8 - - 0.02 0.03 - 0.95 - - 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_try_ref_from_suffix_with_elems_dynamic_padding( source: &[u8], count: usize, ) -> Option<&format::CocoPacket> { match zerocopy::TryFromBytes::try_ref_from_suffix_with_elems(source, count) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_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: lea r8, [rdi + rsi] movzx esi, word ptr [rdi + rsi] cmp si, -16192 mov ecx, 2 cmove rcx, rdx xor eax, eax cmp esi, 49344 cmove rax, r8 mov rdx, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2800 Total Cycles: 878 Total uOps: 3000 Dispatch Width: 4 uOps Per Cycle: 3.42 IPC: 3.19 Block RThroughput: 7.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, 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.50 lea r8, [rdi + rsi] 1 5 0.50 * movzx esi, word ptr [rdi + rsi] 1 1 0.33 cmp si, -16192 1 1 0.33 mov ecx, 2 2 2 0.67 cmove rcx, rdx 1 0 0.25 xor eax, eax 1 1 0.33 cmp esi, 49344 2 2 0.67 cmove rax, r8 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] - - 8.65 8.65 - 8.70 0.50 0.50 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.67 0.30 - 0.03 - - movabs rax, 3074457345618258598 - - 0.01 0.99 - - - - cmp rdx, rax - - - - - 1.00 - - ja .LBB5_1 - - 0.99 0.01 - - - - lea r8d, [rsi + rdi] - - - - - - - - xor ecx, ecx - - 0.35 0.62 - 0.03 - - mov eax, 0 - - 0.99 0.01 - - - - test r8b, 3 - - - - - 1.00 - - je .LBB5_3 - - 0.68 0.30 - 0.02 - - mov rdx, rcx - - - - - 1.00 - - ret - - 0.07 0.93 - - - - lea rax, [rdx + 2*rdx] - - 0.06 0.35 - 0.59 - - or rax, 3 - - 0.02 0.07 - 0.91 - - add rax, 9 - - 0.01 0.04 - 0.95 - - sub rsi, rax - - - - - 1.00 - - jae .LBB5_4 - - - - - - - - xor eax, eax - - 0.92 0.01 - 0.07 - - mov edx, 1 - - - - - 1.00 - - ret - - - 1.00 - - - - lea r8, [rdi + rsi] - - - - - - 0.50 0.50 movzx esi, word ptr [rdi + rsi] - - 0.01 0.99 - - - - cmp si, -16192 - - 0.88 0.04 - 0.08 - - mov ecx, 2 - - 1.00 0.99 - 0.01 - - cmove rcx, rdx - - - - - - - - xor eax, eax - - 0.99 0.01 - - - - cmp esi, 49344 - - 1.00 1.00 - - - - cmove rax, r8 - - - 0.99 - 0.01 - - mov rdx, rcx - - - - - 1.00 - - retfn try_mut_from_bytes_with_elems(source: &mut [u8], count: usize) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + IntoBytes,Attempts to interpret 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, ifsourceis not appropriately aligned, or ifsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &mut ; let packet = try_mut_from_bytes_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; packet.temperature = 111; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_mut_from_byteswhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let mut src = 0xCAFEu16; let src = src.as_mut_bytes; let zsty = try_mut_from_bytes_with_elems.unwrap; assert_eq!;§ Code Generation
fn try_mut_from_prefix_with_elems(source: &mut [u8], count: usize) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + IntoBytes,Attempts to interpret the prefix of the given
sourceas a&mut Selfwith a DST 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 the length ofsourceis less than the size ofSelfwithcountelements, ifsourceis not appropriately aligned, or if the prefix ofsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &mut ; let = try_mut_from_prefix_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; packet.temperature = 111; suffix = 222; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_mut_from_prefixwhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let mut src = 0xCAFEu16; let src = src.as_mut_bytes; let = try_mut_from_prefix_with_elems.unwrap; assert_eq!;§ Code Generation
fn try_mut_from_suffix_with_elems(source: &mut [u8], count: usize) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where Self: KnownLayout<PointerMetadata = usize> + IntoBytes,Attempts to interpret the suffix of the given
sourceas a&mut Selfwith a DST 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 the length ofsourceis less than the size ofSelfwithcountelements, if the suffix ofsourceis not appropriately aligned, or if the suffix ofsourcedoes not contain a valid instance ofSelf, this returnsErr. IfSelf: Unaligned, you can [infallibly discard the alignment error][ConvertError::from].Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &mut ; let = try_mut_from_suffix_with_elems.unwrap; assert_eq!; assert_eq!; assert_eq!; assert_eq!; prefix = 111; packet.temperature = 222; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;Since an explicit
countis provided, this method supports types with zero-sized trailing slice elements. Methods such astry_mut_from_prefixwhich do not take an explicit count do not support such types.use NonZeroU16; use *; # use *; let mut src = 0xCAFEu16; let src = src.as_mut_bytes; let = try_mut_from_suffix_with_elems.unwrap; assert_eq!;§ Code Generation
fn try_read_from_bytes(source: &[u8]) -> Result<Self, TryReadError<&[u8], Self>> where Self: Sized,Attempts to read the given
sourceas aSelf.If
source.len() != size_of::<Self>()or the bytes are not a valid instance ofSelf, this returnsErr.Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; let bytes = &; let packet = try_read_from_bytes.unwrap; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &mut ; assert!;Performance Considerations
In this version of zerocopy, this method reads the
sourceinto a well-aligned stack allocation and then validates that the allocation is a validSelf. This ensures that validation can be performed using aligned reads (which carry a performance advantage over unaligned reads on many platforms) at the cost of an unconditional copy.§ 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_try_read_from_bytes_static_size(source: &[u8]) -> Option<format::CocoPacket> { zerocopy::TryFromBytes::try_read_from_bytes(source).ok() }Assembly
bench_try_read_from_bytes_static_size: mov ax, -16191 cmp rsi, 6 jne .LBB5_1 mov ecx, dword ptr [rdi] movzx edx, cx cmp edx, 49344 jne .LBB5_4 movzx eax, word ptr [rdi + 4] shl rax, 32 or rcx, rax shr rcx, 16 mov ax, -16192 .LBB5_4: shl rcx, 16 movzx eax, ax or rax, rcx ret .LBB5_1: shl rcx, 16 movzx eax, ax or rax, rcx retMachine Code Analysis
Iterations: 100 Instructions: 2000 Total Cycles: 608 Total uOps: 2000 Dispatch Width: 4 uOps Per Cycle: 3.29 IPC: 3.29 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 ax, -16191 1 1 0.33 cmp rsi, 6 1 1 1.00 jne .LBB5_1 1 5 0.50 * mov ecx, dword ptr [rdi] 1 1 0.33 movzx edx, cx 1 1 0.33 cmp edx, 49344 1 1 1.00 jne .LBB5_4 1 5 0.50 * movzx eax, word ptr [rdi + 4] 1 1 0.50 shl rax, 32 1 1 0.33 or rcx, rax 1 1 0.50 shr rcx, 16 1 1 0.33 mov ax, -16192 1 1 0.50 shl rcx, 16 1 1 0.33 movzx eax, ax 1 1 0.33 or rax, rcx 1 1 1.00 U ret 1 1 0.50 shl rcx, 16 1 1 0.33 movzx eax, ax 1 1 0.33 or 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] - - 5.99 5.99 - 6.02 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.99 - 0.01 - - mov ax, -16191 - - - 0.01 - 0.99 - - cmp rsi, 6 - - - - - 1.00 - - jne .LBB5_1 - - - - - - - 1.00 mov ecx, dword ptr [rdi] - - 0.98 - - 0.02 - - movzx edx, cx - - 0.99 0.01 - - - - cmp edx, 49344 - - - - - 1.00 - - jne .LBB5_4 - - - - - - 1.00 - movzx eax, word ptr [rdi + 4] - - 0.01 - - 0.99 - - shl rax, 32 - - 0.02 0.98 - - - - or rcx, rax - - 1.00 - - - - - shr rcx, 16 - - 0.99 0.01 - - - - mov ax, -16192 - - 1.00 - - - - - shl rcx, 16 - - - 1.00 - - - - movzx eax, ax - - - 1.00 - - - - or rax, rcx - - - - - 1.00 - - ret - - 1.00 - - - - - shl rcx, 16 - - - 1.00 - - - - movzx eax, ax - - - 0.99 - 0.01 - - or rax, rcx - - - - - 1.00 - - retfn try_read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), TryReadError<&[u8], Self>> where Self: Sized,Attempts to read a
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>()or the bytes are not a valid instance ofSelf, it returnsErr.Examples
use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &; let = try_read_from_prefix.unwrap; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;Performance Considerations
In this version of zerocopy, this method reads the
sourceinto a well-aligned stack allocation and then validates that the allocation is a validSelf. This ensures that validation can be performed using aligned reads (which carry a performance advantage over unaligned reads on many platforms) at the cost of an unconditional copy.§ 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_try_read_from_prefix_static_size(source: &[u8]) -> Option<format::CocoPacket> { match zerocopy::TryFromBytes::try_read_from_prefix(source) { Ok((packet, _rest)) => Some(packet), _ => None, } }Assembly
bench_try_read_from_prefix_static_size: mov eax, 49345 cmp rsi, 6 jb .LBB5_2 mov eax, dword ptr [rdi] movzx ecx, word ptr [rdi + 4] shl rcx, 32 or rcx, rax movzx eax, cx and rcx, -65536 or rcx, 49344 cmp eax, 49344 mov eax, 49345 cmove rax, rcx .LBB5_2: retMachine Code Analysis
Iterations: 100 Instructions: 1400 Total Cycles: 442 Total uOps: 1500 Dispatch Width: 4 uOps Per Cycle: 3.39 IPC: 3.17 Block RThroughput: 3.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 mov eax, 49345 1 1 0.33 cmp rsi, 6 1 1 1.00 jb .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.33 movzx eax, cx 1 1 0.33 and rcx, -65536 1 1 0.33 or rcx, 49344 1 1 0.33 cmp eax, 49344 1 1 0.33 mov eax, 49345 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] - - 4.33 4.33 - 4.34 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.65 0.01 - 0.34 - - mov eax, 49345 - - 0.01 0.33 - 0.66 - - cmp rsi, 6 - - - - - 1.00 - - jb .LBB5_2 - - - - - - - 1.00 mov eax, dword ptr [rdi] - - - - - - 1.00 - movzx ecx, word ptr [rdi + 4] - - 0.65 - - 0.35 - - shl rcx, 32 - - - 0.67 - 0.33 - - or rcx, rax - - 0.01 0.99 - - - - movzx eax, cx - - 0.99 0.01 - - - - and rcx, -65536 - - 0.01 0.99 - - - - or rcx, 49344 - - 0.99 0.01 - - - - cmp eax, 49344 - - 0.02 0.33 - 0.65 - - mov eax, 49345 - - 1.00 0.99 - 0.01 - - cmove rax, rcx - - - - - 1.00 - - retfn try_read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), TryReadError<&[u8], Self>> where Self: Sized,Attempts to read a
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>()or the bytes are not a valid instance ofSelf, it returnsErr.Examples
# // For C0::xC0 use TryFromBytes; # use *; // The only valid value of this type is the byte `0xC0` // The only valid value of this type is the bytes `0xC0C0`. ; // These are more bytes than are needed to encode a `Packet`. let bytes = &; let = try_read_from_suffix.unwrap; assert_eq!; assert_eq!; assert_eq!; // These bytes are not valid instance of `Packet`. let bytes = &; assert!;Performance Considerations
In this version of zerocopy, this method reads the
sourceinto a well-aligned stack allocation and then validates that the allocation is a validSelf. This ensures that validation can be performed using aligned reads (which carry a performance advantage over unaligned reads on many platforms) at the cost of an unconditional copy.§ 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_try_read_from_suffix_static_size(source: &[u8]) -> Option<format::CocoPacket> { match zerocopy::TryFromBytes::try_read_from_suffix(source) { Ok((_rest, packet)) => Some(packet), _ => None, } }Assembly
bench_try_read_from_suffix_static_size: mov eax, 49345 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 movzx edx, cx xor eax, eax cmp edx, 49344 cmovne rcx, rsi sete al and rcx, -65536 xor rax, 49345 or rax, rcx .LBB5_2: retMachine Code Analysis
Iterations: 100 Instructions: 1600 Total Cycles: 478 Total uOps: 1700 Dispatch Width: 4 uOps Per Cycle: 3.56 IPC: 3.35 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 mov eax, 49345 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.33 movzx edx, cx 1 0 0.25 xor eax, eax 1 1 0.33 cmp edx, 49344 2 2 0.67 cmovne rcx, rsi 1 1 0.50 sete al 1 1 0.33 and rcx, -65536 1 1 0.33 xor rax, 49345 1 1 0.33 or 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] - - 4.66 4.66 - 4.68 1.00 1.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.32 0.01 - 0.67 - - mov eax, 49345 - - 0.62 0.02 - 0.36 - - 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.37 - - 0.63 - - shl rcx, 32 - - 0.99 0.01 - - - - or rcx, rax - - 1.00 - - - - - movzx edx, cx - - - - - - - - xor eax, eax - - 0.35 0.64 - 0.01 - - cmp edx, 49344 - - 1.00 1.00 - - - - cmovne rcx, rsi - - - - - 1.00 - - sete al - - 0.01 0.99 - - - - and rcx, -65536 - - - 1.00 - - - - xor rax, 49345 - - - 0.99 - 0.01 - - or rax, rcx - - - - - 1.00 - - ret
Implementors
impl TryFromBytes for ()impl TryFromBytes for AtomicBoolimpl TryFromBytes for AtomicI16impl TryFromBytes for AtomicI32impl TryFromBytes for AtomicI64impl TryFromBytes for AtomicI8impl TryFromBytes for AtomicIsizeimpl TryFromBytes for AtomicU16impl TryFromBytes for AtomicU32impl TryFromBytes for AtomicU64impl TryFromBytes for AtomicU8impl TryFromBytes for AtomicUsizeimpl TryFromBytes for NonZeroI128impl TryFromBytes for NonZeroI16impl TryFromBytes for NonZeroI32impl TryFromBytes for NonZeroI64impl TryFromBytes for NonZeroI8impl TryFromBytes for NonZeroIsizeimpl TryFromBytes for NonZeroU128impl TryFromBytes for NonZeroU16impl TryFromBytes for NonZeroU32impl TryFromBytes for NonZeroU64impl TryFromBytes for NonZeroU8impl TryFromBytes for NonZeroUsizeimpl TryFromBytes for Option<NonZeroI128>impl TryFromBytes for Option<NonZeroI16>impl TryFromBytes for Option<NonZeroI32>impl TryFromBytes for Option<NonZeroI64>impl TryFromBytes for Option<NonZeroI8>impl TryFromBytes for Option<NonZeroIsize>impl TryFromBytes for Option<NonZeroU128>impl TryFromBytes for Option<NonZeroU16>impl TryFromBytes for Option<NonZeroU32>impl TryFromBytes for Option<NonZeroU64>impl TryFromBytes for Option<NonZeroU8>impl TryFromBytes for Option<NonZeroUsize>impl TryFromBytes for __m128impl TryFromBytes for __m128dimpl TryFromBytes for __m128iimpl TryFromBytes for __m256impl TryFromBytes for __m256dimpl TryFromBytes for __m256iimpl TryFromBytes for __m512impl TryFromBytes for __m512bhimpl TryFromBytes for __m512dimpl TryFromBytes for __m512iimpl TryFromBytes for boolimpl TryFromBytes for charimpl TryFromBytes for f32impl TryFromBytes for f64impl TryFromBytes for i128impl TryFromBytes for i16impl TryFromBytes for i32impl TryFromBytes for i64impl TryFromBytes for i8impl TryFromBytes for isizeimpl TryFromBytes for strimpl TryFromBytes for u128impl TryFromBytes for u16impl TryFromBytes for u32impl TryFromBytes for u64impl TryFromBytes for u8impl TryFromBytes for usizeimpl<A, B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(A, B, C, D, E, F, G, H, I, J, K, L) -> M>impl<A, B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(A, B, C, D, E, F, G, H, I, J, K, L) -> M>impl<A, B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(A, B, C, D, E, F, G, H, I, J, K, L) -> M>impl<A, B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(A, B, C, D, E, F, G, H, I, J, K, L) -> M>impl<A: TryFromBytes> TryFromBytes for (A,)impl<A: TryFromBytes, B: TryFromBytes> TryFromBytes for (A, B)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes> TryFromBytes for (A, B, C)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes> TryFromBytes for (A, B, C, D)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes> TryFromBytes for (A, B, C, D, E)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes> TryFromBytes for (A, B, C, D, E, F)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes> TryFromBytes for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)impl<A: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes, V: TryFromBytes> TryFromBytes 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: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes, V: TryFromBytes, W: TryFromBytes> TryFromBytes 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: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes, V: TryFromBytes, W: TryFromBytes, X: TryFromBytes> TryFromBytes 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: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes, V: TryFromBytes, W: TryFromBytes, X: TryFromBytes, Y: TryFromBytes> TryFromBytes 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: TryFromBytes, B: TryFromBytes, C: TryFromBytes, D: TryFromBytes, E: TryFromBytes, F: TryFromBytes, G: TryFromBytes, H: TryFromBytes, I: TryFromBytes, J: TryFromBytes, K: TryFromBytes, L: TryFromBytes, M: TryFromBytes, N: TryFromBytes, O: TryFromBytes, P: TryFromBytes, Q: TryFromBytes, R: TryFromBytes, S: TryFromBytes, T: TryFromBytes, U: TryFromBytes, V: TryFromBytes, W: TryFromBytes, X: TryFromBytes, Y: TryFromBytes, Z: TryFromBytes> TryFromBytes 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<B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(B, C, D, E, F, G, H, I, J, K, L) -> M>impl<B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(B, C, D, E, F, G, H, I, J, K, L) -> M>impl<B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(B, C, D, E, F, G, H, I, J, K, L) -> M>impl<B, C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(B, C, D, E, F, G, H, I, J, K, L) -> M>impl<C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(C, D, E, F, G, H, I, J, K, L) -> M>impl<C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(C, D, E, F, G, H, I, J, K, L) -> M>impl<C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(C, D, E, F, G, H, I, J, K, L) -> M>impl<C, D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(C, D, E, F, G, H, I, J, K, L) -> M>impl<D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(D, E, F, G, H, I, J, K, L) -> M>impl<D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(D, E, F, G, H, I, J, K, L) -> M>impl<D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(D, E, F, G, H, I, J, K, L) -> M>impl<D, E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(D, E, F, G, H, I, J, K, L) -> M>impl<E, F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(E, F, G, H, I, J, K, L) -> M>impl<E, F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(E, F, G, H, I, J, K, L) -> M>impl<E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(E, F, G, H, I, J, K, L) -> M>impl<E, F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(E, F, G, H, I, J, K, L) -> M>impl<F, G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(F, G, H, I, J, K, L) -> M>impl<F, G, H, I, J, K, L, M> TryFromBytes for Option<fn(F, G, H, I, J, K, L) -> M>impl<F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(F, G, H, I, J, K, L) -> M>impl<F, G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(F, G, H, I, J, K, L) -> M>impl<G, H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(G, H, I, J, K, L) -> M>impl<G, H, I, J, K, L, M> TryFromBytes for Option<fn(G, H, I, J, K, L) -> M>impl<G, H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(G, H, I, J, K, L) -> M>impl<G, H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(G, H, I, J, K, L) -> M>impl<H, I, J, K, L, M> TryFromBytes for Option<extern "C" fn(H, I, J, K, L) -> M>impl<H, I, J, K, L, M> TryFromBytes for Option<fn(H, I, J, K, L) -> M>impl<H, I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(H, I, J, K, L) -> M>impl<H, I, J, K, L, M> TryFromBytes for Option<unsafe fn(H, I, J, K, L) -> M>impl<I, J, K, L, M> TryFromBytes for Option<extern "C" fn(I, J, K, L) -> M>impl<I, J, K, L, M> TryFromBytes for Option<fn(I, J, K, L) -> M>impl<I, J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(I, J, K, L) -> M>impl<I, J, K, L, M> TryFromBytes for Option<unsafe fn(I, J, K, L) -> M>impl<J, K, L, M> TryFromBytes for Option<extern "C" fn(J, K, L) -> M>impl<J, K, L, M> TryFromBytes for Option<fn(J, K, L) -> M>impl<J, K, L, M> TryFromBytes for Option<unsafe extern "C" fn(J, K, L) -> M>impl<J, K, L, M> TryFromBytes for Option<unsafe fn(J, K, L) -> M>impl<K, L, M> TryFromBytes for Option<extern "C" fn(K, L) -> M>impl<K, L, M> TryFromBytes for Option<fn(K, L) -> M>impl<K, L, M> TryFromBytes for Option<unsafe extern "C" fn(K, L) -> M>impl<K, L, M> TryFromBytes for Option<unsafe fn(K, L) -> M>impl<L, M> TryFromBytes for Option<extern "C" fn(L) -> M>impl<L, M> TryFromBytes for Option<fn(L) -> M>impl<L, M> TryFromBytes for Option<unsafe extern "C" fn(L) -> M>impl<L, M> TryFromBytes for Option<unsafe fn(L) -> M>impl<M> TryFromBytes for Option<extern "C" fn() -> M>impl<M> TryFromBytes for Option<fn() -> M>impl<M> TryFromBytes for Option<unsafe extern "C" fn() -> M>impl<M> TryFromBytes for Option<unsafe fn() -> M>impl<O> TryFromBytes for F32<O> where [u8; 4]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for F64<O> where [u8; 8]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for I128<O> where [u8; 16]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for I16<O> where [u8; 2]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for I32<O> where [u8; 4]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for I64<O> where [u8; 8]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for Isize<O> where [u8; 8]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for U128<O> where [u8; 16]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for U16<O> where [u8; 2]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for U32<O> where [u8; 4]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for U64<O> where [u8; 8]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<O> TryFromBytes for Usize<O> where [u8; 8]: TryFromBytes, PhantomData<O>: TryFromBytes,impl<T> TryFromBytes for *const Timpl<T> TryFromBytes for *mut Timpl<T> TryFromBytes for AtomicPtr<T>impl<T> TryFromBytes for CoreMaybeUninit<T>impl<T> TryFromBytes for Option<&T>impl<T> TryFromBytes for Option<&mut T>impl<T> TryFromBytes for Option<NonNull<T>>impl<T> TryFromBytes for Unalign<T> where T: TryFromBytes,impl<T: ?Sized + TryFromBytes> TryFromBytes for Cell<T>impl<T: ?Sized + TryFromBytes> TryFromBytes for ManuallyDrop<T>impl<T: ?Sized + TryFromBytes> TryFromBytes for ReadOnly<T>impl<T: ?Sized> TryFromBytes for PhantomData<T>impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T>impl<T: TryFromBytes> TryFromBytes for Wrapping<T>impl<T: TryFromBytes> TryFromBytes for [T]impl<T: TryFromBytes, const N: usize> TryFromBytes for [T; N]