bytes_cast/
lib.rs

1//! Utilities for safely re-interpreting `&[u8]` bytes as custom structs
2//! and back without copying, for efficiently reading structured binary data.
3//!
4//! # Example
5//!
6//! Reading bytes:
7//!
8//! ```
9//! use bytes_cast::{BytesCast, unaligned};
10//!
11//! #[derive(BytesCast)]
12//! #[repr(C)]
13//! struct Foo {
14//!     bar: [u8; 2],
15//!     baz: unaligned::U32Be,
16//! }
17//!
18//! let input = &[1_u8, 2, 3, 4, 5, 6, 7, 8];
19//!
20//! let (foo, rest) = Foo::from_bytes(input).unwrap();
21//! assert_eq!(foo.bar, [1_u8, 2]);
22//! assert_eq!(foo.baz.get(), 0x0304_0506_u32);
23//! assert_eq!(rest, &[7_u8, 8]);
24//!
25//! assert!(<[Foo; 2]>::from_bytes(input).is_err()); // input is too short
26//!
27//! let (values, rest) = unaligned::U16Le::slice_from_bytes(input, 2).unwrap();
28//! assert_eq!(values.len(), 2);
29//! assert_eq!(values[0].get(), 0x02_01_u16);
30//! assert_eq!(values[1].get(), 0x04_03_u16);
31//! assert_eq!(rest, &[5_u8, 6, 7, 8]);
32//!
33//! assert!(unaligned::U16Le::slice_from_bytes(input, 5).is_err()); // input is too short
34//! ```
35//!
36//! Writing bytes:
37//!
38//! ```
39//! # use bytes_cast::{BytesCast, unaligned};
40//! # #[derive(BytesCast)]
41//! # #[repr(C)]
42//! # struct Foo {
43//! #     bar: [u8; 2],
44//! #     baz: unaligned::U32Be,
45//! # }
46//!
47//! let foo = Foo { bar: [1, 2], baz: 0x0304_0506.into() };
48//! assert_eq!(foo.as_bytes(), &[1_u8, 2, 3, 4, 5, 6]);
49//!
50//! let slice: &[unaligned::U16Le] = &[0x02_01.into(), 0x04_03.into()];
51//! assert_eq!(slice.as_bytes(), &[1_u8, 2, 3, 4]);
52//! ```
53
54#![no_std]
55
56pub use bytes_cast_derive::BytesCast;
57use core::fmt;
58use core::mem;
59use core::slice;
60
61pub mod unaligned;
62
63#[cfg(doctest)]
64mod compile_fail_tests;
65
66/// Marks a type as safe to interpret from and to bytes without copying.
67///
68/// # Safety
69///
70/// For a type to implement this trait:
71///
72/// * All initialized bit patterns must be valid. (This excludes `bool`, enums, etc.)
73/// * There must not be an alignment requirement. (`align_of() == 1`)
74/// * There must be no padding or otherwise uninitialized bytes
75///
76/// # Deriving
77///
78/// Instead of writing `unsafe impl` blocks this trait should be derived.
79/// `#[derive(BytesCast)]` on a type definition invokes a procedural macro
80/// that implements the trait after checking that the type:
81///
82/// * Is a `struct`
83/// * Is not generic
84/// * Has a `#[repr(C)]` or `#[repr(transparent)]` attribute
85/// * Has `align_of() == 1`
86/// * Only has fields whose respective type implement `BytesCast`.
87///
88/// Failing any of these checks causes a compile-time error.
89/// This excludes some types that could implement `BytesCast` without memory safety
90/// issue:
91///
92/// * By choice: disabling field reordering with `repr` is not about memory
93///   safety but making memory layout / field offsets predictable.
94/// * By necessity: generics would make `align_of` potentially depend on type
95///   parameters and not possible to statically check at the struct definition
96///   site.
97pub unsafe trait BytesCast {
98    /// Interpret the start of the given slice of bytes as reference to this
99    /// type.
100    ///
101    /// If the given input is large enough, returns a tuple of the new
102    /// reference and the remaining of the bytes.
103    #[inline]
104    fn from_bytes(bytes: &[u8]) -> Result<(&Self, &[u8]), FromBytesError>
105    where
106        Self: Sized,
107    {
108        let expected_len = mem::size_of::<Self>();
109        remaining_bytes(bytes, expected_len).map(|rest| {
110            // Safety: this cast and dereference are made sound by the length
111            // check done in `remaining_bytes` together with the
112            // invariants of `BytesCast`.
113            let this = unsafe { &*bytes.as_ptr().cast::<Self>() };
114            (this, rest)
115        })
116    }
117
118    /// Interpret the start of the given slice of bytes as slice of this type.
119    ///
120    /// If the given input is large enough, returns a tuple of the new
121    /// slice and the remaining of the bytes.
122    #[inline]
123    fn slice_from_bytes(bytes: &[u8], slice_len: usize) -> Result<(&[Self], &[u8]), FromBytesError>
124    where
125        Self: Sized,
126    {
127        let expected_byte_len =
128            mem::size_of::<Self>()
129                .checked_mul(slice_len)
130                .ok_or(FromBytesError {
131                    input_len: bytes.len(),
132                    expected_len: None,
133                })?;
134        remaining_bytes(bytes, expected_byte_len).map(|rest| {
135            // Safety: this cast and call are made sound by the length check
136            // done in `remaining_bytes` together with the invariants of
137            // `BytesCast`.
138            let this = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<Self>(), slice_len) };
139            (this, rest)
140        })
141    }
142
143    /// Interpret this value as the bytes of its memory representation.
144    #[inline]
145    fn as_bytes(&self) -> &[u8] {
146        let ptr: *const Self = self;
147        let bytes_ptr = ptr.cast::<u8>();
148        let bytes_len = mem::size_of_val(self);
149        // Safety: the invariants of `BytesCast` make this sound by definition:
150        unsafe { slice::from_raw_parts(bytes_ptr, bytes_len) }
151    }
152}
153
154/// If the given slice is long enough, return the the remaining bytes after the
155/// given length.
156#[inline]
157fn remaining_bytes(bytes: &[u8], expected_byte_len: usize) -> Result<&[u8], FromBytesError> {
158    bytes.get(expected_byte_len..).ok_or(FromBytesError {
159        input_len: bytes.len(),
160        expected_len: Some(expected_byte_len),
161    })
162}
163
164/// The error type for [`BytesCast::from_bytes`] and
165/// [`BytesCast::slice_from_bytes`].
166pub struct FromBytesError {
167    expected_len: Option<usize>,
168    input_len: usize,
169}
170
171impl fmt::Display for FromBytesError {
172    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173        if let Some(expected_len) = self.expected_len {
174            write!(
175                f,
176                "Expected at least {} bytes, got {}",
177                expected_len, self.input_len
178            )
179        } else {
180            write!(f, "Expected byte size overflowed in slice_from_bytes")
181        }
182    }
183}
184
185impl fmt::Debug for FromBytesError {
186    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187        fmt::Display::fmt(self, f)
188    }
189}
190
191unsafe impl<T: ?Sized> BytesCast for core::marker::PhantomData<T> {}
192unsafe impl<T: BytesCast> BytesCast for [T] {}
193unsafe impl BytesCast for () {}
194unsafe impl BytesCast for u8 {}
195
196// NOTE: We don’t implement BytesCast for tuples with 2 or more fields
197// because they are subject to field reordering.
198// Like with default-`repr` structs this is not a memory safety issue but still
199// a footgun. Single-field tuples don’t have that problem but are much less
200// useful in the first place.
201
202// FIXME: Use const generics when we require Rust 1.51+
203macro_rules! array_impls {
204    ($($N: expr)+) => {
205        $(
206            unsafe impl<T: BytesCast> BytesCast for [T; $N] {}
207        )+
208    };
209}
210
211array_impls!(
212    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
213    17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
214);