1#[cfg(test)]
2mod tests;
3
4use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
5use crate::trivial_type::{NON_ZERO_SIZED, TrivialType};
6use crate::{DerefWrapper, IoType, IoTypeMut, IoTypeOptional};
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::ptr::NonNull;
10use core::{ptr, slice};
11
12#[derive(Debug)]
18pub struct MaybeData<Data>
19where
20 Data: TrivialType,
21{
22 data: NonNull<Data>,
23 size: NonNull<u32>,
24 _supported: [(); NON_ZERO_SIZED::<Data>],
29}
30
31unsafe impl<Data> IoType for MaybeData<Data>
33where
34 Data: TrivialType,
35 [(); NON_ZERO_SIZED::<Data>]:,
36{
37 const METADATA: &[u8] = {
38 const fn metadata(inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
39 concat_metadata_sources(&[&[IoTypeMetadataKind::MaybeData as u8], inner_metadata])
40 }
41
42 let (metadata_scratch, metadata_size) = &metadata(Data::METADATA);
44 metadata_scratch.split_at(*metadata_size).0
45 };
46
47 type PointerType = Data;
48
49 #[inline(always)]
50 fn size(&self) -> u32 {
51 unsafe { self.size.read() }
53 }
54
55 #[inline(always)]
56 fn capacity(&self) -> u32 {
57 Data::SIZE
58 }
59
60 #[inline(always)]
61 #[track_caller]
62 unsafe fn set_size(&mut self, size: u32) {
63 debug_assert!(
64 size == 0 || size == Data::SIZE,
65 "`set_size` called with invalid input {size} (self size {})",
66 self.size()
67 );
68
69 unsafe {
71 self.size.write(size);
72 }
73 }
74
75 #[inline(always)]
76 #[track_caller]
77 unsafe fn from_ptr<'a>(
78 ptr: &'a NonNull<Self::PointerType>,
79 size: &'a u32,
80 capacity: u32,
81 ) -> impl Deref<Target = Self> + 'a {
82 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
83 debug_assert!(
84 *size == 0 || *size <= capacity,
85 "Invalid size {size} for capacity {capacity}"
86 );
87 debug_assert!(
89 capacity == 0 || capacity >= Data::SIZE,
90 "Invalid capacity {capacity} for size {}",
91 Data::SIZE
92 );
93
94 let size = NonNull::from_ref(size);
95
96 DerefWrapper(MaybeData {
97 data: *ptr,
98 size,
99 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
100 })
101 }
102
103 #[inline(always)]
104 #[track_caller]
105 unsafe fn from_mut_ptr<'a>(
106 ptr: &'a mut NonNull<Self::PointerType>,
107 size: &'a mut u32,
108 capacity: u32,
109 ) -> impl DerefMut<Target = Self> + 'a {
110 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
111 debug_assert!(
112 *size == 0 || *size <= capacity,
113 "Invalid size {size} for capacity {capacity}"
114 );
115 debug_assert!(
116 capacity >= Data::SIZE,
117 "Invalid capacity {capacity} for size {}",
118 Data::SIZE
119 );
120
121 DerefWrapper(MaybeData {
122 data: *ptr,
123 size: NonNull::from_mut(size),
124 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
125 })
126 }
127
128 #[inline(always)]
129 #[track_caller]
130 unsafe fn try_from_ptr<'a>(
131 ptr: &'a NonNull<Self::PointerType>,
132 size: &'a u32,
133 capacity: u32,
134 ) -> Option<impl Deref<Target = Self> + 'a> {
135 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
136 debug_assert!(
137 *size == 0 || (*size == Data::SIZE && *size <= capacity),
138 "Invalid size {size} for capacity {capacity}"
139 );
140 debug_assert!(
142 capacity == 0 || capacity >= Data::SIZE,
143 "Invalid capacity {capacity} for size {}",
144 Data::SIZE
145 );
146 if *size == Data::SIZE {
147 let bytes =
150 unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size_of::<Data>()) };
151 Data::try_from_bytes_unaligned(bytes)?;
152 }
153
154 Some(unsafe { Self::from_ptr(ptr, size, capacity) })
158 }
159
160 #[inline(always)]
161 #[track_caller]
162 unsafe fn try_from_mut_ptr<'a>(
163 ptr: &'a mut NonNull<Self::PointerType>,
164 size: &'a mut u32,
165 capacity: u32,
166 ) -> Option<impl DerefMut<Target = Self> + 'a> {
167 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
168 debug_assert!(
169 *size == 0 || *size == Data::SIZE,
170 "Invalid size {size} for data size {}",
171 Data::SIZE
172 );
173 debug_assert!(
175 capacity >= Data::SIZE,
176 "Invalid capacity {capacity} for size {}",
177 Data::SIZE
178 );
179 if *size == Data::SIZE {
180 let bytes =
184 unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size_of::<Data>()) };
185 Data::try_from_bytes_unaligned(bytes)?;
186 }
187
188 Some(unsafe { Self::from_mut_ptr(ptr, size, capacity) })
193 }
194
195 #[inline(always)]
196 fn as_ptr(&self) -> NonNull<Self::PointerType> {
197 self.data
198 }
199
200 #[inline(always)]
201 fn as_mut_ptr(&mut self) -> NonNull<Self::PointerType> {
202 self.data
203 }
204}
205
206unsafe impl<Data> IoTypeOptional for MaybeData<Data>
208where
209 Data: TrivialType,
210 [(); NON_ZERO_SIZED::<Data>]:,
211{
212}
213
214impl<Data> MaybeData<Data>
217where
218 Data: TrivialType,
219 Self: IoType,
220{
221 pub const fn from_ref(data: Option<&'_ Data>) -> impl Deref<Target = Self> + '_ {
226 let (data, size) = if let Some(data) = data {
227 (NonNull::from_ref(data), &Data::SIZE)
228 } else {
229 (NonNull::dangling(), &0)
230 };
231
232 DerefWrapper(Self {
233 data,
234 size: NonNull::from_ref(size),
235 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
236 })
237 }
238
239 pub fn from_mut<'a>(
249 buffer: &'a mut Data,
250 size: &'a mut u32,
251 ) -> Option<impl DerefMut<Target = Self> + IoTypeMut<Target = Self> + 'a> {
252 if !(*size == 0 || *size == Data::SIZE) {
253 return None;
254 }
255
256 Some(DerefWrapper(Self {
257 data: NonNull::from_mut(buffer),
258 size: NonNull::from_mut(size),
259 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
260 }))
261 }
262
263 pub fn from_uninit<'a>(
272 uninit: &'a mut MaybeUninit<Data>,
273 size: &'a mut u32,
274 ) -> Option<impl DerefMut<Target = Self> + IoTypeMut<Target = Self> + 'a> {
275 if *size != 0 {
276 return None;
277 }
278
279 Some(DerefWrapper(Self {
280 data: NonNull::from_mut(uninit).cast::<Data>(),
281 size: NonNull::from_mut(size),
282 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
283 }))
284 }
285
286 #[inline(always)]
288 pub const fn get(&self) -> Option<&Data> {
289 if unsafe { self.size.read() } == Data::SIZE {
291 Some(unsafe { self.data.as_ref() })
293 } else {
294 None
295 }
296 }
297
298 #[inline(always)]
300 pub fn get_mut(&mut self) -> Option<&mut Data> {
301 if unsafe { self.size.read() } == Data::SIZE {
303 Some(unsafe { self.data.as_mut() })
305 } else {
306 None
307 }
308 }
309
310 #[inline(always)]
312 pub fn replace(&mut self, data: Data) -> &mut Data {
313 unsafe {
315 self.size.write(Data::SIZE);
316 }
317 unsafe {
319 self.data.write(data);
320 self.data.as_mut()
321 }
322 }
323
324 #[inline(always)]
326 pub fn remove(&mut self) {
327 unsafe {
329 self.size.write(0);
330 }
331 }
332
333 #[inline(always)]
340 pub fn get_mut_or_init_with<Init>(&mut self, init: Init) -> &mut Data
341 where
342 Init: FnOnce(&mut MaybeUninit<Data>) -> &mut Data,
343 {
344 if unsafe { self.size.read() } == Data::SIZE {
346 unsafe { self.data.as_mut() }
348 } else {
349 let data = init(unsafe { self.data.as_uninit_mut() });
351 if !ptr::eq(data, self.data.as_ptr()) {
352 unsafe {
354 self.data.write(*data);
355 }
356 }
357 unsafe {
359 self.size.write(Data::SIZE);
360 }
361 unsafe { self.data.as_mut() }
364 }
365 }
366
367 #[inline(always)]
372 pub unsafe fn assume_init(&mut self) -> &mut Data {
373 unsafe {
375 self.size.write(Data::SIZE);
376 }
377 unsafe { self.data.as_mut() }
380 }
381}
382
383impl<Data> MaybeData<Data>
384where
385 Data: TrivialType + Default,
386 Self: IoType,
387{
388 #[inline(always)]
390 pub fn get_mut_or_default(&mut self) -> &mut Data {
391 self.get_mut_or_init_with(|data| data.write(Data::default()))
392 }
393}