safe_bytes/lib.rs
1//! This crate allows reading bytes representation of structs
2//! even in presence of padding bytes.
3//!
4//! [](https://crates.io/crates/safe-bytes)
5//! [](https://docs.rs/safe-bytes)
6//! [](LICENSE-MIT)
7//! [](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}