Skip to main content

IntoBytes

Trait IntoBytes 

Source
pub unsafe trait IntoBytes {
    // Provided methods
    fn as_bytes(&self) -> &[u8]
       where Self: Immutable { ... }
    fn as_mut_bytes(&mut self) -> &mut [u8]
       where Self: FromBytes { ... }
    fn write_to(
        &self,
        dst: &mut [u8],
    ) -> Result<(), SizeError<&Self, &mut [u8]>>
       where Self: Immutable { ... }
    fn write_to_prefix(
        &self,
        dst: &mut [u8],
    ) -> Result<(), SizeError<&Self, &mut [u8]>>
       where Self: Immutable { ... }
    fn write_to_suffix(
        &self,
        dst: &mut [u8],
    ) -> Result<(), SizeError<&Self, &mut [u8]>>
       where Self: Immutable { ... }
}
Expand description

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.:

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

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

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§

Source

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

Gets the bytes of this value.

§Examples
use zerocopy::IntoBytes;

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

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

let bytes = header.as_bytes();

assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
§ 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
   ret
Machine 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    -      -     ret
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
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
   ret
Machine 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    -      -     ret
Source

fn as_mut_bytes(&mut self) -> &mut [u8]
where Self: FromBytes,

Gets the bytes of this value mutably.

§Examples
use zerocopy::IntoBytes;

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

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

let bytes = header.as_mut_bytes();

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

bytes.reverse();

assert_eq!(header, PacketHeader {
    src_port: [7, 6],
    dst_port: [5, 4],
    length: [3, 2],
    checksum: [1, 0],
});
§ Code Generation

See IntoBytes::as_bytes.

Source

fn write_to(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>>
where Self: Immutable,

Writes a copy of self to dst.

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

§Examples
use zerocopy::IntoBytes;

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

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

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

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

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

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

let mut excessive_bytes = &mut [0u8; 128][..];

let write_result = header.write_to(excessive_bytes);

assert!(write_result.is_err());
assert_eq!(excessive_bytes, [0u8; 128]);
§ 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
   ret
Machine 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    -      -     ret
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
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
   ret
Machine 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    -      -     ret
Source

fn write_to_prefix( &self, dst: &mut [u8], ) -> Result<(), SizeError<&Self, &mut [u8]>>
where Self: Immutable,

Writes a copy of self to the prefix of dst.

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

§Examples
use zerocopy::IntoBytes;

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

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

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

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

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

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

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

let write_result = header.write_to_suffix(insufficient_bytes);

assert!(write_result.is_err());
assert_eq!(insufficient_bytes, [0, 0]);
§ 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
   ret
Machine 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    -      -     ret
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
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
   ret
Machine 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    -      -     ret
Source

fn write_to_suffix( &self, dst: &mut [u8], ) -> Result<(), SizeError<&Self, &mut [u8]>>
where Self: Immutable,

Writes a copy of self to the suffix of dst.

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

§Examples
use zerocopy::IntoBytes;

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

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

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

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

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

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

let write_result = header.write_to_suffix(insufficient_bytes);

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

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

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

let write_result = header.write_to_suffix(insufficient_bytes);

assert!(write_result.is_err());
assert_eq!(insufficient_bytes, [0, 0]);
§ 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
   ret
Machine 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    -      -     ret
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
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
   ret
Machine 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

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl IntoBytes for ()

Source§

impl IntoBytes for AtomicBool

Source§

impl IntoBytes for AtomicI8

Source§

impl IntoBytes for AtomicI16

Source§

impl IntoBytes for AtomicI32

Source§

impl IntoBytes for AtomicI64

Source§

impl IntoBytes for AtomicIsize

Source§

impl IntoBytes for AtomicU8

Source§

impl IntoBytes for AtomicU16

Source§

impl IntoBytes for AtomicU32

Source§

impl IntoBytes for AtomicU64

Source§

impl IntoBytes for AtomicUsize

Source§

impl IntoBytes for NonZeroI8

Source§

impl IntoBytes for NonZeroI16

Source§

impl IntoBytes for NonZeroI32

Source§

impl IntoBytes for NonZeroI64

Source§

impl IntoBytes for NonZeroI128

Source§

impl IntoBytes for NonZeroIsize

Source§

impl IntoBytes for NonZeroU8

Source§

impl IntoBytes for NonZeroU16

Source§

impl IntoBytes for NonZeroU32

Source§

impl IntoBytes for NonZeroU64

Source§

impl IntoBytes for NonZeroU128

Source§

impl IntoBytes for NonZeroUsize

Source§

impl IntoBytes for Option<NonZeroI8>

Source§

impl IntoBytes for Option<NonZeroI16>

Source§

impl IntoBytes for Option<NonZeroI32>

Source§

impl IntoBytes for Option<NonZeroI64>

Source§

impl IntoBytes for Option<NonZeroI128>

Source§

impl IntoBytes for Option<NonZeroIsize>

Source§

impl IntoBytes for Option<NonZeroU8>

Source§

impl IntoBytes for Option<NonZeroU16>

Source§

impl IntoBytes for Option<NonZeroU32>

Source§

impl IntoBytes for Option<NonZeroU64>

Source§

impl IntoBytes for Option<NonZeroU128>

Source§

impl IntoBytes for Option<NonZeroUsize>

Source§

impl IntoBytes for bool

Source§

impl IntoBytes for char

Source§

impl IntoBytes for f32

Source§

impl IntoBytes for f64

Source§

impl IntoBytes for i8

Source§

impl IntoBytes for i16

Source§

impl IntoBytes for i32

Source§

impl IntoBytes for i64

Source§

impl IntoBytes for i128

Source§

impl IntoBytes for isize

Source§

impl IntoBytes for str

Source§

impl IntoBytes for u8

Source§

impl IntoBytes for u16

Source§

impl IntoBytes for u32

Source§

impl IntoBytes for u64

Source§

impl IntoBytes for u128

Source§

impl IntoBytes for usize

Source§

impl<T: IntoBytes> IntoBytes for Wrapping<T>

Source§

impl<T: IntoBytes> IntoBytes for [T]

Source§

impl<T: IntoBytes, const N: usize> IntoBytes for [T; N]

Source§

impl<T: ?Sized + IntoBytes> IntoBytes for Cell<T>

Source§

impl<T: ?Sized + IntoBytes> IntoBytes for ManuallyDrop<T>

Source§

impl<T: ?Sized + IntoBytes> IntoBytes for UnsafeCell<T>

Source§

impl<T: ?Sized> IntoBytes for PhantomData<T>

Implementors§

Source§

impl<O> IntoBytes for F32<O>
where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for F64<O>
where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for I16<O>
where [u8; 2]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for I32<O>
where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for I64<O>
where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for I128<O>
where [u8; 16]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for Isize<O>
where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for U16<O>
where [u8; 2]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for U32<O>
where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for U64<O>
where [u8; 8]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for U128<O>
where [u8; 16]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<O> IntoBytes for Usize<O>
where [u8; 4]: IntoBytes, PhantomData<O>: IntoBytes,

Source§

impl<T> IntoBytes for Unalign<T>
where T: IntoBytes,