ab_io_type/
maybe_data.rs

1use crate::trivial_type::TrivialType;
2use crate::{DerefWrapper, IoType, IoTypeOptional};
3use core::mem::MaybeUninit;
4use core::ops::{Deref, DerefMut};
5use core::ptr::NonNull;
6
7/// Wrapper type for `Data` that may or may not be filled with contents.
8///
9/// This is somewhat similar to [`VariableBytes`](crate::variable_bytes::VariableBytes), but instead
10/// of variable size, data structure allows either having it or not having the contents, which is a
11/// simpler and more convenient API that is also sufficient in many cases.
12#[derive(Debug)]
13pub struct MaybeData<Data>
14where
15    Data: TrivialType,
16{
17    data: NonNull<Data>,
18    size: NonNull<u32>,
19}
20
21// SAFETY: Low-level (effectively internal) implementation that upholds safety requirements
22unsafe impl<Data> IoType for MaybeData<Data>
23where
24    Data: TrivialType,
25{
26    const METADATA: &[u8] = Data::METADATA;
27
28    type PointerType = Data;
29
30    #[inline(always)]
31    fn size(&self) -> u32 {
32        // SAFETY: guaranteed to be initialized by constructors
33        unsafe { self.size.read() }
34    }
35
36    #[inline(always)]
37    unsafe fn size_ptr(&self) -> impl Deref<Target = NonNull<u32>> {
38        DerefWrapper(self.size)
39    }
40
41    #[inline(always)]
42    unsafe fn size_mut_ptr(&mut self) -> impl DerefMut<Target = *mut u32> {
43        DerefWrapper(self.size.as_ptr())
44    }
45
46    #[inline(always)]
47    fn capacity(&self) -> u32 {
48        Data::SIZE
49    }
50
51    #[inline(always)]
52    unsafe fn capacity_ptr(&self) -> impl Deref<Target = NonNull<u32>> {
53        DerefWrapper(NonNull::from_ref(&Data::SIZE))
54    }
55
56    #[inline(always)]
57    #[track_caller]
58    unsafe fn set_size(&mut self, size: u32) {
59        debug_assert!(
60            size == 0 || size == self.size(),
61            "`set_size` called with invalid input {size} (self size {})",
62            self.size()
63        );
64
65        // SAFETY: guaranteed to be initialized by constructors
66        unsafe {
67            self.size.write(size);
68        }
69    }
70
71    #[inline(always)]
72    #[track_caller]
73    unsafe fn from_ptr<'a>(
74        data: &'a NonNull<Self::PointerType>,
75        size: &'a u32,
76        capacity: u32,
77    ) -> impl Deref<Target = Self> + 'a {
78        debug_assert!(data.is_aligned(), "Misaligned pointer");
79        debug_assert!(
80            *size == 0 || *size <= capacity,
81            "Invalid size {size} for capacity {capacity}"
82        );
83        // Read-only instance can have 0 capacity if empty
84        debug_assert!(
85            capacity == 0 || capacity >= Data::SIZE,
86            "Invalid capacity {capacity} for size {}",
87            Data::SIZE
88        );
89
90        let size = NonNull::from_ref(size);
91
92        DerefWrapper(MaybeData { data: *data, size })
93    }
94
95    #[inline(always)]
96    #[track_caller]
97    unsafe fn from_mut_ptr<'a>(
98        data: &'a mut NonNull<Self::PointerType>,
99        size: &'a mut *mut u32,
100        capacity: u32,
101    ) -> impl DerefMut<Target = Self> + 'a {
102        debug_assert!(!size.is_null(), "`null` pointer for non-`TrivialType` size");
103        // SAFETY: Must be guaranteed by the caller + debug check above
104        let size = unsafe { NonNull::new_unchecked(*size) };
105        debug_assert!(data.is_aligned(), "Misaligned pointer");
106        {
107            // SAFETY: Must be guaranteed by the caller
108            let size = unsafe { size.read() };
109            debug_assert!(
110                size == 0 || size <= capacity,
111                "Invalid size {size} for capacity {capacity}"
112            );
113        }
114        debug_assert!(
115            capacity >= Data::SIZE,
116            "Invalid capacity {capacity} for size {}",
117            Data::SIZE
118        );
119
120        DerefWrapper(MaybeData { data: *data, size })
121    }
122
123    #[inline(always)]
124    unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>> {
125        &self.data
126    }
127
128    #[inline(always)]
129    unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>> {
130        &mut self.data
131    }
132}
133
134impl<Data> IoTypeOptional for MaybeData<Data> where Data: TrivialType {}
135
136impl<Data> MaybeData<Data>
137where
138    Data: TrivialType,
139{
140    /// Create a new shared instance from provided data reference.
141    //
142    // `impl Deref` is used to tie lifetime of returned value to inputs, but still treat it as a
143    // shared reference for most practical purposes.
144    pub const fn from_ref(data: Option<&'_ Data>) -> impl Deref<Target = Self> + '_ {
145        let (data, size) = if let Some(data) = data {
146            (NonNull::from_ref(data), &Data::SIZE)
147        } else {
148            (NonNull::dangling(), &0)
149        };
150
151        DerefWrapper(Self {
152            data,
153            size: NonNull::from_ref(size),
154        })
155    }
156
157    /// Create a new exclusive instance from provided data reference.
158    ///
159    /// `size` can be either `0` or `Data::SIZE`, indicating that value is missing or present
160    /// accordingly.
161    ///
162    /// # Panics
163    /// Panics if `size != 0 && size != Data::SIZE`
164    //
165    // `impl DerefMut` is used to tie lifetime of returned value to inputs, but still treat it as an
166    // exclusive reference for most practical purposes.
167    #[track_caller]
168    pub fn from_mut<'a>(
169        buffer: &'a mut Data,
170        size: &'a mut u32,
171    ) -> impl DerefMut<Target = Self> + 'a {
172        debug_assert!(
173            *size == 0 || *size == Data::SIZE,
174            "Invalid size {size} (self size {})",
175            Data::SIZE
176        );
177
178        DerefWrapper(Self {
179            data: NonNull::from_mut(buffer),
180            size: NonNull::from_ref(size),
181        })
182    }
183
184    /// Create a new shared instance from provided memory buffer.
185    ///
186    /// `size` must be `0`.
187    ///
188    /// # Panics
189    /// Panics if `size != 0`
190    //
191    // `impl Deref` is used to tie lifetime of returned value to inputs, but still treat it as a
192    // shared reference for most practical purposes.
193    // TODO: Change `usize` to `u32` once stabilized `generic_const_exprs` feature allows us to do
194    //  `CAPACITY as usize`
195    #[track_caller]
196    pub fn from_uninit<'a>(
197        uninit: &'a mut MaybeUninit<Data>,
198        size: &'a mut u32,
199    ) -> impl DerefMut<Target = Self> + 'a {
200        debug_assert_eq!(*size, 0, "Invalid size");
201
202        DerefWrapper(Self {
203            data: NonNull::from_mut(uninit).cast::<Data>(),
204            size: NonNull::from_mut(size),
205        })
206    }
207
208    /// Try to get access to initialized `Data`, returns `None` if not initialized
209    #[inline(always)]
210    pub const fn get(&self) -> Option<&Data> {
211        // SAFETY: guaranteed to be initialized by constructors
212        if unsafe { self.size.read() } == Data::SIZE {
213            // SAFETY: initialized
214            Some(unsafe { self.data.as_ref() })
215        } else {
216            None
217        }
218    }
219
220    /// Try to get exclusive access to initialized `Data`, returns `None` if not initialized
221    #[inline(always)]
222    pub fn get_mut(&mut self) -> Option<&mut Data> {
223        // SAFETY: guaranteed to be initialized by constructors
224        if unsafe { self.size.read() } == Data::SIZE {
225            // SAFETY: initialized
226            Some(unsafe { self.data.as_mut() })
227        } else {
228            None
229        }
230    }
231
232    /// Initialize by inserting `Data` by value or replace existing value and return reference to it
233    #[inline(always)]
234    pub fn replace(&mut self, data: Data) -> &mut Data {
235        // SAFETY: guaranteed to be initialized by constructors
236        unsafe {
237            self.size.write(Data::SIZE);
238        }
239        // SAFETY: constructor guarantees that memory is aligned
240        unsafe {
241            self.data.write(data);
242            self.data.as_mut()
243        }
244    }
245
246    /// Remove `Data` inside and turn instance back into uninitialized
247    #[inline(always)]
248    pub fn remove(&mut self) {
249        // SAFETY: guaranteed to be initialized by constructors
250        unsafe {
251            self.size.write(0);
252        }
253    }
254
255    /// Get exclusive access to initialized `Data`, running provided initialization function if
256    /// necessary
257    #[inline(always)]
258    pub fn get_mut_or_init_with<Init>(&mut self, init: Init) -> &mut Data
259    where
260        Init: FnOnce(&mut MaybeUninit<Data>) -> &mut Data,
261    {
262        // SAFETY: guaranteed to be initialized by constructors
263        if unsafe { self.size.read() } == Data::SIZE {
264            // SAFETY: initialized
265            unsafe { self.data.as_mut() }
266        } else {
267            // SAFETY: constructor guarantees that memory is aligned
268            let data = init(unsafe { self.data.as_uninit_mut() });
269            // SAFETY: guaranteed to be initialized by constructors
270            unsafe {
271                self.size.write(Data::SIZE);
272            }
273            data
274        }
275    }
276
277    /// Assume value is initialized
278    ///
279    /// # Safety
280    /// Caller must ensure `Data` is actually properly initialized
281    #[inline(always)]
282    pub unsafe fn assume_init(&mut self) -> &mut Data {
283        // SAFETY: guaranteed to be initialized by constructors
284        unsafe {
285            self.size.write(Data::SIZE);
286        }
287        // SAFETY: guaranteed to be initialized by caller, the rest of guarantees are provided by
288        // constructors
289        unsafe { self.data.as_mut() }
290    }
291}
292
293impl<Data> MaybeData<Data>
294where
295    Data: TrivialType + Default,
296{
297    /// Get exclusive access to initialized `Data`, initializing with default value if necessary
298    #[inline(always)]
299    pub fn get_mut_or_default(&mut self) -> &mut Data {
300        self.get_mut_or_init_with(|data| data.write(Data::default()))
301    }
302}