flatty_base/
traits.rs

1use crate::{emplacer::Emplacer, error::Error, utils::mem::check_align_and_min_size};
2use core::{
3    mem::{align_of, size_of},
4    ptr,
5};
6
7/// Basic flat type properties.
8pub unsafe trait FlatBase: Send + Sync {
9    /// Align of the type.
10    const ALIGN: usize;
11    /// Minimal size of an instance of the type.
12    const MIN_SIZE: usize;
13
14    /// Size of an instance of the type.
15    fn size(&self) -> usize;
16}
17
18/// Dynamically-sized flat type. Like `?Sized` but for `Flat`.
19///
20/// *For now has to be implemented for all [`Flat`] types because there is no mutually exclusive traits in Rust yet.*
21pub unsafe trait FlatUnsized: FlatBase {
22    /// Sized type that has the same alignment as `Self`.
23    type AlignAs: Sized + Send + Sync;
24
25    unsafe fn ptr_from_bytes(bytes: *mut [u8]) -> *mut Self;
26    unsafe fn ptr_to_bytes(this: *mut Self) -> *mut [u8];
27
28    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
29        &*Self::ptr_from_bytes(bytes as *const _ as *mut _)
30    }
31    unsafe fn from_mut_bytes_unchecked(bytes: &mut [u8]) -> &mut Self {
32        &mut *Self::ptr_from_bytes(bytes)
33    }
34    fn as_bytes(&self) -> &[u8] {
35        unsafe { &*Self::ptr_to_bytes(self as *const _ as *mut _) }
36    }
37    /// # Safety
38    ///
39    /// Modification of returned bytes must not make `self` invalid.
40    unsafe fn as_mut_bytes(&mut self) -> &mut [u8] {
41        unsafe { &mut *Self::ptr_to_bytes(self as *mut _) }
42    }
43
44    /// Create a new instance of `Self` initializing raw memory into default state of `Self`.
45    fn new_in_place<I: Emplacer<Self>>(bytes: &mut [u8], emplacer: I) -> Result<&mut Self, Error> {
46        emplacer.emplace(bytes)?;
47        Ok(unsafe { Self::from_mut_bytes_unchecked(bytes) })
48    }
49    fn assign_in_place<I: Emplacer<Self>>(&mut self, emplacer: I) -> Result<&mut Self, Error> {
50        unsafe {
51            let bytes = self.as_mut_bytes();
52            emplacer.emplace_unchecked(bytes)?;
53            Ok(Self::from_mut_bytes_unchecked(bytes))
54        }
55    }
56}
57
58/// Flat type runtime checking.
59pub unsafe trait FlatValidate: FlatUnsized {
60    unsafe fn validate_unchecked(bytes: &[u8]) -> Result<(), Error>;
61
62    unsafe fn validate_ptr(this: *const Self) -> Result<(), Error> {
63        unsafe { Self::validate_unchecked(&*Self::ptr_to_bytes(this as *mut _)) }
64    }
65
66    /// Check that memory contents of `this` is valid for `Self`.
67    fn validate(bytes: &[u8]) -> Result<(), Error> {
68        check_align_and_min_size::<Self>(bytes)?;
69        unsafe { Self::validate_unchecked(bytes) }
70    }
71
72    fn from_bytes(bytes: &[u8]) -> Result<&Self, Error> {
73        Self::validate(bytes)?;
74        Ok(unsafe { Self::from_bytes_unchecked(bytes) })
75    }
76    fn from_mut_bytes(bytes: &mut [u8]) -> Result<&mut Self, Error> {
77        Self::validate(bytes)?;
78        Ok(unsafe { Self::from_mut_bytes_unchecked(bytes) })
79    }
80}
81
82/// Flat type.
83///
84/// *If you want to implement this type for your custom type it's recommended to use safe `#[flat]` attribute macro instead.*
85///
86/// # Safety
87///
88/// By implementing this trait by yourself you guarantee:
89///
90/// + `Self` has stable binary representation that will not change in future.
91///   (But the representation could be differ across different platforms. If you need stronger guarantees consider using `Portable` types.)
92/// + `Self` don't own any resources outside of it.
93/// + `Self` could be trivially copied as bytes. (We cannot require `Self: `[`Copy`] because it `?Sized`.)
94/// + All methods of dependent traits have proper implementation and will not cause an UB.
95pub unsafe trait Flat: FlatBase + FlatUnsized + FlatValidate {}
96
97/// Statically-sized flat type.
98///
99/// # Safety
100///
101/// `SIZE` must match `Self` size.
102pub unsafe trait FlatSized: FlatUnsized + Sized {
103    /// Static size of the type.
104    const SIZE: usize = size_of::<Self>();
105}
106
107unsafe impl<T: Flat> FlatSized for T {}
108
109unsafe impl<T: FlatSized> FlatBase for T {
110    const ALIGN: usize = align_of::<Self>();
111
112    const MIN_SIZE: usize = Self::SIZE;
113
114    fn size(&self) -> usize {
115        Self::SIZE
116    }
117}
118
119unsafe impl<T: FlatSized> FlatUnsized for T {
120    type AlignAs = T;
121
122    unsafe fn ptr_from_bytes(bytes: *mut [u8]) -> *mut Self {
123        bytes as *mut Self
124    }
125    unsafe fn ptr_to_bytes(this: *mut Self) -> *mut [u8] {
126        ptr::slice_from_raw_parts_mut(this as *mut u8, Self::SIZE)
127    }
128}
129
130/// Flat types that can be initialized to default state.
131///
132/// # Safety
133///
134/// Methods must properly initialize memory.
135pub trait FlatDefault: Flat {
136    type DefaultEmplacer: Emplacer<Self>;
137
138    /// Initialize uninitialized memory into valid default state.
139    ///
140    /// This method returned `Ok` must guaratee that `this` could be safely transmuted to `Self`.
141    fn default_emplacer() -> Self::DefaultEmplacer;
142
143    /// Create a new instance of `Self` initializing raw memory into default state of `Self`.
144    fn default_in_place(bytes: &mut [u8]) -> Result<&mut Self, Error> {
145        Self::new_in_place(bytes, Self::default_emplacer())
146    }
147}
148
149impl<T: Flat + Default> FlatDefault for T {
150    type DefaultEmplacer = Self;
151
152    fn default_emplacer() -> Self::DefaultEmplacer {
153        Self::default()
154    }
155}