safe_bytes/
lib.rs

1//! This crate allows reading bytes representation of structs
2//! even in presence of padding bytes.
3//!
4//! [![crates](https://img.shields.io/crates/v/safe-bytes.svg?label=safe-bytes)](https://crates.io/crates/safe-bytes)
5//! [![docs](https://docs.rs/safe-bytes/badge.svg)](https://docs.rs/safe-bytes)
6//! [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
7//! [![License](https://img.shields.io/badge/license-APACHE-blue.svg)](LICENSE-APACHE)
8//!
9//! Simply derive [`SafeBytes`] for structures
10//! where all field types are [`SafeBytes`] implementations.
11//! And [`SafeBytes::safe_bytes`] would initialize all padding bytes
12//! before returning `&[u8]`.
13//! All primitives implement [`SafeBytes`] as there is no padding bytes.
14//! Additionally some std types implement [`SafeBytes`].
15//!
16//! Note that in order to initialize padding bytes
17//! [`SafeBytes::safe_bytes`] takes mutable reference `&mut self`.
18//! And returns shareable reference `&[u8]` because not all
19//! bitpatterns may be allowed for the type.
20//!
21//! [`SafeBytes`]: ./trait.SafeBytes.html
22//! [`SafeBytes::safe_bytes`]: ./trait.SafeBytes.html#tymethod.safe_bytes
23
24#![no_std]
25
26mod pod;
27
28use core::{
29    mem::{size_of, size_of_val, ManuallyDrop, MaybeUninit},
30    num::Wrapping,
31    slice::{from_raw_parts, from_raw_parts_mut},
32};
33
34pub use safe_bytes_derive::SafeBytes;
35
36#[doc(hidden)]
37pub use core;
38
39/// Creates [`TypeField`] for fieled of the given instance.
40/// Can be used to implement [`PaddingBane::get_fields`].
41///
42/// [`TypeField`]: ./struct.TypedField.html
43/// [`PaddingBane::get_fields`]: ./trait.PaddingBane.html#tymethod.get_fields
44#[macro_export]
45macro_rules! typed_field {
46    ($instance:expr, $type:path, $field:ident) => {{
47        let reference: &$type = &$instance;
48        let $type {
49            $field: field_reference,
50            ..
51        } = reference;
52        let base_address = reference as *const _ as usize;
53        let field_size = $crate::core::mem::size_of_val(field_reference);
54        let field_address = field_reference as *const _ as usize;
55        let field_offset = field_address.checked_sub(base_address).unwrap();
56        let field_sub = $crate::PaddingBane::get_fields(field_reference);
57
58        TypedField {
59            raw: $crate::Field {
60                offset: field_offset,
61                size: field_size,
62            },
63            sub: field_sub,
64        }
65    }};
66}
67
68/// Trait for types that can initialize their padding in
69/// their bytes representation.
70///
71/// # Safety
72///
73/// This trait's implementation *should* be able to produce initialized
74/// bytes slice that contain original structure raw
75/// representation.
76/// It is safe to implement it in wrong way.
77/// But it is advised to derive [`SafeBytes`] if possible.
78/// Or implement [`PaddingBane`] instead if deriving is not possible,
79/// as [`SafeBytes`] has blanket implementation for [`PaddingBane`] implementors.
80///
81/// [`SafeBytes`]: ./trait.SafeBytes.html
82/// [`PaddingBane`]: ./trait.PaddingBane.html
83pub trait SafeBytes {
84    /// Returns bytes representation of the value,
85    /// initializing all padding bytes
86    fn safe_bytes(&mut self) -> &[u8];
87}
88
89/// This trait must be implemented in order to fill padding bytes of an object.
90pub unsafe trait PaddingBane {
91    /// Metadata about type's fields.
92    type Fields: Copy;
93
94    /// Return fields metadata.
95    ///
96    /// # Safety
97    ///
98    /// This function must return equal value for any instance of the `Self` type.
99    /// It exists only because reference to instance is required to
100    /// fetch field offsets.
101    fn get_fields(&self) -> Self::Fields;
102
103    /// Fills padding bytes in the bytes array.
104    /// Padding bytes are bytes where no fields of the struct are stored
105    /// or padding bytes of the fields.
106    ///
107    /// # Safety
108    ///
109    /// `fields` must be created from any instance of `Self`.
110    /// `bytes` must be created by casting `&mut Self` or, for a field,
111    /// it must be subslice of the parent's bytes where field is stored.
112    unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]);
113}
114
115impl<T> SafeBytes for T
116where
117    T: PaddingBane,
118{
119    #[inline]
120    fn safe_bytes(&mut self) -> &[u8] {
121        let fields = self.get_fields();
122        unsafe {
123            let bytes = maybe_init_bytes_of(self);
124            Self::init_padding(fields, bytes);
125            assume_slice_init(&*bytes)
126        }
127    }
128}
129
130impl<T> SafeBytes for [T]
131where
132    T: PaddingBane,
133{
134    fn safe_bytes(&mut self) -> &[u8] {
135        if self.is_empty() {
136            &[]
137        } else {
138            let fields = self[0].get_fields();
139            let len = self.len();
140            unsafe {
141                let bytes = maybe_init_bytes_of(self);
142                for i in 0..len {
143                    let start = i * size_of::<T>();
144                    let end = start + size_of::<T>();
145                    T::init_padding(fields, &mut bytes[start..end]);
146                }
147                assume_slice_init(&*bytes)
148            }
149        }
150    }
151}
152
153macro_rules! impl_for_array {
154    ($N:tt) => {
155        unsafe impl<T> PaddingBane for [T; $N]
156        where
157            T: PaddingBane,
158        {
159            type Fields = T::Fields;
160            #[inline(always)]
161            fn get_fields(&self) -> T::Fields {
162                self[0].get_fields()
163            }
164
165            #[inline(always)]
166            unsafe fn init_padding(fields: T::Fields, bytes: &mut [MaybeUninit<u8>]) {
167                for i in 0 .. $N {
168                    let start = i * size_of::<T>();
169                    let end = start + size_of::<T>();
170                    T::init_padding(fields, &mut bytes[start..end]);
171                }
172            }
173        }
174    };
175
176    ($($N:tt)*) => {
177        $(impl_for_array!($N);)*
178    };
179}
180
181impl_for_array! {
182    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
183    48 64 96 128 256 512 1024 2048 4096 8192 16384 32768 65536
184}
185
186unsafe impl<T> PaddingBane for ManuallyDrop<T>
187where
188    T: PaddingBane,
189{
190    type Fields = T::Fields;
191
192    #[inline(always)]
193    fn get_fields(&self) -> Self::Fields {
194        (&**self).get_fields()
195    }
196
197    #[inline(always)]
198    unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]) {
199        T::init_padding(fields, bytes);
200    }
201}
202
203unsafe impl<T> PaddingBane for Wrapping<T>
204where
205    T: PaddingBane,
206{
207    type Fields = T::Fields;
208
209    #[inline(always)]
210    fn get_fields(&self) -> Self::Fields {
211        self.0.get_fields()
212    }
213
214    #[inline(always)]
215    unsafe fn init_padding(fields: Self::Fields, bytes: &mut [MaybeUninit<u8>]) {
216        T::init_padding(fields, bytes);
217    }
218}
219
220/// Basic field information.
221/// Enough to fill padding bytes between fields.
222#[derive(Clone, Copy)]
223pub struct Field {
224    pub offset: usize,
225    pub size: usize,
226}
227
228/// Field information.
229/// Enough to fill padding bytes between fields and
230/// inside the fields.
231#[derive(Clone, Copy)]
232pub struct TypedField<T: PaddingBane> {
233    pub raw: Field,
234    pub sub: T::Fields,
235}
236
237/// Returns maybe uninitialized bytes of the value.
238/// Intended for initializing padding bytes.
239///
240/// # Safety
241///
242/// Returned bytes reference must not be used to create invalid bit pattern.
243unsafe fn maybe_init_bytes_of<T: ?Sized>(r: &mut T) -> &mut [MaybeUninit<u8>] {
244    from_raw_parts_mut(r as *mut T as *mut MaybeUninit<u8>, size_of_val(r))
245}
246
247/// Assume all elements of the slice are initialized.
248///
249/// # Safety
250///
251/// All elements of the slice must be initialized.
252unsafe fn assume_slice_init<T>(slice: &[MaybeUninit<T>]) -> &[T] {
253    from_raw_parts(slice.as_ptr() as *const T, size_of_val(slice))
254}