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, IoTypeOptional};
7use core::marker::PhantomData;
8use core::mem::MaybeUninit;
9use core::ops::{Deref, DerefMut};
10use core::ptr::NonNull;
11use core::{ptr, slice};
12
13#[derive(Debug)]
21pub struct MaybeData<'a, Data>
22where
23 Data: TrivialType,
24{
25 data: NonNull<Data>,
26 size: NonNull<u32>,
27 memory: PhantomData<&'a ()>,
28 _supported: [(); NON_ZERO_SIZED::<Data>],
33}
34
35unsafe impl<Data> IoType for MaybeData<'_, Data>
37where
38 Data: TrivialType,
39 [(); NON_ZERO_SIZED::<Data>]:,
40{
41 const METADATA: &[u8] = {
42 const fn metadata(inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
43 concat_metadata_sources(&[&[IoTypeMetadataKind::MaybeData as u8], inner_metadata])
44 }
45
46 let (metadata_scratch, metadata_size) = &metadata(Data::METADATA);
48 metadata_scratch.split_at(*metadata_size).0
49 };
50
51 type PointerType = Data;
52
53 type WithLifetime<'b> = MaybeData<'b, Data>;
54
55 type Reborrowed<'b>
56 = MaybeData<'b, Data>
57 where
58 Self: 'b;
59
60 #[inline(always)]
61 fn size(&self) -> u32 {
62 unsafe { self.size.read() }
64 }
65
66 #[inline(always)]
67 fn capacity(&self) -> u32 {
68 Data::SIZE
69 }
70
71 #[inline(always)]
72 #[track_caller]
73 unsafe fn set_size(&mut self, size: u32) {
74 debug_assert!(
75 size == 0 || size == Data::SIZE,
76 "`set_size` called with invalid input {size} (self size {})",
77 self.size()
78 );
79
80 unsafe {
82 self.size.write(size);
83 }
84 }
85
86 #[inline(always)]
87 #[track_caller]
88 unsafe fn from_ptr<'a>(
89 ptr: &'a NonNull<Self::PointerType>,
90 size: &'a u32,
91 capacity: u32,
92 ) -> impl Deref<Target = Self::WithLifetime<'a>> + 'a {
93 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
94 debug_assert!(
95 *size == 0 || *size <= capacity,
96 "Invalid size {size} for capacity {capacity}"
97 );
98 debug_assert!(
100 capacity == 0 || capacity >= Data::SIZE,
101 "Invalid capacity {capacity} for size {}",
102 Data::SIZE
103 );
104
105 let size = NonNull::from_ref(size);
106
107 DerefWrapper(MaybeData {
108 data: *ptr,
109 size,
110 memory: PhantomData,
111 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
112 })
113 }
114
115 #[inline(always)]
116 #[track_caller]
117 unsafe fn from_mut_ptr<'a>(
118 ptr: &'a mut NonNull<Self::PointerType>,
119 size: &'a mut u32,
120 capacity: u32,
121 ) -> impl DerefMut<Target = Self::WithLifetime<'a>> + 'a {
122 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
123 debug_assert!(
124 *size == 0 || *size <= capacity,
125 "Invalid size {size} for capacity {capacity}"
126 );
127 debug_assert!(
128 capacity >= Data::SIZE,
129 "Invalid capacity {capacity} for size {}",
130 Data::SIZE
131 );
132
133 DerefWrapper(MaybeData {
134 data: *ptr,
135 size: NonNull::from_mut(size),
136 memory: PhantomData,
137 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
138 })
139 }
140
141 #[inline(always)]
142 #[track_caller]
143 unsafe fn try_from_ptr<'a>(
144 ptr: &'a NonNull<Self::PointerType>,
145 size: &'a u32,
146 capacity: u32,
147 ) -> Option<impl Deref<Target = Self::WithLifetime<'a>> + 'a> {
148 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
149 debug_assert!(
150 *size == 0 || (*size == Data::SIZE && *size <= capacity),
151 "Invalid size {size} for capacity {capacity}"
152 );
153 debug_assert!(
155 capacity == 0 || capacity >= Data::SIZE,
156 "Invalid capacity {capacity} for size {}",
157 Data::SIZE
158 );
159 if *size == Data::SIZE {
160 let bytes =
163 unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size_of::<Data>()) };
164 unsafe { Data::parse_step::<true>(bytes) }?;
166 }
167
168 Some(unsafe { Self::from_ptr(ptr, size, capacity) })
172 }
173
174 #[inline(always)]
175 #[track_caller]
176 unsafe fn try_from_mut_ptr<'a>(
177 ptr: &'a mut NonNull<Self::PointerType>,
178 size: &'a mut u32,
179 capacity: u32,
180 ) -> Option<impl DerefMut<Target = Self::WithLifetime<'a>> + 'a> {
181 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
182 debug_assert!(
183 *size == 0 || *size == Data::SIZE,
184 "Invalid size {size} for data size {}",
185 Data::SIZE
186 );
187 debug_assert!(
189 capacity >= Data::SIZE,
190 "Invalid capacity {capacity} for size {}",
191 Data::SIZE
192 );
193 if *size == Data::SIZE {
194 let bytes =
198 unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size_of::<Data>()) };
199 unsafe { Data::parse_step::<true>(bytes) }?;
201 }
202
203 Some(unsafe { Self::from_mut_ptr(ptr, size, capacity) })
208 }
209
210 #[inline(always)]
211 fn as_ptr(&self) -> NonNull<Self::PointerType> {
212 self.data
213 }
214
215 #[inline(always)]
216 fn as_mut_ptr(&mut self) -> NonNull<Self::PointerType> {
217 self.data
218 }
219
220 #[inline(always)]
221 fn reborrow_mut(&mut self) -> Self::Reborrowed<'_> {
222 MaybeData {
223 data: self.data,
224 size: self.size,
225 memory: PhantomData,
226 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
227 }
228 }
229}
230
231unsafe impl<Data> IoTypeOptional for MaybeData<'_, Data>
233where
234 Data: TrivialType,
235 [(); NON_ZERO_SIZED::<Data>]:,
236{
237}
238
239impl<'a, Data> MaybeData<'a, Data>
242where
243 Data: TrivialType,
244 Self: IoType,
245{
246 pub const fn from_ref(data: Option<&'a Data>) -> impl Deref<Target = Self> + 'a {
251 let (data, size) = if let Some(data) = data {
252 (NonNull::from_ref(data), &Data::SIZE)
253 } else {
254 (NonNull::dangling(), &0)
255 };
256
257 DerefWrapper(Self {
258 data,
259 size: NonNull::from_ref(size),
260 memory: PhantomData,
261 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
262 })
263 }
264
265 pub fn from_mut(buffer: &'a mut Data, size: &'a mut u32) -> Option<Self> {
272 if !(*size == 0 || *size == Data::SIZE) {
273 return None;
274 }
275
276 Some(Self {
277 data: NonNull::from_mut(buffer),
278 size: NonNull::from_mut(size),
279 memory: PhantomData,
280 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
281 })
282 }
283
284 pub fn from_uninit(uninit: &'a mut MaybeUninit<Data>, size: &'a mut u32) -> Option<Self> {
290 if *size != 0 {
291 return None;
292 }
293
294 Some(Self {
295 data: NonNull::from_mut(uninit).cast::<Data>(),
296 size: NonNull::from_mut(size),
297 memory: PhantomData,
298 _supported: const { [(); NON_ZERO_SIZED::<Data>] },
299 })
300 }
301
302 #[inline(always)]
304 pub const fn get(&self) -> Option<&Data> {
305 if unsafe { self.size.read() } == Data::SIZE {
307 Some(unsafe { self.data.as_ref() })
309 } else {
310 None
311 }
312 }
313
314 #[inline(always)]
316 pub fn get_mut(&mut self) -> Option<&mut Data> {
317 if unsafe { self.size.read() } == Data::SIZE {
319 Some(unsafe { self.data.as_mut() })
321 } else {
322 None
323 }
324 }
325
326 #[inline(always)]
328 pub fn replace(&mut self, data: Data) -> &mut Data {
329 unsafe {
331 self.size.write(Data::SIZE);
332 }
333 unsafe {
335 self.data.write(data);
336 self.data.as_mut()
337 }
338 }
339
340 #[inline(always)]
342 pub fn remove(&mut self) {
343 unsafe {
345 self.size.write(0);
346 }
347 }
348
349 #[inline(always)]
356 pub fn get_mut_or_init_with<Init>(&mut self, init: Init) -> &mut Data
357 where
358 Init: FnOnce(&mut MaybeUninit<Data>) -> &mut Data,
359 {
360 if unsafe { self.size.read() } == Data::SIZE {
362 unsafe { self.data.as_mut() }
364 } else {
365 let data = init(unsafe { self.data.as_uninit_mut() });
367 if !ptr::eq(data, self.data.as_ptr()) {
368 unsafe {
370 self.data.write(*data);
371 }
372 }
373 unsafe {
375 self.size.write(Data::SIZE);
376 }
377 unsafe { self.data.as_mut() }
380 }
381 }
382
383 #[inline(always)]
388 pub unsafe fn assume_init(&mut self) -> &mut Data {
389 unsafe {
391 self.size.write(Data::SIZE);
392 }
393 unsafe { self.data.as_mut() }
396 }
397}
398
399impl<Data> MaybeData<'_, Data>
400where
401 Data: TrivialType + Default,
402 Self: IoType,
403{
404 #[inline(always)]
406 pub fn get_mut_or_default(&mut self) -> &mut Data {
407 self.get_mut_or_init_with(|data| data.write(Data::default()))
408 }
409}