1#[cfg(test)]
2mod tests;
3
4use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
5use crate::trivial_type::{NON_ZERO_SIZED, TrivialType, try_skip_valid};
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#[inline(always)]
19unsafe fn contents_are_valid<Element>(ptr: NonNull<Element>, size: u32) -> bool
20where
21 Element: TrivialType,
22 [(); NON_ZERO_SIZED::<Element>]:,
23{
24 if size_of::<Element>() == 0 {
27 return false;
28 }
29 let bytes = unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size as usize) };
32 unsafe { try_skip_valid::<Element, true>(bytes, bytes.len() / size_of::<Element>()) }.is_some()
34}
35
36#[derive(Debug)]
45#[repr(C)]
46pub struct VariableElements<'a, Element, const RECOMMENDED_ALLOCATION: u32 = 0>
47where
48 Element: TrivialType,
49{
50 elements: NonNull<Element>,
51 size: NonNull<u32>,
52 capacity: u32,
53 memory: PhantomData<&'a ()>,
54 _supported: [(); NON_ZERO_SIZED::<Element>],
59}
60
61unsafe impl<Element, const RECOMMENDED_ALLOCATION: u32> IoType
63 for VariableElements<'_, Element, RECOMMENDED_ALLOCATION>
64where
65 Element: TrivialType,
66 [(); NON_ZERO_SIZED::<Element>]:,
67{
68 const METADATA: &[u8] = {
69 const fn metadata(
70 recommended_allocation: u32,
71 inner_metadata: &[u8],
72 ) -> ([u8; MAX_METADATA_CAPACITY], usize) {
73 concat_metadata_sources(&[
74 &[IoTypeMetadataKind::VariableElements as u8],
75 &recommended_allocation.to_le_bytes(),
76 inner_metadata,
77 ])
78 }
79
80 let (metadata_scratch, metadata_size) =
82 &metadata(RECOMMENDED_ALLOCATION, Element::METADATA);
83 metadata_scratch.split_at(*metadata_size).0
84 };
85
86 type PointerType = Element;
88
89 type WithLifetime<'b> = VariableElements<'b, Element, RECOMMENDED_ALLOCATION>;
90
91 type Reborrowed<'b>
92 = VariableElements<'b, Element, RECOMMENDED_ALLOCATION>
93 where
94 Self: 'b;
95
96 #[inline(always)]
97 fn size(&self) -> u32 {
98 self.size()
99 }
100
101 #[inline(always)]
102 fn capacity(&self) -> u32 {
103 self.capacity
104 }
105
106 #[inline(always)]
107 #[track_caller]
108 unsafe fn set_size(&mut self, size: u32) {
109 debug_assert!(
110 size <= self.capacity,
111 "`set_size` called with invalid input {size} for capacity {}",
112 self.capacity
113 );
114 debug_assert!(
115 size.is_multiple_of(Element::SIZE),
116 "`set_size` called with invalid input {size} for element size {}",
117 Element::SIZE
118 );
119
120 unsafe {
122 self.size.write(size);
123 }
124 }
125
126 #[inline(always)]
127 #[track_caller]
128 unsafe fn from_ptr<'a>(
129 ptr: &'a NonNull<Self::PointerType>,
130 size: &'a u32,
131 capacity: u32,
132 ) -> impl Deref<Target = Self::WithLifetime<'a>> + 'a {
133 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
134 debug_assert!(
135 *size <= capacity,
136 "Size {size} must not exceed capacity {capacity}"
137 );
138 debug_assert!(
139 size.is_multiple_of(Element::SIZE),
140 "Size {size} is invalid for element size {}",
141 Element::SIZE
142 );
143
144 DerefWrapper(VariableElements {
145 elements: *ptr,
146 size: NonNull::from_ref(size),
147 capacity,
148 memory: PhantomData,
149 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
150 })
151 }
152
153 #[inline(always)]
154 #[track_caller]
155 unsafe fn from_mut_ptr<'a>(
156 ptr: &'a mut NonNull<Self::PointerType>,
157 size: &'a mut u32,
158 capacity: u32,
159 ) -> impl DerefMut<Target = Self::WithLifetime<'a>> + 'a {
160 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
161 debug_assert!(
162 *size <= capacity,
163 "Size {size} must not exceed capacity {capacity}"
164 );
165 debug_assert!(
166 size.is_multiple_of(Element::SIZE),
167 "Size {size} is invalid for element size {}",
168 Element::SIZE
169 );
170
171 DerefWrapper(VariableElements {
172 elements: *ptr,
173 size: NonNull::from_mut(size),
174 capacity,
175 memory: PhantomData,
176 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
177 })
178 }
179
180 #[inline(always)]
181 #[track_caller]
182 unsafe fn try_from_ptr<'a>(
183 ptr: &'a NonNull<Self::PointerType>,
184 size: &'a u32,
185 capacity: u32,
186 ) -> Option<impl Deref<Target = Self::WithLifetime<'a>> + 'a> {
187 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
188 debug_assert!(
189 *size <= capacity,
190 "Size {size} must not exceed capacity {capacity}"
191 );
192 debug_assert!(
193 size.is_multiple_of(Element::SIZE),
194 "Size {size} is invalid for element size {}",
195 Element::SIZE
196 );
197 if !unsafe { contents_are_valid(*ptr, *size) } {
200 return None;
201 }
202
203 Some(unsafe { Self::from_ptr(ptr, size, capacity) })
207 }
208
209 #[inline(always)]
210 #[track_caller]
211 unsafe fn try_from_mut_ptr<'a>(
212 ptr: &'a mut NonNull<Self::PointerType>,
213 size: &'a mut u32,
214 capacity: u32,
215 ) -> Option<impl DerefMut<Target = Self::WithLifetime<'a>> + 'a> {
216 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
217 debug_assert!(
218 *size <= capacity,
219 "Size {size} must not exceed capacity {capacity}"
220 );
221 debug_assert!(
222 size.is_multiple_of(Element::SIZE),
223 "Size {size} is invalid for element size {}",
224 Element::SIZE
225 );
226 if !unsafe { contents_are_valid(*ptr, *size) } {
229 return None;
230 }
231
232 Some(unsafe { Self::from_mut_ptr(ptr, size, capacity) })
237 }
238
239 #[inline(always)]
240 fn as_ptr(&self) -> NonNull<Self::PointerType> {
241 self.elements
242 }
243
244 #[inline(always)]
245 fn as_mut_ptr(&mut self) -> NonNull<Self::PointerType> {
246 self.elements
247 }
248
249 #[inline(always)]
250 fn reborrow_mut(&mut self) -> Self::Reborrowed<'_> {
251 VariableElements {
252 elements: self.elements,
253 size: self.size,
254 capacity: self.capacity,
255 memory: PhantomData,
256 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
257 }
258 }
259}
260
261unsafe impl<Element, const RECOMMENDED_ALLOCATION: u32> IoTypeOptional
264 for VariableElements<'_, Element, RECOMMENDED_ALLOCATION>
265where
266 Element: TrivialType,
267 [(); NON_ZERO_SIZED::<Element>]:,
268{
269}
270
271impl<'a, Element, const RECOMMENDED_ALLOCATION: u32>
274 VariableElements<'a, Element, RECOMMENDED_ALLOCATION>
275where
276 Element: TrivialType,
277 Self: IoType,
278{
279 #[inline(always)]
288 pub const fn from_buffer(
289 buffer: &'a [Element],
290 size: &'a u32,
291 ) -> Option<impl Deref<Target = Self> + 'a> {
292 if size_of_val(buffer) != *size as usize {
293 return None;
294 }
295
296 Some(DerefWrapper(Self {
297 elements: NonNull::new(buffer.as_ptr().cast_mut()).expect("Not null; qed"),
298 size: NonNull::from_ref(size),
299 capacity: *size,
300 memory: PhantomData,
301 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
302 }))
303 }
304
305 #[inline(always)]
311 pub fn from_buffer_mut(buffer: &'a mut [Element], size: &'a mut u32) -> Option<Self> {
312 if size_of_val(buffer) != *size as usize {
313 return None;
314 }
315
316 Some(Self {
317 elements: NonNull::new(buffer.as_mut_ptr()).expect("Not null; qed"),
318 size: NonNull::from_mut(size),
319 capacity: *size,
320 memory: PhantomData,
321 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
322 })
323 }
324
325 #[inline(always)]
332 pub fn from_uninit(uninit: &'a mut [MaybeUninit<Element>], size: &'a mut u32) -> Option<Self> {
333 if *size != 0 {
334 return None;
335 }
336 let capacity = u32::try_from(size_of_val(uninit)).ok()?;
337
338 Some(Self {
339 elements: NonNull::new(uninit.as_mut_ptr().cast_init()).expect("Not null; qed"),
340 size: NonNull::from_mut(size),
341 capacity,
342 memory: PhantomData,
343 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
344 })
345 }
346
347 #[inline(always)]
349 pub const fn count(&self) -> u32 {
350 self.size() / Element::SIZE
351 }
352
353 #[inline(always)]
355 pub const fn get_initialized(&self) -> &[Element] {
356 let size = self.size();
357 let ptr = self.elements.as_ptr();
358 unsafe { slice::from_raw_parts(ptr, (size / Element::SIZE) as usize) }
360 }
361
362 #[inline(always)]
364 pub fn get_initialized_mut(&mut self) -> &mut [Element] {
365 let size = self.size();
366 let ptr = self.elements.as_ptr();
367 unsafe { slice::from_raw_parts_mut(ptr, (size / Element::SIZE) as usize) }
369 }
370
371 #[inline(always)]
375 #[must_use = "Operation may fail"]
376 pub fn append(&mut self, elements: &[Element]) -> bool {
377 let size = self.size();
378 let Some(new_size) = u32::try_from(size_of_val(elements))
379 .ok()
380 .and_then(|appended_size| size.checked_add(appended_size))
381 else {
382 return false;
383 };
384 if new_size > self.capacity {
385 return false;
386 }
387
388 let Ok(offset) = isize::try_from(size / Element::SIZE) else {
390 return false;
391 };
392
393 let start = unsafe { self.elements.offset(offset) };
396 unsafe {
402 ptr::copy_nonoverlapping(elements.as_ptr(), start.as_ptr(), elements.len());
403 self.size.write(new_size);
404 }
405
406 true
407 }
408
409 #[inline(always)]
414 #[must_use = "Operation may fail"]
415 pub fn truncate(&mut self, new_size: u32) -> bool {
416 if new_size > self.size() || !new_size.is_multiple_of(Element::SIZE) {
417 return false;
418 }
419
420 unsafe {
422 self.size.write(new_size);
423 }
424
425 true
426 }
427
428 #[inline(always)]
432 #[must_use = "Operation may fail"]
433 pub fn copy_from(
434 &mut self,
435 src: &VariableElements<'_, Element, RECOMMENDED_ALLOCATION>,
436 ) -> bool {
437 let src_size = src.size();
438 if src_size > self.capacity {
439 return false;
440 }
441
442 unsafe {
446 self.elements
447 .copy_from_nonoverlapping(src.elements, (src_size / Element::SIZE) as usize);
448 self.size.write(src_size);
449 }
450
451 true
452 }
453
454 #[inline(always)]
462 #[must_use = "Operation may fail"]
463 pub unsafe fn assume_init(&mut self, size: u32) -> Option<&mut [Element]> {
464 if size > self.capacity || !size.is_multiple_of(Element::SIZE) {
465 return None;
466 }
467
468 unsafe {
470 self.size.write(size);
471 }
472 Some(self.get_initialized_mut())
473 }
474}
475
476impl<'a, Element, const RECOMMENDED_ALLOCATION: u32>
478 VariableElements<'a, Element, RECOMMENDED_ALLOCATION>
479where
480 Element: TrivialType,
481{
482 #[inline(always)]
484 pub const fn size(&self) -> u32 {
485 unsafe { self.size.read() }
487 }
488
489 #[inline(always)]
491 pub fn capacity(&self) -> u32 {
492 self.capacity
493 }
494
495 #[inline(always)]
498 pub fn cast_ref<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
499 &self,
500 ) -> &VariableElements<'a, Element, DIFFERENT_RECOMMENDED_ALLOCATION> {
501 unsafe {
504 NonNull::from_ref(self)
505 .cast::<VariableElements<'a, Element, DIFFERENT_RECOMMENDED_ALLOCATION>>()
506 .as_ref()
507 }
508 }
509
510 #[inline(always)]
513 pub fn cast_mut<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
514 &mut self,
515 ) -> &mut VariableElements<'a, Element, DIFFERENT_RECOMMENDED_ALLOCATION> {
516 unsafe {
519 NonNull::from_mut(self)
520 .cast::<VariableElements<'a, Element, DIFFERENT_RECOMMENDED_ALLOCATION>>()
521 .as_mut()
522 }
523 }
524}