ab_io_type/
trivial_type.rs

1use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
2use crate::unaligned::Unaligned;
3use crate::{DerefWrapper, IoType};
4pub use ab_trivial_type_derive::TrivialType;
5use core::ops::{Deref, DerefMut};
6use core::ptr;
7use core::ptr::NonNull;
8
9/// Simple wrapper data type that is designed in such a way that its serialization/deserialization
10/// is the same as the type itself.
11///
12/// # Safety
13/// This trait is used for types with memory layout that can be treated as bytes. It must not be
14/// relied on with untrusted data (it can be constructed from bytes, and internal invariants might
15/// not be invalid). Serializing and deserializing of types that implement this trait is simply
16/// casting of underlying memory. As a result, all the types implementing this trait must not use
17/// implicit padding, unions or anything similar that might make it unsound to access any bits of
18/// the type.
19///
20/// Helper functions are provided to make casting to/from bytes a bit safer than it would otherwise,
21/// but extra care is still needed.
22///
23/// **Do not implement this trait explicitly!** Use `#[derive(TrivialType)]` instead, which will
24/// ensure safety requirements are upheld.
25pub unsafe trait TrivialType
26where
27    Self: Copy,
28{
29    const SIZE: u32 = size_of::<Self>() as u32;
30    /// Data structure metadata in binary form, describing shape and types of the contents, see
31    /// [`IoTypeMetadataKind`] for encoding details.
32    const METADATA: &[u8];
33
34    /// Read unaligned value from memory.
35    ///
36    /// Returns `None` if the number of input bytes is not sufficient to represent the type.
37    ///
38    /// # Safety
39    /// Input bytes must be previously produced by taking underlying bytes of the same type, or else
40    /// the data structure might have unexpected contents. While technically not unsafe, this API
41    /// should be used very carefully and data structure invariants need to be checked manually.
42    #[inline(always)]
43    unsafe fn read_unaligned(bytes: &[u8]) -> Option<Self> {
44        // SAFETY: Guaranteed by function contract
45        Some(unsafe { Unaligned::<Self>::from_bytes(bytes)?.as_inner() })
46    }
47
48    /// Similar to [`Self::read_unaligned()`], but doesn't do any checks at all.
49    ///
50    /// # Safety
51    /// The number of bytes must be at least as big as the type itself.
52    #[inline(always)]
53    unsafe fn read_unaligned_unchecked(bytes: &[u8]) -> Self {
54        // SAFETY: Guaranteed by function contract
55        unsafe { Unaligned::<Self>::from_bytes_unchecked(bytes).as_inner() }
56    }
57
58    /// Create a reference to a type, which is represented by provided memory.
59    ///
60    /// Memory must be correctly aligned, or else `None` will be returned. Size must be sufficient,
61    /// padding beyond the size of the type is allowed.
62    ///
63    /// # Safety
64    /// Input bytes must be previously produced by taking underlying bytes of the same type, or else
65    /// the data structure might have unexpected contents. While technically not unsafe, this API
66    /// should be used very carefully and data structure invariants need to be checked manually.
67    #[inline(always)]
68    unsafe fn from_bytes(bytes: &[u8]) -> Option<&Self> {
69        // SAFETY: For trivial types all bit patterns are valid
70        let (before, slice, _) = unsafe { bytes.align_to::<Self>() };
71
72        before.is_empty().then(|| slice.first()).flatten()
73    }
74
75    /// Similar to [`Self::from_bytes()`], but doesn't do any checks at all.
76    ///
77    /// # Safety
78    /// Size is at least as big as the type itself, and alignment is correct.
79    #[inline(always)]
80    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
81        // SAFETY: Guaranteed by function contract
82        unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() }
83    }
84
85    /// Create a mutable reference to a type, which is represented by provided memory.
86    ///
87    /// Memory must be correctly aligned, or else `None` will be returned. Size must be sufficient,
88    /// padding beyond the size of the type is allowed.
89    ///
90    /// # Safety
91    /// Input bytes must be previously produced by taking underlying bytes of the same type, or else
92    /// the data structure might have unexpected contents. While technically not unsafe, this API
93    /// should be used very carefully and data structure invariants need to be checked manually.
94    #[inline(always)]
95    unsafe fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self> {
96        // SAFETY: For trivial types all bit patterns are valid
97        let (before, slice, _) = unsafe { bytes.align_to_mut::<Self>() };
98
99        before.is_empty().then(|| slice.first_mut()).flatten()
100    }
101
102    /// Similar to [`Self::from_bytes_mut()`], but doesn't do any checks at all.
103    ///
104    /// # Safety
105    /// Size is at least as big as the type itself, and alignment is correct.
106    #[inline(always)]
107    unsafe fn from_bytes_mut_unchecked(bytes: &mut [u8]) -> &mut Self {
108        // SAFETY: Guaranteed by function contract
109        unsafe { bytes.as_mut_ptr().cast::<Self>().as_mut_unchecked() }
110    }
111
112    /// Access the underlying byte representation of a data structure
113    #[inline(always)]
114    fn as_bytes(&self) -> &[u8; size_of::<Self>()] {
115        // SAFETY: All bits are valid for reading as bytes, see `TrivialType` description
116        unsafe { ptr::from_ref(self).cast::<[u8; _]>().as_ref_unchecked() }
117    }
118
119    /// Access the underlying mutable byte representation of a data structure.
120    ///
121    /// # Safety
122    /// While calling this function is technically safe, modifying returned memory buffer may result
123    /// in broken invariants of underlying data structure and should be done with extra care.
124    #[inline(always)]
125    unsafe fn as_bytes_mut(&mut self) -> &mut [u8; size_of::<Self>()] {
126        // SAFETY: All bits are valid for reading as bytes, see `TrivialType` description
127        unsafe { ptr::from_mut(self).cast::<[u8; _]>().as_mut_unchecked() }
128    }
129}
130
131// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
132unsafe impl TrivialType for () {
133    const METADATA: &[u8] = &[IoTypeMetadataKind::Unit as u8];
134}
135// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
136unsafe impl TrivialType for u8 {
137    const METADATA: &[u8] = &[IoTypeMetadataKind::U8 as u8];
138}
139// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
140unsafe impl TrivialType for u16 {
141    const METADATA: &[u8] = &[IoTypeMetadataKind::U16 as u8];
142}
143// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
144unsafe impl TrivialType for u32 {
145    const METADATA: &[u8] = &[IoTypeMetadataKind::U32 as u8];
146}
147// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
148unsafe impl TrivialType for u64 {
149    const METADATA: &[u8] = &[IoTypeMetadataKind::U64 as u8];
150}
151// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
152unsafe impl TrivialType for u128 {
153    const METADATA: &[u8] = &[IoTypeMetadataKind::U128 as u8];
154}
155// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
156unsafe impl TrivialType for i8 {
157    const METADATA: &[u8] = &[IoTypeMetadataKind::I8 as u8];
158}
159// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
160unsafe impl TrivialType for i16 {
161    const METADATA: &[u8] = &[IoTypeMetadataKind::I16 as u8];
162}
163// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
164unsafe impl TrivialType for i32 {
165    const METADATA: &[u8] = &[IoTypeMetadataKind::I32 as u8];
166}
167// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
168unsafe impl TrivialType for i64 {
169    const METADATA: &[u8] = &[IoTypeMetadataKind::I64 as u8];
170}
171// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
172unsafe impl TrivialType for i128 {
173    const METADATA: &[u8] = &[IoTypeMetadataKind::I128 as u8];
174}
175
176const fn array_metadata(size: u32, inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
177    if inner_metadata.len() == 1 && inner_metadata[0] == IoTypeMetadataKind::U8 as u8 {
178        if size == 8 {
179            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x8 as u8]]);
180        } else if size == 16 {
181            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x16 as u8]]);
182        } else if size == 32 {
183            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x32 as u8]]);
184        } else if size == 64 {
185            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x64 as u8]]);
186        } else if size == 128 {
187            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x128 as u8]]);
188        } else if size == 256 {
189            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x256 as u8]]);
190        } else if size == 512 {
191            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x512 as u8]]);
192        } else if size == 1024 {
193            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x1024 as u8]]);
194        } else if size == 2028 {
195            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x2028 as u8]]);
196        } else if size == 4096 {
197            return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x4096 as u8]]);
198        }
199    }
200
201    let (io_type, size_bytes) = if size < 2u32.pow(8) {
202        (IoTypeMetadataKind::Array8b, 1)
203    } else if size < 2u32.pow(16) {
204        (IoTypeMetadataKind::Array16b, 2)
205    } else {
206        (IoTypeMetadataKind::Array32b, 4)
207    };
208
209    concat_metadata_sources(&[
210        &[io_type as u8],
211        size.to_le_bytes().split_at(size_bytes).0,
212        inner_metadata,
213    ])
214}
215
216// TODO: Change `usize` to `u32` once stabilized `generic_const_exprs` feature allows us to do
217//  `SIZE as usize`
218// SAFETY: Any bit pattern is valid, so it is safe to implement `TrivialType` for this type
219unsafe impl<const SIZE: usize, T> TrivialType for [T; SIZE]
220where
221    T: TrivialType,
222{
223    const METADATA: &[u8] = {
224        // Strange syntax to allow Rust to extend the lifetime of metadata scratch automatically
225        array_metadata(SIZE as u32, T::METADATA)
226            .0
227            .split_at(array_metadata(SIZE as u32, T::METADATA).1)
228            .0
229    };
230}
231
232// SAFETY: All `TrivialType` instances are valid for `IoType`
233unsafe impl<T> IoType for T
234where
235    T: TrivialType,
236{
237    const METADATA: &[u8] = T::METADATA;
238
239    type PointerType = T;
240
241    #[inline(always)]
242    fn size(&self) -> u32 {
243        size_of::<T>() as u32
244    }
245
246    #[inline(always)]
247    fn capacity(&self) -> u32 {
248        self.size()
249    }
250
251    #[inline(always)]
252    #[track_caller]
253    unsafe fn set_size(&mut self, size: u32) {
254        debug_assert_eq!(size, T::SIZE, "`set_size` called with invalid input");
255    }
256
257    #[inline(always)]
258    #[track_caller]
259    unsafe fn from_ptr<'a>(
260        ptr: &'a NonNull<Self::PointerType>,
261        size: &'a u32,
262        capacity: u32,
263    ) -> impl Deref<Target = Self> + 'a {
264        debug_assert!(ptr.is_aligned(), "Misaligned pointer");
265        debug_assert_eq!(*size, T::SIZE, "Invalid size");
266        debug_assert!(
267            *size <= capacity,
268            "Size {size} must not exceed capacity {capacity}"
269        );
270
271        // SAFETY: guaranteed by this function signature
272        unsafe { ptr.as_ref() }
273    }
274
275    #[inline(always)]
276    #[track_caller]
277    unsafe fn from_mut_ptr<'a>(
278        ptr: &'a mut NonNull<Self::PointerType>,
279        _size: &'a mut u32,
280        capacity: u32,
281    ) -> impl DerefMut<Target = Self> + 'a {
282        debug_assert!(ptr.is_aligned(), "Misaligned pointer");
283        debug_assert!(
284            Self::SIZE <= capacity,
285            "Size {} must not exceed capacity {capacity}",
286            Self::SIZE
287        );
288
289        // SAFETY: guaranteed by this function signature
290        unsafe { ptr.as_mut() }
291    }
292
293    #[inline(always)]
294    unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>> {
295        DerefWrapper(NonNull::from_ref(self))
296    }
297
298    #[inline(always)]
299    unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>> {
300        DerefWrapper(NonNull::from_mut(self))
301    }
302}