Trait IntoBytes
pub unsafe trait IntoBytes
Types that can be converted to an immutable slice of initialized bytes.
Any IntoBytes type can be converted to a slice of initialized bytes of the
same size. This is useful for efficiently serializing structured data as raw
bytes.
Implementation
Do not implement this trait yourself! Instead, use
#[derive(IntoBytes)]; e.g.:
# use IntoBytes;
This derive performs a sophisticated, compile-time safety analysis to
determine whether a type is IntoBytes. See the derive
documentation for guidance on how to interpret error messages
produced by the derive's analysis.
Safety
This section describes what is required in order for T: IntoBytes, and
what unsafe code may assume of such types. If you don't plan on implementing
IntoBytes manually, and you don't plan on writing unsafe code that
operates on IntoBytes types, then you don't need to read this section.
If T: IntoBytes, then unsafe code may assume that it is sound to treat any
t: T as an immutable [u8] of length size_of_val(t). If a type is
marked as IntoBytes which violates this contract, it may cause undefined
behavior.
#[derive(IntoBytes)] only permits types which satisfy these
requirements.
Provided Methods
fn as_bytes(&self) -> &[u8] where Self: Immutable,Gets the bytes of this value.
Examples
use IntoBytes; # use *; let header = PacketHeader ; let bytes = header.as_bytes; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
use zerocopy::*; #[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_as_bytes_static_size(source: &format::CocoPacket) -> &[u8] { source.as_bytes() }Assembly
bench_as_bytes_static_size: mov rax, rdi mov edx, 6 retMachine Code Analysis
Iterations: 100 Instructions: 300 Total Cycles: 104 Total uOps: 300 Dispatch Width: 4 uOps Per Cycle: 2.88 IPC: 2.88 Block RThroughput: 1.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 mov edx, 6 1 1 1.00 U ret Resources: [0] - SBDivider [1] - SBFPDivider [2] - SBPort0 [3] - SBPort1 [4] - SBPort4 [5] - SBPort5 [6.0] - SBPort23 [6.1] - SBPort23 Resource pressure per iteration: [0] [1] [2] [3] [4] [5] [6.0] [6.1] - - 0.99 1.00 - 1.01 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.99 - - 0.01 - - mov rax, rdi - - - 1.00 - - - - mov edx, 6 - - - - - 1.00 - - retUnsized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [[u8; 2]], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
use zerocopy::*; #[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_as_bytes_dynamic_size(source: &format::CocoPacket) -> &[u8] { source.as_bytes() }Assembly
bench_as_bytes_dynamic_size: mov rax, rdi lea rdx, [2*rsi + 5] and rdx, -2 retMachine Code Analysis
Iterations: 100 Instructions: 400 Total Cycles: 137 Total uOps: 400 Dispatch Width: 4 uOps Per Cycle: 2.92 IPC: 2.92 Block RThroughput: 1.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.50 lea rdx, [2*rsi + 5] 1 1 0.33 and rdx, -2 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] - - 1.33 1.33 - 1.34 - - Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - 0.66 - 0.34 - - mov rax, rdi - - 0.33 0.67 - - - - lea rdx, [2*rsi + 5] - - 1.00 - - - - - and rdx, -2 - - - - - 1.00 - - retfn as_mut_bytes(&mut self) -> &mut [u8] where Self: FromBytes,Gets the bytes of this value mutably.
Examples
use IntoBytes; # use *; # let mut header = PacketHeader ; let bytes = header.as_mut_bytes; assert_eq!; bytes.reverse; assert_eq!;§ Code Generation
See
IntoBytes::as_bytes.fn write_to(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable,Writes a copy of
selftodst.If
dst.len() != size_of_val(self),write_toreturnsErr.Examples
use IntoBytes; # use *; let header = PacketHeader ; let mut bytes = ; header.write_to; assert_eq!;If too many or too few target bytes are provided,
write_toreturnsErrand leaves the target bytes unmodified:# use IntoBytes; # let header = MAX; let mut excessive_bytes = &mut ; let write_result = header.write_to; assert!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
use zerocopy::*; #[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_static_size(source: &format::CocoPacket, destination: &mut [u8]) -> Option<()> { source.write_to(destination).ok() }Assembly
bench_write_to_static_size: cmp rdx, 6 jne .LBB5_2 movzx eax, word ptr [rdi + 4] mov word ptr [rsi + 4], ax mov eax, dword ptr [rdi] mov dword ptr [rsi], eax .LBB5_2: cmp rdx, 6 sete al retMachine Code Analysis
Iterations: 100 Instructions: 900 Total Cycles: 233 Total uOps: 900 Dispatch Width: 4 uOps Per Cycle: 3.86 IPC: 3.86 Block RThroughput: 2.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 cmp rdx, 6 1 1 1.00 jne .LBB5_2 1 5 0.50 * movzx eax, word ptr [rdi + 4] 1 1 1.00 * mov word ptr [rsi + 4], ax 1 5 0.50 * mov eax, dword ptr [rdi] 1 1 1.00 * mov dword ptr [rsi], eax 1 1 0.33 cmp rdx, 6 1 1 0.50 sete al 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] - - 1.50 1.49 2.00 2.01 2.00 2.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.25 0.74 - 0.01 - - cmp rdx, 6 - - - - - 1.00 - - jne .LBB5_2 - - - - - - 0.50 0.50 movzx eax, word ptr [rdi + 4] - - - - 1.00 - 0.48 0.52 mov word ptr [rsi + 4], ax - - - - - - 0.52 0.48 mov eax, dword ptr [rdi] - - - - 1.00 - 0.50 0.50 mov dword ptr [rsi], eax - - 0.25 0.75 - - - - cmp rdx, 6 - - 1.00 - - - - - sete al - - - - - 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
use zerocopy::*; #[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_dynamic_size(source: &format::CocoPacket, destination: &mut [u8]) -> Option<()> { source.write_to(destination).ok() }Assembly
bench_write_to_dynamic_size: push r14 push rbx push rax mov rbx, rcx lea r14, [2*rsi + 5] and r14, -2 cmp rcx, r14 jne .LBB5_2 mov rax, rdi mov rdi, rdx mov rsi, rax mov rdx, rbx call qword ptr [rip + memcpy@GOTPCREL] .LBB5_2: cmp rbx, r14 sete al add rsp, 8 pop rbx pop r14 retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 2890 Total uOps: 2500 Dispatch Width: 4 uOps Per Cycle: 0.87 IPC: 0.66 Block RThroughput: 6.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 2 5 1.00 * push r14 2 5 1.00 * push rbx 2 5 1.00 * push rax 1 1 0.33 mov rbx, rcx 1 1 0.50 lea r14, [2*rsi + 5] 1 1 0.33 and r14, -2 1 1 0.33 cmp rcx, r14 1 1 1.00 jne .LBB5_2 1 1 0.33 mov rax, rdi 1 1 0.33 mov rdi, rdx 1 1 0.33 mov rsi, rax 1 1 0.33 mov rdx, rbx 4 7 1.00 * call qword ptr [rip + memcpy@GOTPCREL] 1 1 0.33 cmp rbx, r14 1 1 0.50 sete al 1 1 0.33 add rsp, 8 1 6 0.50 * pop rbx 1 6 0.50 * pop r14 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.64 4.00 4.70 4.00 3.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - 1.00 - - 1.00 push r14 - - - - 1.00 - 1.00 - push rbx - - - - 1.00 - - 1.00 push rax - - 0.02 0.97 - 0.01 - - mov rbx, rcx - - 0.97 0.03 - - - - lea r14, [2*rsi + 5] - - 0.63 0.35 - 0.02 - - and r14, -2 - - 0.31 0.34 - 0.35 - - cmp rcx, r14 - - - - - 1.00 - - jne .LBB5_2 - - 0.33 0.33 - 0.34 - - mov rax, rdi - - 0.36 0.31 - 0.33 - - mov rdi, rdx - - 0.33 0.35 - 0.32 - - mov rsi, rax - - 0.35 0.63 - 0.02 - - mov rdx, rbx - - - - 1.00 1.00 2.00 - call qword ptr [rip + memcpy@GOTPCREL] - - 0.65 0.35 - - - - cmp rbx, r14 - - 0.69 - - 0.31 - - sete al - - 0.02 0.98 - - - - add rsp, 8 - - - - - - - 1.00 pop rbx - - - - - - 1.00 - pop r14 - - - - - 1.00 - - retfn write_to_prefix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable,Writes a copy of
selfto the prefix ofdst.write_to_prefixwritesselfto the firstsize_of_val(self)bytes ofdst. Ifdst.len() < size_of_val(self), it returnsErr.Examples
use IntoBytes; # use *; let header = PacketHeader ; let mut bytes = ; header.write_to_prefix; assert_eq!;If insufficient target bytes are provided,
write_to_prefixreturnsErrand leaves the target bytes unmodified:# use IntoBytes; # let header = MAX; let mut insufficient_bytes = &mut ; let write_result = header.write_to_suffix; assert!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
use zerocopy::*; #[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_prefix_static_size( source: &format::CocoPacket, destination: &mut [u8], ) -> Option<()> { source.write_to_prefix(destination).ok() }Assembly
bench_write_to_prefix_static_size: cmp rdx, 6 jb .LBB5_2 movzx eax, word ptr [rdi + 4] mov word ptr [rsi + 4], ax mov eax, dword ptr [rdi] mov dword ptr [rsi], eax .LBB5_2: cmp rdx, 6 setae al retMachine Code Analysis
Iterations: 100 Instructions: 900 Total Cycles: 233 Total uOps: 900 Dispatch Width: 4 uOps Per Cycle: 3.86 IPC: 3.86 Block RThroughput: 2.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 cmp rdx, 6 1 1 1.00 jb .LBB5_2 1 5 0.50 * movzx eax, word ptr [rdi + 4] 1 1 1.00 * mov word ptr [rsi + 4], ax 1 5 0.50 * mov eax, dword ptr [rdi] 1 1 1.00 * mov dword ptr [rsi], eax 1 1 0.33 cmp rdx, 6 1 1 0.50 setae al 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] - - 1.50 1.49 2.00 2.01 2.00 2.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.25 0.74 - 0.01 - - cmp rdx, 6 - - - - - 1.00 - - jb .LBB5_2 - - - - - - 0.50 0.50 movzx eax, word ptr [rdi + 4] - - - - 1.00 - 0.48 0.52 mov word ptr [rsi + 4], ax - - - - - - 0.52 0.48 mov eax, dword ptr [rdi] - - - - 1.00 - 0.50 0.50 mov dword ptr [rsi], eax - - 0.25 0.75 - - - - cmp rdx, 6 - - 1.00 - - - - - setae al - - - - - 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
use zerocopy::*; #[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_prefix_dynamic_size( source: &format::CocoPacket, destination: &mut [u8], ) -> Option<()> { source.write_to_prefix(destination).ok() }Assembly
bench_write_to_prefix_dynamic_size: push r14 push rbx push rax mov rbx, rcx lea r14, [2*rsi + 5] and r14, -2 cmp r14, rcx ja .LBB5_2 mov rax, rdi mov rdi, rdx mov rsi, rax mov rdx, r14 call qword ptr [rip + memcpy@GOTPCREL] .LBB5_2: cmp r14, rbx setbe al add rsp, 8 pop rbx pop r14 retMachine Code Analysis
Iterations: 100 Instructions: 1900 Total Cycles: 2890 Total uOps: 2600 Dispatch Width: 4 uOps Per Cycle: 0.90 IPC: 0.66 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: 2 5 1.00 * push r14 2 5 1.00 * push rbx 2 5 1.00 * push rax 1 1 0.33 mov rbx, rcx 1 1 0.50 lea r14, [2*rsi + 5] 1 1 0.33 and r14, -2 1 1 0.33 cmp r14, rcx 1 1 1.00 ja .LBB5_2 1 1 0.33 mov rax, rdi 1 1 0.33 mov rdi, rdx 1 1 0.33 mov rsi, rax 1 1 0.33 mov rdx, r14 4 7 1.00 * call qword ptr [rip + memcpy@GOTPCREL] 1 1 0.33 cmp r14, rbx 2 2 1.00 setbe al 1 1 0.33 add rsp, 8 1 6 0.50 * pop rbx 1 6 0.50 * pop r14 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.47 4.49 4.00 5.04 4.00 3.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - 1.00 - - 1.00 push r14 - - - - 1.00 - 1.00 - push rbx - - - - 1.00 - - 1.00 push rax - - 0.48 0.51 - 0.01 - - mov rbx, rcx - - 0.51 0.49 - - - - lea r14, [2*rsi + 5] - - 0.48 0.05 - 0.47 - - and r14, -2 - - 0.48 0.49 - 0.03 - - cmp r14, rcx - - - - - 1.00 - - ja .LBB5_2 - - 0.04 0.47 - 0.49 - - mov rax, rdi - - 0.49 0.03 - 0.48 - - mov rdi, rdx - - 0.03 0.48 - 0.49 - - mov rsi, rax - - 0.48 0.51 - 0.01 - - mov rdx, r14 - - - - 1.00 1.00 2.00 - call qword ptr [rip + memcpy@GOTPCREL] - - 0.51 0.49 - - - - cmp r14, rbx - - 1.94 - - 0.06 - - setbe al - - 0.03 0.97 - - - - add rsp, 8 - - - - - - - 1.00 pop rbx - - - - - - 1.00 - pop r14 - - - - - 1.00 - - retfn write_to_suffix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable,Writes a copy of
selfto the suffix ofdst.write_to_suffixwritesselfto the lastsize_of_val(self)bytes ofdst. Ifdst.len() < size_of_val(self), it returnsErr.Examples
use IntoBytes; # use *; let header = PacketHeader ; let mut bytes = ; header.write_to_suffix; assert_eq!; let mut insufficient_bytes = &mut ; let write_result = header.write_to_suffix; assert!; assert_eq!;If insufficient target bytes are provided,
write_to_suffixreturnsErrand leaves the target bytes unmodified:# use IntoBytes; # let header = MAX; let mut insufficient_bytes = &mut ; let write_result = header.write_to_suffix; assert!; assert_eq!;§ Code Generation
This abstraction is safe and cheap, but does not necessarily have zero runtime cost. The codegen you experience in practice will depend on optimization level, the layout of the destination type, and what the compiler can prove about the source.
The below examples illustrate typical codegen for increasingly complex types:
Sized
Format
use zerocopy_derive::*; // The only valid value of this type are the bytes `0xC0C0`. #[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)] #[repr(u16)] pub enum C0C0 { _XC0C0 = 0xC0C0, } macro_rules! define_packet { ($name: ident, $trait: ident, $leading_field: ty) => { #[derive($trait, KnownLayout, Immutable, IntoBytes)] #[repr(C, align(2))] pub struct $name { magic_number: $leading_field, mug_size: u8, temperature: u8, marshmallows: [u8; 2], } }; } /// Packet begins with bytes 0xC0C0. define_packet!(CocoPacket, TryFromBytes, C0C0); /// Packet begins with any two bytes. define_packet!(LocoPacket, FromBytes, [u8; 2]);Benchmark
use zerocopy::*; #[path = "formats/coco_static_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_suffix_static_size( source: &format::CocoPacket, destination: &mut [u8], ) -> Option<()> { source.write_to_suffix(destination).ok() }Assembly
bench_write_to_suffix_static_size: cmp rdx, 6 jb .LBB5_2 movzx eax, word ptr [rdi + 4] mov word ptr [rsi + rdx - 2], ax mov eax, dword ptr [rdi] mov dword ptr [rsi + rdx - 6], eax .LBB5_2: cmp rdx, 6 setae al retMachine Code Analysis
Iterations: 100 Instructions: 900 Total Cycles: 233 Total uOps: 900 Dispatch Width: 4 uOps Per Cycle: 3.86 IPC: 3.86 Block RThroughput: 2.3 Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) [1] [2] [3] [4] [5] [6] Instructions: 1 1 0.33 cmp rdx, 6 1 1 1.00 jb .LBB5_2 1 5 0.50 * movzx eax, word ptr [rdi + 4] 1 1 1.00 * mov word ptr [rsi + rdx - 2], ax 1 5 0.50 * mov eax, dword ptr [rdi] 1 1 1.00 * mov dword ptr [rsi + rdx - 6], eax 1 1 0.33 cmp rdx, 6 1 1 0.50 setae al 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] - - 1.50 1.49 2.00 2.01 2.00 2.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - 0.25 0.74 - 0.01 - - cmp rdx, 6 - - - - - 1.00 - - jb .LBB5_2 - - - - - - 0.50 0.50 movzx eax, word ptr [rdi + 4] - - - - 1.00 - 0.48 0.52 mov word ptr [rsi + rdx - 2], ax - - - - - - 0.52 0.48 mov eax, dword ptr [rdi] - - - - 1.00 - 0.50 0.50 mov dword ptr [rsi + rdx - 6], eax - - 0.25 0.75 - - - - cmp rdx, 6 - - 1.00 - - - - - setae al - - - - - 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
use zerocopy::*; #[path = "formats/coco_dynamic_size.rs"] mod format; #[unsafe(no_mangle)] fn bench_write_to_suffix_dynamic_size( source: &format::CocoPacket, destination: &mut [u8], ) -> Option<()> { source.write_to_suffix(destination).ok() }Assembly
bench_write_to_suffix_dynamic_size: push r14 push rbx push rax mov rbx, rcx lea r14, [2*rsi + 5] and r14, -2 sub rcx, r14 jb .LBB5_2 mov rax, rdi add rdx, rcx mov rdi, rdx mov rsi, rax mov rdx, r14 call qword ptr [rip + memcpy@GOTPCREL] .LBB5_2: cmp rbx, r14 setae al add rsp, 8 pop rbx pop r14 retMachine Code Analysis
Iterations: 100 Instructions: 2000 Total Cycles: 2890 Total uOps: 2600 Dispatch Width: 4 uOps Per Cycle: 0.90 IPC: 0.69 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: 2 5 1.00 * push r14 2 5 1.00 * push rbx 2 5 1.00 * push rax 1 1 0.33 mov rbx, rcx 1 1 0.50 lea r14, [2*rsi + 5] 1 1 0.33 and r14, -2 1 1 0.33 sub rcx, r14 1 1 1.00 jb .LBB5_2 1 1 0.33 mov rax, rdi 1 1 0.33 add rdx, rcx 1 1 0.33 mov rdi, rdx 1 1 0.33 mov rsi, rax 1 1 0.33 mov rdx, r14 4 7 1.00 * call qword ptr [rip + memcpy@GOTPCREL] 1 1 0.33 cmp rbx, r14 1 1 0.50 setae al 1 1 0.33 add rsp, 8 1 6 0.50 * pop rbx 1 6 0.50 * pop r14 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.98 4.00 5.04 4.00 3.00 Resource pressure by instruction: [0] [1] [2] [3] [4] [5] [6.0] [6.1] Instructions: - - - - 1.00 - - 1.00 push r14 - - - - 1.00 - 1.00 - push rbx - - - - 1.00 - - 1.00 push rax - - 0.94 0.05 - 0.01 - - mov rbx, rcx - - 0.06 0.94 - - - - lea r14, [2*rsi + 5] - - 0.93 0.02 - 0.05 - - and r14, -2 - - 0.05 0.94 - 0.01 - - sub rcx, r14 - - - - - 1.00 - - jb .LBB5_2 - - 0.02 0.04 - 0.94 - - mov rax, rdi - - 0.03 0.97 - - - - add rdx, rcx - - 0.95 0.05 - - - - mov rdi, rdx - - 0.94 0.03 - 0.03 - - mov rsi, rax - - 0.01 0.03 - 0.96 - - mov rdx, r14 - - - - 1.00 1.00 2.00 - call qword ptr [rip + memcpy@GOTPCREL] - - 0.05 0.94 - 0.01 - - cmp rbx, r14 - - 0.97 - - 0.03 - - setae al - - 0.03 0.97 - - - - add rsp, 8 - - - - - - - 1.00 pop rbx - - - - - - 1.00 - pop r14 - - - - - 1.00 - - ret
Implementors
impl IntoBytes for ()impl IntoBytes for AtomicBoolimpl IntoBytes for AtomicI16impl IntoBytes for AtomicI32impl IntoBytes for AtomicI64impl IntoBytes for AtomicI8impl IntoBytes for AtomicIsizeimpl IntoBytes for AtomicU16impl IntoBytes for AtomicU32impl IntoBytes for AtomicU64impl IntoBytes for AtomicU8impl IntoBytes for AtomicUsizeimpl IntoBytes for NonZeroI128impl IntoBytes for NonZeroI16impl IntoBytes for NonZeroI32impl IntoBytes for NonZeroI64impl IntoBytes for NonZeroI8impl IntoBytes for NonZeroIsizeimpl IntoBytes for NonZeroU128impl IntoBytes for NonZeroU16impl IntoBytes for NonZeroU32impl IntoBytes for NonZeroU64impl IntoBytes for NonZeroU8impl IntoBytes for NonZeroUsizeimpl IntoBytes for Option<NonZeroI128>impl IntoBytes for Option<NonZeroI16>impl IntoBytes for Option<NonZeroI32>impl IntoBytes for Option<NonZeroI64>impl IntoBytes for Option<NonZeroI8>impl IntoBytes for Option<NonZeroIsize>impl IntoBytes for Option<NonZeroU128>impl IntoBytes for Option<NonZeroU16>impl IntoBytes for Option<NonZeroU32>impl IntoBytes for Option<NonZeroU64>impl IntoBytes for Option<NonZeroU8>impl IntoBytes for Option<NonZeroUsize>impl IntoBytes for __m128impl IntoBytes for __m128dimpl IntoBytes for __m128iimpl IntoBytes for __m256impl IntoBytes for __m256dimpl IntoBytes for __m256iimpl IntoBytes for __m512impl IntoBytes for __m512bhimpl IntoBytes for __m512dimpl IntoBytes for __m512iimpl IntoBytes for boolimpl IntoBytes for charimpl IntoBytes for f32impl IntoBytes for f64impl IntoBytes for i128impl IntoBytes for i16impl IntoBytes for i32impl IntoBytes for i64impl IntoBytes for i8impl IntoBytes for isizeimpl IntoBytes for strimpl IntoBytes for u128impl IntoBytes for u16impl IntoBytes for u32impl IntoBytes for u64impl IntoBytes for u8impl IntoBytes for usizeimpl<O> IntoBytes for F32<O> where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for F64<O> where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for I128<O> where [u8; 16]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for I16<O> where [u8; 2]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for I32<O> where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for I64<O> where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for Isize<O> where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for U128<O> where [u8; 16]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for U16<O> where [u8; 2]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for U32<O> where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for U64<O> where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,impl<O> IntoBytes for Usize<O> where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,impl<T> IntoBytes for Unalign<T> where T: IntoBytes,impl<T: ?Sized + IntoBytes> IntoBytes for Cell<T>impl<T: ?Sized + IntoBytes> IntoBytes for ManuallyDrop<T>impl<T: ?Sized + IntoBytes> IntoBytes for ReadOnly<T>impl<T: ?Sized + IntoBytes> IntoBytes for UnsafeCell<T>impl<T: ?Sized> IntoBytes for PhantomData<T>impl<T: IntoBytes> IntoBytes for Wrapping<T>impl<T: IntoBytes> IntoBytes for [T]impl<T: IntoBytes, const N: usize> IntoBytes for [T; N]