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, IoTypeMut, IoTypeOptional};
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::ptr::NonNull;
10use core::{ptr, slice};
11
12#[inline(always)]
18unsafe fn contents_are_valid<Element>(ptr: NonNull<Element>, size: u32) -> bool
19where
20 Element: TrivialType,
21 [(); NON_ZERO_SIZED::<Element>]:,
22{
23 if size_of::<Element>() == 0 {
26 return false;
27 }
28 let bytes = unsafe { slice::from_raw_parts(ptr.as_ptr().cast::<u8>(), size as usize) };
31 try_skip_valid::<Element>(bytes, bytes.len() / size_of::<Element>()).is_some()
32}
33
34#[derive(Debug)]
41#[repr(C)]
42pub struct VariableElements<Element, const RECOMMENDED_ALLOCATION: u32 = 0>
43where
44 Element: TrivialType,
45{
46 elements: NonNull<Element>,
47 size: NonNull<u32>,
48 capacity: u32,
49 _supported: [(); NON_ZERO_SIZED::<Element>],
54}
55
56unsafe impl<Element, const RECOMMENDED_ALLOCATION: u32> IoType
58 for VariableElements<Element, RECOMMENDED_ALLOCATION>
59where
60 Element: TrivialType,
61 [(); NON_ZERO_SIZED::<Element>]:,
62{
63 const METADATA: &[u8] = {
64 const fn metadata(
65 recommended_allocation: u32,
66 inner_metadata: &[u8],
67 ) -> ([u8; MAX_METADATA_CAPACITY], usize) {
68 concat_metadata_sources(&[
69 &[IoTypeMetadataKind::VariableElements as u8],
70 &recommended_allocation.to_le_bytes(),
71 inner_metadata,
72 ])
73 }
74
75 let (metadata_scratch, metadata_size) =
77 &metadata(RECOMMENDED_ALLOCATION, Element::METADATA);
78 metadata_scratch.split_at(*metadata_size).0
79 };
80
81 type PointerType = Element;
83
84 #[inline(always)]
85 fn size(&self) -> u32 {
86 self.size()
87 }
88
89 #[inline(always)]
90 fn capacity(&self) -> u32 {
91 self.capacity
92 }
93
94 #[inline(always)]
95 #[track_caller]
96 unsafe fn set_size(&mut self, size: u32) {
97 debug_assert!(
98 size <= self.capacity,
99 "`set_size` called with invalid input {size} for capacity {}",
100 self.capacity
101 );
102 debug_assert!(
103 size.is_multiple_of(Element::SIZE),
104 "`set_size` called with invalid input {size} for element size {}",
105 Element::SIZE
106 );
107
108 unsafe {
110 self.size.write(size);
111 }
112 }
113
114 #[inline(always)]
115 #[track_caller]
116 unsafe fn from_ptr<'a>(
117 ptr: &'a NonNull<Self::PointerType>,
118 size: &'a u32,
119 capacity: u32,
120 ) -> impl Deref<Target = Self> + 'a {
121 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
122 debug_assert!(
123 *size <= capacity,
124 "Size {size} must not exceed capacity {capacity}"
125 );
126 debug_assert!(
127 size.is_multiple_of(Element::SIZE),
128 "Size {size} is invalid for element size {}",
129 Element::SIZE
130 );
131
132 DerefWrapper(Self {
133 elements: *ptr,
134 size: NonNull::from_ref(size),
135 capacity,
136 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
137 })
138 }
139
140 #[inline(always)]
141 #[track_caller]
142 unsafe fn from_mut_ptr<'a>(
143 ptr: &'a mut NonNull<Self::PointerType>,
144 size: &'a mut u32,
145 capacity: u32,
146 ) -> impl DerefMut<Target = Self> + 'a {
147 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
148 debug_assert!(
149 *size <= capacity,
150 "Size {size} must not exceed capacity {capacity}"
151 );
152 debug_assert!(
153 size.is_multiple_of(Element::SIZE),
154 "Size {size} is invalid for element size {}",
155 Element::SIZE
156 );
157
158 DerefWrapper(Self {
159 elements: *ptr,
160 size: NonNull::from_mut(size),
161 capacity,
162 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
163 })
164 }
165
166 #[inline(always)]
167 #[track_caller]
168 unsafe fn try_from_ptr<'a>(
169 ptr: &'a NonNull<Self::PointerType>,
170 size: &'a u32,
171 capacity: u32,
172 ) -> Option<impl Deref<Target = Self> + 'a> {
173 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
174 debug_assert!(
175 *size <= capacity,
176 "Size {size} must not exceed capacity {capacity}"
177 );
178 debug_assert!(
179 size.is_multiple_of(Element::SIZE),
180 "Size {size} is invalid for element size {}",
181 Element::SIZE
182 );
183 if !unsafe { contents_are_valid(*ptr, *size) } {
186 return None;
187 }
188
189 Some(unsafe { Self::from_ptr(ptr, size, capacity) })
193 }
194
195 #[inline(always)]
196 #[track_caller]
197 unsafe fn try_from_mut_ptr<'a>(
198 ptr: &'a mut NonNull<Self::PointerType>,
199 size: &'a mut u32,
200 capacity: u32,
201 ) -> Option<impl DerefMut<Target = Self> + 'a> {
202 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
203 debug_assert!(
204 *size <= capacity,
205 "Size {size} must not exceed capacity {capacity}"
206 );
207 debug_assert!(
208 size.is_multiple_of(Element::SIZE),
209 "Size {size} is invalid for element size {}",
210 Element::SIZE
211 );
212 if !unsafe { contents_are_valid(*ptr, *size) } {
215 return None;
216 }
217
218 Some(unsafe { Self::from_mut_ptr(ptr, size, capacity) })
222 }
223
224 #[inline(always)]
225 fn as_ptr(&self) -> NonNull<Self::PointerType> {
226 self.elements
227 }
228
229 #[inline(always)]
230 fn as_mut_ptr(&mut self) -> NonNull<Self::PointerType> {
231 self.elements
232 }
233}
234
235unsafe impl<Element, const RECOMMENDED_ALLOCATION: u32> IoTypeOptional
238 for VariableElements<Element, RECOMMENDED_ALLOCATION>
239where
240 Element: TrivialType,
241 [(); NON_ZERO_SIZED::<Element>]:,
242{
243}
244
245impl<Element, const RECOMMENDED_ALLOCATION: u32> VariableElements<Element, RECOMMENDED_ALLOCATION>
248where
249 Element: TrivialType,
250 Self: IoType,
251{
252 #[inline(always)]
261 pub const fn from_buffer<'a>(
262 buffer: &'a [Element],
263 size: &'a u32,
264 ) -> Option<impl Deref<Target = Self> + 'a> {
265 if size_of_val(buffer) != *size as usize {
266 return None;
267 }
268
269 Some(DerefWrapper(Self {
270 elements: NonNull::new(buffer.as_ptr().cast_mut()).expect("Not null; qed"),
271 size: NonNull::from_ref(size),
272 capacity: *size,
273 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
274 }))
275 }
276
277 #[inline(always)]
286 pub fn from_buffer_mut<'a>(
287 buffer: &'a mut [Element],
288 size: &'a mut u32,
289 ) -> Option<impl DerefMut<Target = Self> + IoTypeMut<Target = Self> + 'a> {
290 if size_of_val(buffer) != *size as usize {
291 return None;
292 }
293
294 Some(DerefWrapper(Self {
295 elements: NonNull::new(buffer.as_mut_ptr()).expect("Not null; qed"),
296 size: NonNull::from_mut(size),
297 capacity: *size,
298 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
299 }))
300 }
301
302 #[inline(always)]
312 pub fn from_uninit<'a>(
313 uninit: &'a mut [MaybeUninit<Element>],
314 size: &'a mut u32,
315 ) -> Option<impl DerefMut<Target = Self> + IoTypeMut<Target = Self> + 'a> {
316 if *size != 0 {
317 return None;
318 }
319 let capacity = u32::try_from(size_of_val(uninit)).ok()?;
320
321 Some(DerefWrapper(Self {
322 elements: NonNull::new(uninit.as_mut_ptr().cast_init()).expect("Not null; qed"),
323 size: NonNull::from_mut(size),
324 capacity,
325 _supported: const { [(); NON_ZERO_SIZED::<Element>] },
326 }))
327 }
328
329 #[inline(always)]
331 pub const fn size(&self) -> u32 {
332 unsafe { self.size.read() }
334 }
335
336 #[inline(always)]
338 pub fn capacity(&self) -> u32 {
339 self.capacity
340 }
341
342 #[inline(always)]
344 pub const fn count(&self) -> u32 {
345 self.size() / Element::SIZE
346 }
347
348 #[inline(always)]
350 pub const fn get_initialized(&self) -> &[Element] {
351 let size = self.size();
352 let ptr = self.elements.as_ptr();
353 unsafe { slice::from_raw_parts(ptr, (size / Element::SIZE) as usize) }
355 }
356
357 #[inline(always)]
359 pub fn get_initialized_mut(&mut self) -> &mut [Element] {
360 let size = self.size();
361 let ptr = self.elements.as_ptr();
362 unsafe { slice::from_raw_parts_mut(ptr, (size / Element::SIZE) as usize) }
364 }
365
366 #[inline(always)]
370 #[must_use = "Operation may fail"]
371 pub fn append(&mut self, elements: &[Element]) -> bool {
372 let size = self.size();
373 let Some(new_size) = u32::try_from(size_of_val(elements))
374 .ok()
375 .and_then(|appended_size| size.checked_add(appended_size))
376 else {
377 return false;
378 };
379 if new_size > self.capacity {
380 return false;
381 }
382
383 let Ok(offset) = isize::try_from(size / Element::SIZE) else {
385 return false;
386 };
387
388 let start = unsafe { self.elements.offset(offset) };
391 unsafe {
397 ptr::copy_nonoverlapping(elements.as_ptr(), start.as_ptr(), elements.len());
398 self.size.write(new_size);
399 }
400
401 true
402 }
403
404 #[inline(always)]
409 #[must_use = "Operation may fail"]
410 pub fn truncate(&mut self, new_size: u32) -> bool {
411 if new_size > self.size() || !new_size.is_multiple_of(Element::SIZE) {
412 return false;
413 }
414
415 unsafe {
417 self.size.write(new_size);
418 }
419
420 true
421 }
422
423 #[inline(always)]
427 #[must_use = "Operation may fail"]
428 pub fn copy_from(&mut self, src: &Self) -> bool {
429 let src_size = src.size();
430 if src_size > self.capacity {
431 return false;
432 }
433
434 unsafe {
438 self.elements
439 .copy_from_nonoverlapping(src.elements, (src_size / Element::SIZE) as usize);
440 self.size.write(src_size);
441 }
442
443 true
444 }
445
446 #[inline(always)]
449 pub fn cast_ref<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
450 &self,
451 ) -> &VariableElements<Element, DIFFERENT_RECOMMENDED_ALLOCATION> {
452 unsafe {
455 NonNull::from_ref(self)
456 .cast::<VariableElements<Element, DIFFERENT_RECOMMENDED_ALLOCATION>>()
457 .as_ref()
458 }
459 }
460
461 #[inline(always)]
464 pub fn cast_mut<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
465 &mut self,
466 ) -> &mut VariableElements<Element, DIFFERENT_RECOMMENDED_ALLOCATION> {
467 unsafe {
470 NonNull::from_mut(self)
471 .cast::<VariableElements<Element, DIFFERENT_RECOMMENDED_ALLOCATION>>()
472 .as_mut()
473 }
474 }
475
476 #[inline(always)]
484 #[must_use = "Operation may fail"]
485 pub unsafe fn assume_init(&mut self, size: u32) -> Option<&mut [Element]> {
486 if size > self.capacity || !size.is_multiple_of(Element::SIZE) {
487 return None;
488 }
489
490 unsafe {
492 self.size.write(size);
493 }
494 Some(self.get_initialized_mut())
495 }
496}