1#![allow(unused_qualifications)]
6
7use super::VarZeroVecFormatError;
8use crate::ule::*;
9use core::cmp::Ordering;
10use core::convert::TryFrom;
11use core::marker::PhantomData;
12use core::ops::Range;
13
14pub trait VarZeroVecFormat: 'static + Sized {
24 #[doc(hidden)]
28 type Index: IntegerULE;
29 #[doc(hidden)]
33 type Len: IntegerULE;
34}
35
36#[doc(hidden)]
41pub unsafe trait IntegerULE: ULE {
42 #[doc(hidden)]
44 const TOO_LARGE_ERROR: &'static str;
45
46 #[doc(hidden)]
48 const SIZE: usize;
49
50 #[doc(hidden)]
52 const MAX_VALUE: u32;
53
54 #[doc(hidden)]
57 fn iule_to_usize(self) -> usize;
58
59 #[doc(hidden)]
60 fn iule_from_usize(x: usize) -> Option<Self>;
61
62 #[doc(hidden)]
64 #[cfg(feature = "alloc")]
65 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self];
66}
67
68#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
74#[allow(clippy::exhaustive_structs)] pub struct Index8;
76
77#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
84#[allow(clippy::exhaustive_structs)] pub struct Index16;
86
87#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
91#[allow(clippy::exhaustive_structs)] pub struct Index32;
93
94impl VarZeroVecFormat for Index8 {
95 type Index = u8;
96 type Len = u8;
97}
98
99impl VarZeroVecFormat for Index16 {
100 type Index = RawBytesULE<2>;
101 type Len = RawBytesULE<2>;
102}
103
104impl VarZeroVecFormat for Index32 {
105 type Index = RawBytesULE<4>;
106 type Len = RawBytesULE<4>;
107}
108
109unsafe impl IntegerULE for u8 {
110 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
111 cumulatively are larger than a u8 in size";
112 const SIZE: usize = size_of::<Self>();
113 const MAX_VALUE: u32 = u8::MAX as u32;
114 #[inline]
115 fn iule_to_usize(self) -> usize {
116 self as usize
117 }
118 #[inline]
119 fn iule_from_usize(u: usize) -> Option<Self> {
120 u8::try_from(u).ok()
121 }
122 #[inline]
123 #[cfg(feature = "alloc")]
124 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
125 bytes
126 }
127}
128
129unsafe impl IntegerULE for RawBytesULE<2> {
130 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
131 cumulatively are larger than a u16 in size";
132 const SIZE: usize = size_of::<Self>();
133 const MAX_VALUE: u32 = u16::MAX as u32;
134 #[inline]
135 fn iule_to_usize(self) -> usize {
136 self.as_unsigned_int() as usize
137 }
138 #[inline]
139 fn iule_from_usize(u: usize) -> Option<Self> {
140 u16::try_from(u).ok().map(u16::to_unaligned)
141 }
142 #[inline]
143 #[cfg(feature = "alloc")]
144 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
145 Self::from_bytes_unchecked_mut(bytes)
146 }
147}
148
149unsafe impl IntegerULE for RawBytesULE<4> {
150 const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
151 cumulatively are larger than a u32 in size";
152 const SIZE: usize = size_of::<Self>();
153 const MAX_VALUE: u32 = u32::MAX;
154 #[inline]
155 fn iule_to_usize(self) -> usize {
156 self.as_unsigned_int() as usize
157 }
158 #[inline]
159 fn iule_from_usize(u: usize) -> Option<Self> {
160 u32::try_from(u).ok().map(u32::to_unaligned)
161 }
162 #[inline]
163 #[cfg(feature = "alloc")]
164 fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
165 Self::from_bytes_unchecked_mut(bytes)
166 }
167}
168
169#[derive(Debug)]
179pub struct VarZeroVecComponents<'a, T: ?Sized, F> {
180 len: u32,
182 indices: &'a [u8],
185 things: &'a [u8],
187 marker: PhantomData<(&'a T, F)>,
188}
189
190impl<'a, T: ?Sized, F> Copy for VarZeroVecComponents<'a, T, F> {}
193impl<'a, T: ?Sized, F> Clone for VarZeroVecComponents<'a, T, F> {
194 fn clone(&self) -> Self {
195 *self
196 }
197}
198
199impl<'a, T: VarULE + ?Sized, F> Default for VarZeroVecComponents<'a, T, F> {
200 #[inline]
201 fn default() -> Self {
202 Self::new()
203 }
204}
205
206impl<'a, T: VarULE + ?Sized, F> VarZeroVecComponents<'a, T, F> {
207 #[inline]
208 pub fn new() -> Self {
209 Self {
210 len: 0,
211 indices: &[],
212 things: &[],
213 marker: PhantomData,
214 }
215 }
216}
217impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F> {
218 #[inline]
229 pub fn parse_bytes(slice: &'a [u8]) -> Result<Self, VarZeroVecFormatError> {
230 if slice.is_empty() {
232 return Ok(VarZeroVecComponents {
233 len: 0,
234 indices: &[],
235 things: &[],
236 marker: PhantomData,
237 });
238 }
239 let len_bytes = slice
240 .get(0..F::Len::SIZE)
241 .ok_or(VarZeroVecFormatError::Metadata)?;
242 let len_ule =
243 F::Len::parse_bytes_to_slice(len_bytes).map_err(|_| VarZeroVecFormatError::Metadata)?;
244
245 let len = len_ule
246 .first()
247 .ok_or(VarZeroVecFormatError::Metadata)?
248 .iule_to_usize();
249
250 let rest = slice
251 .get(F::Len::SIZE..)
252 .ok_or(VarZeroVecFormatError::Metadata)?;
253 let len_u32 = u32::try_from(len).map_err(|_| VarZeroVecFormatError::Metadata);
254 Self::parse_bytes_with_length(len_u32?, rest)
256 }
257
258 #[inline]
266 pub fn parse_bytes_with_length(
267 len: u32,
268 slice: &'a [u8],
269 ) -> Result<Self, VarZeroVecFormatError> {
270 let len_minus_one = len.checked_sub(1);
271 let Some(len_minus_one) = len_minus_one else {
273 return Ok(VarZeroVecComponents {
274 len: 0,
275 indices: &[],
276 things: &[],
277 marker: PhantomData,
278 });
279 };
280 let indices_len = u32::try_from(F::Index::SIZE)
286 .ok()
287 .and_then(|x| x.checked_mul(len_minus_one))
288 .and_then(|x| usize::try_from(x).ok())
289 .ok_or(VarZeroVecFormatError::Metadata)?;
290 let indices_bytes = slice
291 .get(..indices_len)
292 .ok_or(VarZeroVecFormatError::Metadata)?;
293 let things = slice
294 .get(indices_len..)
295 .ok_or(VarZeroVecFormatError::Metadata)?;
296
297 let borrowed = VarZeroVecComponents {
298 len,
299 indices: indices_bytes,
300 things,
301 marker: PhantomData,
302 };
303
304 borrowed.check_indices_and_things()?;
305
306 Ok(borrowed)
307 }
308
309 pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
318 if slice.is_empty() {
320 return VarZeroVecComponents {
321 len: 0,
322 indices: &[],
323 things: &[],
324 marker: PhantomData,
325 };
326 }
327 let (len_bytes, data_bytes) = unsafe { slice.split_at_unchecked(F::Len::SIZE) };
328 let len_ule = F::Len::slice_from_bytes_unchecked(len_bytes);
330
331 let len = len_ule.get_unchecked(0).iule_to_usize();
332 let len_u32 = len as u32;
333 debug_assert_eq!(len, len_u32 as usize);
334
335 Self::from_bytes_unchecked_with_length(len_u32, data_bytes)
340 }
341
342 pub unsafe fn from_bytes_unchecked_with_length(len: u32, slice: &'a [u8]) -> Self {
351 let len_minus_one = len.checked_sub(1);
352 let Some(len_minus_one) = len_minus_one else {
354 return VarZeroVecComponents {
355 len: 0,
356 indices: &[],
357 things: &[],
358 marker: PhantomData,
359 };
360 };
361 let indices_len = F::Index::SIZE.wrapping_mul(len_minus_one as usize);
364 debug_assert!(F::Index::SIZE.checked_mul(len_minus_one as usize).is_some());
365 let indices_bytes = slice.get_unchecked(..indices_len);
366 let things = slice.get_unchecked(indices_len..);
367
368 VarZeroVecComponents {
369 len,
370 indices: indices_bytes,
371 things,
372 marker: PhantomData,
373 }
374 }
375
376 #[inline]
378 pub fn len(self) -> usize {
379 self.len as usize
380 }
381
382 #[inline]
384 pub fn is_empty(self) -> bool {
385 self.len == 0
386 }
387
388 #[inline]
390 pub fn get(self, idx: usize) -> Option<&'a T> {
391 if idx >= self.len() {
392 return None;
393 }
394 Some(unsafe { self.get_unchecked(idx) })
395 }
396
397 #[inline]
402 pub(crate) unsafe fn get_unchecked(self, idx: usize) -> &'a T {
403 let range = self.get_things_range(idx);
404 let things_slice = self.things.get_unchecked(range);
405 T::from_bytes_unchecked(things_slice)
406 }
407
408 #[inline]
413 pub(crate) unsafe fn get_things_range(self, idx: usize) -> Range<usize> {
414 let start = if let Some(idx_minus_one) = idx.checked_sub(1) {
415 self.indices_slice()
416 .get_unchecked(idx_minus_one)
417 .iule_to_usize()
418 } else {
419 0
420 };
421 let end = if idx + 1 == self.len() {
422 self.things.len()
423 } else {
424 self.indices_slice().get_unchecked(idx).iule_to_usize()
425 };
426 debug_assert!(start <= end);
427 start..end
428 }
429
430 pub(crate) unsafe fn get_indices_size(self) -> usize {
432 self.indices.len()
433 }
434
435 #[inline]
446 #[expect(clippy::len_zero)] fn check_indices_and_things(self) -> Result<(), VarZeroVecFormatError> {
448 if self.len() == 0 {
449 if self.things.len() > 0 {
450 return Err(VarZeroVecFormatError::Metadata);
451 } else {
452 return Ok(());
453 }
454 }
455 let indices_slice = self.indices_slice();
456 assert_eq!(self.len(), indices_slice.len() + 1);
457 let mut start = 0;
459 for i in 0..self.len() {
460 let end = if let Some(end) = indices_slice.get(i) {
464 end.iule_to_usize()
465 } else {
466 self.things.len()
470 };
471
472 if start > end {
473 return Err(VarZeroVecFormatError::Metadata);
474 }
475 if end > self.things.len() {
476 return Err(VarZeroVecFormatError::Metadata);
477 }
478 let bytes = unsafe { self.things.get_unchecked(start..end) };
480 T::parse_bytes(bytes).map_err(VarZeroVecFormatError::Values)?;
481 start = end;
482 }
483 Ok(())
484 }
485
486 #[inline]
488 pub fn iter(self) -> VarZeroSliceIter<'a, T, F> {
489 VarZeroSliceIter::new(self)
490 }
491
492 #[cfg(feature = "alloc")]
493 pub fn to_vec(self) -> alloc::vec::Vec<alloc::boxed::Box<T>> {
494 self.iter().map(T::to_boxed).collect()
495 }
496
497 #[inline]
498 fn indices_slice(&self) -> &'a [F::Index] {
499 unsafe { F::Index::slice_from_bytes_unchecked(self.indices) }
500 }
501
502 #[allow(unused)] #[cfg(feature = "alloc")]
505 pub(crate) fn dump(&self) -> alloc::string::String {
506 let indices = self
507 .indices_slice()
508 .iter()
509 .copied()
510 .map(IntegerULE::iule_to_usize)
511 .collect::<alloc::vec::Vec<_>>();
512 alloc::format!("VarZeroVecComponents {{ indices: {indices:?} }}")
513 }
514}
515
516#[derive(Debug)]
518pub struct VarZeroSliceIter<'a, T: ?Sized, F = Index16> {
519 components: VarZeroVecComponents<'a, T, F>,
520 index: usize,
521 start_index: usize,
526}
527
528impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> Clone for VarZeroSliceIter<'a, T, F> {
529 fn clone(&self) -> Self {
530 Self {
531 components: self.components,
532 index: self.index,
533 start_index: self.start_index,
534 }
535 }
536}
537
538impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroSliceIter<'a, T, F> {
539 fn new(c: VarZeroVecComponents<'a, T, F>) -> Self {
540 Self {
541 components: c,
542 index: 0,
543 start_index: 0,
545 }
546 }
547}
548impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> Iterator for VarZeroSliceIter<'a, T, F> {
549 type Item = &'a T;
550
551 fn next(&mut self) -> Option<Self::Item> {
552 if self.index >= self.components.len() {
556 return None;
557 }
558
559 let end = if self.index + 1 == self.components.len() {
563 self.components.things.len()
565 } else {
566 unsafe {
568 self.components
569 .indices_slice()
570 .get_unchecked(self.index)
571 .iule_to_usize()
572 }
573 };
574 let item = unsafe {
578 T::from_bytes_unchecked(self.components.things.get_unchecked(self.start_index..end))
581 };
582 self.index += 1;
583 self.start_index = end;
585 Some(item)
586 }
587
588 fn size_hint(&self) -> (usize, Option<usize>) {
589 let remainder = self.components.len() - self.index;
590 (remainder, Some(remainder))
591 }
592}
593
594impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> ExactSizeIterator for VarZeroSliceIter<'a, T, F> {
595 fn len(&self) -> usize {
596 self.components.len() - self.index
597 }
598}
599
600impl<'a, T, F> VarZeroVecComponents<'a, T, F>
601where
602 T: VarULE,
603 T: ?Sized,
604 T: Ord,
605 F: VarZeroVecFormat,
606{
607 pub fn binary_search(&self, needle: &T) -> Result<usize, usize> {
610 self.binary_search_by(|probe| probe.cmp(needle))
611 }
612
613 pub fn binary_search_in_range(
614 &self,
615 needle: &T,
616 range: Range<usize>,
617 ) -> Option<Result<usize, usize>> {
618 self.binary_search_in_range_by(|probe| probe.cmp(needle), range)
619 }
620}
621
622impl<'a, T, F> VarZeroVecComponents<'a, T, F>
623where
624 T: VarULE,
625 T: ?Sized,
626 F: VarZeroVecFormat,
627{
628 pub fn binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> {
631 unsafe { self.binary_search_in_range_unchecked(predicate, 0..self.len()) }
633 }
634
635 pub fn binary_search_in_range_by(
638 &self,
639 predicate: impl FnMut(&T) -> Ordering,
640 range: Range<usize>,
641 ) -> Option<Result<usize, usize>> {
642 if range.end > self.len() {
643 return None;
644 }
645 if range.end < range.start {
646 return None;
647 }
648 let range_absolute =
650 unsafe { self.binary_search_in_range_unchecked(predicate, range.clone()) };
651 Some(
653 range_absolute
654 .map(|o| o - range.start)
655 .map_err(|e| e - range.start),
656 )
657 }
658
659 unsafe fn binary_search_in_range_unchecked(
661 &self,
662 mut predicate: impl FnMut(&T) -> Ordering,
663 range: Range<usize>,
664 ) -> Result<usize, usize> {
665 let mut start = range.start;
667 let mut end = range.end;
668 let mut size;
669
670 while start < end {
673 size = end - start;
674 let mid = start + size / 2;
678
679 let cmp = predicate(self.get_unchecked(mid));
681
682 match cmp {
683 Ordering::Less => {
684 start = mid + 1;
688 }
689 Ordering::Greater => {
690 end = mid;
694 }
695 Ordering::Equal => return Ok(mid),
696 }
697 }
698 Err(start)
699 }
700}
701
702#[cfg(feature = "alloc")]
704pub fn get_serializable_bytes_non_empty<T, A, F>(elements: &[A]) -> Option<alloc::vec::Vec<u8>>
705where
706 T: VarULE + ?Sized,
707 A: EncodeAsVarULE<T>,
708 F: VarZeroVecFormat,
709{
710 debug_assert!(!elements.is_empty());
711 let len = compute_serializable_len::<T, A, F>(elements)?;
712 debug_assert!(
713 len >= F::Len::SIZE as u32,
714 "Must have at least F::Len::SIZE bytes to hold the length of the vector"
715 );
716 let mut output = alloc::vec![0u8; len as usize];
717 write_serializable_bytes::<T, A, F>(elements, &mut output);
718 Some(output)
719}
720
721pub fn write_serializable_bytes_without_length<T, A, F>(elements: &[A], output: &mut [u8])
730where
731 T: VarULE + ?Sized,
732 A: EncodeAsVarULE<T>,
733 F: VarZeroVecFormat,
734{
735 assert!(elements.len() <= F::Len::MAX_VALUE as usize);
736 if elements.is_empty() {
737 return;
738 }
739
740 let mut idx_offset: usize = 0;
742 #[expect(
744 clippy::expect_used,
745 reason = "Function contract allows panicky behavior"
746 )]
747 let indices_size = F::Index::SIZE
748 .checked_mul(elements.len() - 1)
749 .expect(F::Index::TOO_LARGE_ERROR);
750 let first_dat_offset: usize = idx_offset + indices_size;
751 let mut dat_offset: usize = first_dat_offset;
753
754 for (i, element) in elements.iter().enumerate() {
755 let element_len = element.encode_var_ule_len();
756
757 if i != 0 {
759 let idx_limit = idx_offset + F::Index::SIZE;
760 #[expect(clippy::indexing_slicing)] let idx_slice = &mut output[idx_offset..idx_limit];
762 let idx = dat_offset - first_dat_offset;
764 assert!(idx <= F::Index::MAX_VALUE as usize);
765 #[expect(clippy::expect_used)] let bytes_to_write = F::Index::iule_from_usize(idx).expect(F::Index::TOO_LARGE_ERROR);
767 idx_slice.copy_from_slice(ULE::slice_as_bytes(&[bytes_to_write]));
768
769 idx_offset = idx_limit;
770 }
771
772 let dat_limit = dat_offset + element_len;
773 #[expect(
774 clippy::indexing_slicing,
775 reason = "Function contract allows panicky behavior"
776 )]
777 let dat_slice = &mut output[dat_offset..dat_limit];
778 element.encode_var_ule_write(dat_slice);
779 debug_assert_eq!(T::validate_bytes(dat_slice), Ok(()));
780 dat_offset = dat_limit;
781 }
782
783 #[expect(
784 clippy::expect_used,
785 reason = "Function contract allows panicky behavior"
786 )]
787 let indices_size = F::Index::SIZE
788 .checked_mul(elements.len() - 1)
789 .expect(F::Index::TOO_LARGE_ERROR);
790 debug_assert_eq!(idx_offset, indices_size);
791 assert_eq!(dat_offset, output.len());
792}
793
794pub fn write_serializable_bytes<T, A, F>(elements: &[A], output: &mut [u8])
802where
803 T: VarULE + ?Sized,
804 A: EncodeAsVarULE<T>,
805 F: VarZeroVecFormat,
806{
807 if elements.is_empty() {
808 return;
809 }
810 assert!(elements.len() <= F::Len::MAX_VALUE as usize);
811 #[expect(clippy::expect_used)] let num_elements_ule = F::Len::iule_from_usize(elements.len()).expect(F::Len::TOO_LARGE_ERROR);
813 #[expect(clippy::indexing_slicing)] output[0..F::Len::SIZE].copy_from_slice(ULE::slice_as_bytes(&[num_elements_ule]));
815
816 #[expect(clippy::indexing_slicing)] write_serializable_bytes_without_length::<T, A, F>(elements, &mut output[F::Len::SIZE..]);
818}
819
820pub fn compute_serializable_len_without_length<T, A, F>(elements: &[A]) -> Option<u32>
821where
822 T: VarULE + ?Sized,
823 A: EncodeAsVarULE<T>,
824 F: VarZeroVecFormat,
825{
826 let elements_len = elements.len();
827 let Some(elements_len_minus_one) = elements_len.checked_sub(1) else {
828 return Some(0);
830 };
831 let idx_len: u32 = u32::try_from(elements_len_minus_one)
832 .ok()?
833 .checked_mul(F::Index::SIZE as u32)?;
834 let data_len: u32 = elements
835 .iter()
836 .map(|v| u32::try_from(v.encode_var_ule_len()).ok())
837 .try_fold(0u32, |s, v| s.checked_add(v?))?;
838 let ret = idx_len.checked_add(data_len);
839 if let Some(r) = ret {
840 if r >= F::Index::MAX_VALUE {
841 return None;
842 }
843 }
844 ret
845}
846
847pub fn compute_serializable_len<T, A, F>(elements: &[A]) -> Option<u32>
848where
849 T: VarULE + ?Sized,
850 A: EncodeAsVarULE<T>,
851 F: VarZeroVecFormat,
852{
853 compute_serializable_len_without_length::<T, A, F>(elements).map(|x| x + F::Len::SIZE as u32)
854}