1use super::VarZeroVecFormatError;
6use crate::ule::*;
7use core::cmp::Ordering;
8use core::convert::TryFrom;
9use core::marker::PhantomData;
10use core::mem;
11use core::ops::Range;
12
13pub trait VarZeroVecFormat: 'static + Sized {
23 #[doc(hidden)]
27 type Index: IntegerULE;
28 #[doc(hidden)]
32 type Len: IntegerULE;
33}
34
35#[doc(hidden)]
40pub unsafe trait IntegerULE: ULE {
41 #[doc(hidden)]
43 const TOO_LARGE_ERROR: &'static str;
44
45 #[doc(hidden)]
47 const SIZE: usize;
48
49 #[doc(hidden)]
51 const MAX_VALUE: u32;
52
53 #[doc(hidden)]
56 fn iule_to_usize(self) -> usize;
57
58 #[doc(hidden)]
59 fn iule_from_usize(x: usize) -> Option<Self>;
60
61 #[doc(hidden)]
63 #[cfg(feature = "alloc")]
64 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self];
65}
66
67#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
73#[allow(clippy::exhaustive_structs)] pub struct Index8;
75
76#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
83#[allow(clippy::exhaustive_structs)] pub struct Index16;
85
86#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
90#[allow(clippy::exhaustive_structs)] pub struct Index32;
92
93impl VarZeroVecFormat for Index8 {
94 type Index = u8;
95 type Len = u8;
96}
97
98impl VarZeroVecFormat for Index16 {
99 type Index = RawBytesULE<2>;
100 type Len = RawBytesULE<2>;
101}
102
103impl VarZeroVecFormat for Index32 {
104 type Index = RawBytesULE<4>;
105 type Len = RawBytesULE<4>;
106}
107
108unsafe impl IntegerULE for u8 {
109 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
110 cumulatively are larger than a u8 in size";
111 const SIZE: usize = mem::size_of::<Self>();
112 const MAX_VALUE: u32 = u8::MAX as u32;
113 #[inline]
114 fn iule_to_usize(self) -> usize {
115 self as usize
116 }
117 #[inline]
118 fn iule_from_usize(u: usize) -> Option<Self> {
119 u8::try_from(u).ok()
120 }
121 #[inline]
122 #[cfg(feature = "alloc")]
123 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
124 bytes
125 }
126}
127
128unsafe impl IntegerULE for RawBytesULE<2> {
129 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
130 cumulatively are larger than a u16 in size";
131 const SIZE: usize = mem::size_of::<Self>();
132 const MAX_VALUE: u32 = u16::MAX as u32;
133 #[inline]
134 fn iule_to_usize(self) -> usize {
135 self.as_unsigned_int() as usize
136 }
137 #[inline]
138 fn iule_from_usize(u: usize) -> Option<Self> {
139 u16::try_from(u).ok().map(u16::to_unaligned)
140 }
141 #[inline]
142 #[cfg(feature = "alloc")]
143 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
144 Self::from_bytes_unchecked_mut(bytes)
145 }
146}
147
148unsafe impl IntegerULE for RawBytesULE<4> {
149 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
150 cumulatively are larger than a u32 in size";
151 const SIZE: usize = mem::size_of::<Self>();
152 const MAX_VALUE: u32 = u32::MAX;
153 #[inline]
154 fn iule_to_usize(self) -> usize {
155 self.as_unsigned_int() as usize
156 }
157 #[inline]
158 fn iule_from_usize(u: usize) -> Option<Self> {
159 u32::try_from(u).ok().map(u32::to_unaligned)
160 }
161 #[inline]
162 #[cfg(feature = "alloc")]
163 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
164 Self::from_bytes_unchecked_mut(bytes)
165 }
166}
167
168#[derive(Debug)]
178pub struct VarZeroVecComponents<'a, T: ?Sized, F> {
179 len: u32,
181 indices: &'a [u8],
184 things: &'a [u8],
186 marker: PhantomData<(&'a T, F)>,
187}
188
189impl<'a, T: ?Sized, F> Copy for VarZeroVecComponents<'a, T, F> {}
192impl<'a, T: ?Sized, F> Clone for VarZeroVecComponents<'a, T, F> {
193 fn clone(&self) -> Self {
194 *self
195 }
196}
197
198impl<'a, T: VarULE + ?Sized, F> Default for VarZeroVecComponents<'a, T, F> {
199 #[inline]
200 fn default() -> Self {
201 Self::new()
202 }
203}
204
205impl<'a, T: VarULE + ?Sized, F> VarZeroVecComponents<'a, T, F> {
206 #[inline]
207 pub fn new() -> Self {
208 Self {
209 len: 0,
210 indices: &[],
211 things: &[],
212 marker: PhantomData,
213 }
214 }
215}
216impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F> {
217 #[inline]
228 pub fn parse_bytes(slice: &'a [u8]) -> Result<Self, VarZeroVecFormatError> {
229 if slice.is_empty() {
231 return Ok(VarZeroVecComponents {
232 len: 0,
233 indices: &[],
234 things: &[],
235 marker: PhantomData,
236 });
237 }
238 let len_bytes = slice
239 .get(0..F::Len::SIZE)
240 .ok_or(VarZeroVecFormatError::Metadata)?;
241 let len_ule =
242 F::Len::parse_bytes_to_slice(len_bytes).map_err(|_| VarZeroVecFormatError::Metadata)?;
243
244 let len = len_ule
245 .first()
246 .ok_or(VarZeroVecFormatError::Metadata)?
247 .iule_to_usize();
248
249 let rest = slice
250 .get(F::Len::SIZE..)
251 .ok_or(VarZeroVecFormatError::Metadata)?;
252 let len_u32 = u32::try_from(len).map_err(|_| VarZeroVecFormatError::Metadata);
253 Self::parse_bytes_with_length(len_u32?, rest)
255 }
256
257 #[inline]
265 pub fn parse_bytes_with_length(
266 len: u32,
267 slice: &'a [u8],
268 ) -> Result<Self, VarZeroVecFormatError> {
269 let len_minus_one = len.checked_sub(1);
270 let Some(len_minus_one) = len_minus_one else {
272 return Ok(VarZeroVecComponents {
273 len: 0,
274 indices: &[],
275 things: &[],
276 marker: PhantomData,
277 });
278 };
279 let indices_bytes = slice
282 .get(..F::Index::SIZE * (len_minus_one as usize))
283 .ok_or(VarZeroVecFormatError::Metadata)?;
284 let things = slice
285 .get(F::Index::SIZE * (len_minus_one as usize)..)
286 .ok_or(VarZeroVecFormatError::Metadata)?;
287
288 let borrowed = VarZeroVecComponents {
289 len,
290 indices: indices_bytes,
291 things,
292 marker: PhantomData,
293 };
294
295 borrowed.check_indices_and_things()?;
296
297 Ok(borrowed)
298 }
299
300 pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
309 if slice.is_empty() {
311 return VarZeroVecComponents {
312 len: 0,
313 indices: &[],
314 things: &[],
315 marker: PhantomData,
316 };
317 }
318 let (len_bytes, data_bytes) = unsafe { slice.split_at_unchecked(F::Len::SIZE) };
319 let len_ule = F::Len::slice_from_bytes_unchecked(len_bytes);
321
322 let len = len_ule.get_unchecked(0).iule_to_usize();
323 let len_u32 = len as u32;
324
325 Self::from_bytes_unchecked_with_length(len_u32, data_bytes)
330 }
331
332 pub unsafe fn from_bytes_unchecked_with_length(len: u32, slice: &'a [u8]) -> Self {
341 let len_minus_one = len.checked_sub(1);
342 let Some(len_minus_one) = len_minus_one else {
344 return VarZeroVecComponents {
345 len: 0,
346 indices: &[],
347 things: &[],
348 marker: PhantomData,
349 };
350 };
351 let indices_bytes = slice.get_unchecked(..F::Index::SIZE * (len_minus_one as usize));
354 let things = slice.get_unchecked(F::Index::SIZE * (len_minus_one as usize)..);
355
356 VarZeroVecComponents {
357 len,
358 indices: indices_bytes,
359 things,
360 marker: PhantomData,
361 }
362 }
363
364 #[inline]
366 pub fn len(self) -> usize {
367 self.len as usize
368 }
369
370 #[inline]
372 pub fn is_empty(self) -> bool {
373 self.len == 0
374 }
375
376 #[inline]
378 pub fn get(self, idx: usize) -> Option<&'a T> {
379 if idx >= self.len() {
380 return None;
381 }
382 Some(unsafe { self.get_unchecked(idx) })
383 }
384
385 #[inline]
390 pub(crate) unsafe fn get_unchecked(self, idx: usize) -> &'a T {
391 let range = self.get_things_range(idx);
392 let things_slice = self.things.get_unchecked(range);
393 T::from_bytes_unchecked(things_slice)
394 }
395
396 #[inline]
401 pub(crate) unsafe fn get_things_range(self, idx: usize) -> Range<usize> {
402 let start = if let Some(idx_minus_one) = idx.checked_sub(1) {
403 self.indices_slice()
404 .get_unchecked(idx_minus_one)
405 .iule_to_usize()
406 } else {
407 0
408 };
409 let end = if idx + 1 == self.len() {
410 self.things.len()
411 } else {
412 self.indices_slice().get_unchecked(idx).iule_to_usize()
413 };
414 debug_assert!(start <= end);
415 start..end
416 }
417
418 pub(crate) unsafe fn get_indices_size(self) -> usize {
420 self.indices.len()
421 }
422
423 #[inline]
434 #[expect(clippy::len_zero)] fn check_indices_and_things(self) -> Result<(), VarZeroVecFormatError> {
436 if self.len() == 0 {
437 if self.things.len() > 0 {
438 return Err(VarZeroVecFormatError::Metadata);
439 } else {
440 return Ok(());
441 }
442 }
443 let indices_slice = self.indices_slice();
444 assert_eq!(self.len(), indices_slice.len() + 1);
445 let mut start = 0;
447 for i in 0..self.len() {
448 let end = if let Some(end) = indices_slice.get(i) {
452 end.iule_to_usize()
453 } else {
454 self.things.len()
458 };
459
460 if start > end {
461 return Err(VarZeroVecFormatError::Metadata);
462 }
463 if end > self.things.len() {
464 return Err(VarZeroVecFormatError::Metadata);
465 }
466 let bytes = unsafe { self.things.get_unchecked(start..end) };
468 T::parse_bytes(bytes).map_err(VarZeroVecFormatError::Values)?;
469 start = end;
470 }
471 Ok(())
472 }
473
474 #[inline]
476 pub fn iter(self) -> VarZeroSliceIter<'a, T, F> {
477 VarZeroSliceIter::new(self)
478 }
479
480 #[cfg(feature = "alloc")]
481 pub fn to_vec(self) -> alloc::vec::Vec<alloc::boxed::Box<T>> {
482 self.iter().map(T::to_boxed).collect()
483 }
484
485 #[inline]
486 fn indices_slice(&self) -> &'a [F::Index] {
487 unsafe { F::Index::slice_from_bytes_unchecked(self.indices) }
488 }
489
490 #[allow(unused)] #[cfg(feature = "alloc")]
493 pub(crate) fn dump(&self) -> alloc::string::String {
494 let indices = self
495 .indices_slice()
496 .iter()
497 .copied()
498 .map(IntegerULE::iule_to_usize)
499 .collect::<alloc::vec::Vec<_>>();
500 alloc::format!("VarZeroVecComponents {{ indices: {indices:?} }}")
501 }
502}
503
504#[derive(Debug)]
506pub struct VarZeroSliceIter<'a, T: ?Sized, F = Index16> {
507 components: VarZeroVecComponents<'a, T, F>,
508 index: usize,
509 start_index: usize,
514}
515
516impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroSliceIter<'a, T, F> {
517 fn new(c: VarZeroVecComponents<'a, T, F>) -> Self {
518 Self {
519 components: c,
520 index: 0,
521 start_index: 0,
523 }
524 }
525}
526impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> Iterator for VarZeroSliceIter<'a, T, F> {
527 type Item = &'a T;
528
529 fn next(&mut self) -> Option<Self::Item> {
530 if self.index >= self.components.len() {
534 return None;
535 }
536
537 let end = if self.index + 1 == self.components.len() {
541 self.components.things.len()
543 } else {
544 unsafe {
546 self.components
547 .indices_slice()
548 .get_unchecked(self.index)
549 .iule_to_usize()
550 }
551 };
552 let item = unsafe {
556 T::from_bytes_unchecked(self.components.things.get_unchecked(self.start_index..end))
559 };
560 self.index += 1;
561 self.start_index = end;
563 Some(item)
564 }
565
566 fn size_hint(&self) -> (usize, Option<usize>) {
567 let remainder = self.components.len() - self.index;
568 (remainder, Some(remainder))
569 }
570}
571
572impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> ExactSizeIterator for VarZeroSliceIter<'a, T, F> {
573 fn len(&self) -> usize {
574 self.components.len() - self.index
575 }
576}
577
578impl<'a, T, F> VarZeroVecComponents<'a, T, F>
579where
580 T: VarULE,
581 T: ?Sized,
582 T: Ord,
583 F: VarZeroVecFormat,
584{
585 pub fn binary_search(&self, needle: &T) -> Result<usize, usize> {
588 self.binary_search_by(|probe| probe.cmp(needle))
589 }
590
591 pub fn binary_search_in_range(
592 &self,
593 needle: &T,
594 range: Range<usize>,
595 ) -> Option<Result<usize, usize>> {
596 self.binary_search_in_range_by(|probe| probe.cmp(needle), range)
597 }
598}
599
600impl<'a, T, F> VarZeroVecComponents<'a, T, F>
601where
602 T: VarULE,
603 T: ?Sized,
604 F: VarZeroVecFormat,
605{
606 pub fn binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> {
609 unsafe { self.binary_search_in_range_unchecked(predicate, 0..self.len()) }
611 }
612
613 pub fn binary_search_in_range_by(
616 &self,
617 predicate: impl FnMut(&T) -> Ordering,
618 range: Range<usize>,
619 ) -> Option<Result<usize, usize>> {
620 if range.end > self.len() {
621 return None;
622 }
623 if range.end < range.start {
624 return None;
625 }
626 let range_absolute =
628 unsafe { self.binary_search_in_range_unchecked(predicate, range.clone()) };
629 Some(
631 range_absolute
632 .map(|o| o - range.start)
633 .map_err(|e| e - range.start),
634 )
635 }
636
637 unsafe fn binary_search_in_range_unchecked(
639 &self,
640 mut predicate: impl FnMut(&T) -> Ordering,
641 range: Range<usize>,
642 ) -> Result<usize, usize> {
643 let mut start = range.start;
645 let mut end = range.end;
646 let mut size;
647
648 while start < end {
651 size = end - start;
652 let mid = start + size / 2;
656
657 let cmp = predicate(self.get_unchecked(mid));
659
660 match cmp {
661 Ordering::Less => {
662 start = mid + 1;
666 }
667 Ordering::Greater => {
668 end = mid;
672 }
673 Ordering::Equal => return Ok(mid),
674 }
675 }
676 Err(start)
677 }
678}
679
680#[cfg(feature = "alloc")]
682pub fn get_serializable_bytes_non_empty<T, A, F>(elements: &[A]) -> Option<alloc::vec::Vec<u8>>
683where
684 T: VarULE + ?Sized,
685 A: EncodeAsVarULE<T>,
686 F: VarZeroVecFormat,
687{
688 debug_assert!(!elements.is_empty());
689 let len = compute_serializable_len::<T, A, F>(elements)?;
690 debug_assert!(
691 len >= F::Len::SIZE as u32,
692 "Must have at least F::Len::SIZE bytes to hold the length of the vector"
693 );
694 let mut output = alloc::vec![0u8; len as usize];
695 write_serializable_bytes::<T, A, F>(elements, &mut output);
696 Some(output)
697}
698
699pub fn write_serializable_bytes_without_length<T, A, F>(elements: &[A], output: &mut [u8])
708where
709 T: VarULE + ?Sized,
710 A: EncodeAsVarULE<T>,
711 F: VarZeroVecFormat,
712{
713 assert!(elements.len() <= F::Len::MAX_VALUE as usize);
714 if elements.is_empty() {
715 return;
716 }
717
718 let mut idx_offset: usize = 0;
720 let first_dat_offset: usize = idx_offset + (elements.len() - 1) * F::Index::SIZE;
722 let mut dat_offset: usize = first_dat_offset;
724
725 for (i, element) in elements.iter().enumerate() {
726 let element_len = element.encode_var_ule_len();
727
728 if i != 0 {
730 let idx_limit = idx_offset + F::Index::SIZE;
731 #[expect(clippy::indexing_slicing)] let idx_slice = &mut output[idx_offset..idx_limit];
733 let idx = dat_offset - first_dat_offset;
735 assert!(idx <= F::Index::MAX_VALUE as usize);
736 #[expect(clippy::expect_used)] let bytes_to_write = F::Index::iule_from_usize(idx).expect(F::Index::TOO_LARGE_ERROR);
738 idx_slice.copy_from_slice(ULE::slice_as_bytes(&[bytes_to_write]));
739
740 idx_offset = idx_limit;
741 }
742
743 let dat_limit = dat_offset + element_len;
744 #[expect(clippy::indexing_slicing)] let dat_slice = &mut output[dat_offset..dat_limit];
746 element.encode_var_ule_write(dat_slice);
747 debug_assert_eq!(T::validate_bytes(dat_slice), Ok(()));
748 dat_offset = dat_limit;
749 }
750
751 debug_assert_eq!(idx_offset, F::Index::SIZE * (elements.len() - 1));
752 assert_eq!(dat_offset, output.len());
753}
754
755pub fn write_serializable_bytes<T, A, F>(elements: &[A], output: &mut [u8])
763where
764 T: VarULE + ?Sized,
765 A: EncodeAsVarULE<T>,
766 F: VarZeroVecFormat,
767{
768 if elements.is_empty() {
769 return;
770 }
771 assert!(elements.len() <= F::Len::MAX_VALUE as usize);
772 #[expect(clippy::expect_used)] let num_elements_ule = F::Len::iule_from_usize(elements.len()).expect(F::Len::TOO_LARGE_ERROR);
774 #[expect(clippy::indexing_slicing)] output[0..F::Len::SIZE].copy_from_slice(ULE::slice_as_bytes(&[num_elements_ule]));
776
777 #[expect(clippy::indexing_slicing)] write_serializable_bytes_without_length::<T, A, F>(elements, &mut output[F::Len::SIZE..]);
779}
780
781pub fn compute_serializable_len_without_length<T, A, F>(elements: &[A]) -> Option<u32>
782where
783 T: VarULE + ?Sized,
784 A: EncodeAsVarULE<T>,
785 F: VarZeroVecFormat,
786{
787 let elements_len = elements.len();
788 let Some(elements_len_minus_one) = elements_len.checked_sub(1) else {
789 return Some(0);
791 };
792 let idx_len: u32 = u32::try_from(elements_len_minus_one)
793 .ok()?
794 .checked_mul(F::Index::SIZE as u32)?;
795 let data_len: u32 = elements
796 .iter()
797 .map(|v| u32::try_from(v.encode_var_ule_len()).ok())
798 .try_fold(0u32, |s, v| s.checked_add(v?))?;
799 let ret = idx_len.checked_add(data_len);
800 if let Some(r) = ret {
801 if r >= F::Index::MAX_VALUE {
802 return None;
803 }
804 }
805 ret
806}
807
808pub fn compute_serializable_len<T, A, F>(elements: &[A]) -> Option<u32>
809where
810 T: VarULE + ?Sized,
811 A: EncodeAsVarULE<T>,
812 F: VarZeroVecFormat,
813{
814 compute_serializable_len_without_length::<T, A, F>(elements).map(|x| x + F::Len::SIZE as u32)
815}