1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
45#![allow(unused_qualifications)]
67use super::VarZeroVecFormatError;
8use crate::ule::*;
9use core::cmp::Ordering;
10use core::convert::TryFrom;
11use core::marker::PhantomData;
12use core::ops::Range;
1314/// This trait allows switching between different possible internal
15/// representations of [`VarZeroVec`](super::VarZeroVec).
16///
17/// Currently this crate supports three formats: [`Index8`], [`Index16`] and [`Index32`],
18/// with [`Index16`] being the default for all [`VarZeroVec`](super::VarZeroVec)
19/// types unless explicitly specified otherwise.
20///
21/// Do not implement this trait, its internals may be changed in the future,
22/// and all of its associated items are hidden from the docs.
23pub trait VarZeroVecFormat: 'static + Sized {
24/// The type to use for the indexing array
25 ///
26 /// Safety: must be a ULE for which all byte sequences are allowed
27#[doc(hidden)]
28type Index: IntegerULE;
29/// The type to use for the length segment
30 ///
31 /// Safety: must be a ULE for which all byte sequences are allowed
32#[doc(hidden)]
33type Len: IntegerULE;
34}
3536/// This trait represents various ULE types that can be used to represent an integer
37///
38/// Do not implement this trait, its internals may be changed in the future,
39/// and all of its associated items are hidden from the docs.
40#[doc(hidden)]
41pub unsafe trait IntegerULE: ULE {
42/// The error to show when unable to construct a vec
43#[doc(hidden)]
44const TOO_LARGE_ERROR: &'static str;
4546/// Safety: must be sizeof(self)
47#[doc(hidden)]
48const SIZE: usize;
4950/// Safety: must be maximum integral value represented here
51#[doc(hidden)]
52const MAX_VALUE: u32;
5354/// Safety: Must roundtrip with from_usize and represent the correct
55 /// integral value
56#[doc(hidden)]
57fn iule_to_usize(self) -> usize;
5859#[doc(hidden)]
60fn iule_from_usize(x: usize) -> Option<Self>;
6162/// Safety: Should always convert a buffer into an array of Self with the correct length
63#[doc(hidden)]
64 #[cfg(feature = "alloc")]
65fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self];
66}
6768/// This is a [`VarZeroVecFormat`] that stores u8s in the index array, and a u8 for a length.
69///
70/// Will have a smaller data size, but it's *extremely* likely for larger arrays
71/// to be unrepresentable (and error on construction). Should probably be used
72/// for known-small arrays, where all but the last field are known-small.
73#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::marker::Copy for Index8 { }Copy, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::clone::Clone for Index8 {
#[inline]
fn clone(&self) -> Index8 { *self }
}Clone, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::fmt::Debug for Index8 {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Index8")
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::hash::Hash for Index8 {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialEq for Index8 {
#[inline]
fn eq(&self, other: &Index8) -> bool { true }
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Eq for Index8 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialOrd for Index8 {
#[inline]
fn partial_cmp(&self, other: &Index8)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
}PartialOrd, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Ord for Index8 {
#[inline]
fn cmp(&self, other: &Index8) -> ::core::cmp::Ordering {
::core::cmp::Ordering::Equal
}
}Ord)]
74#[allow(clippy::exhaustive_structs)] // marker
75pub struct Index8;
7677/// This is a [`VarZeroVecFormat`] that stores u16s in the index array, and a u16 for a length.
78///
79/// Will have a smaller data size, but it's more likely for larger arrays
80/// to be unrepresentable (and error on construction)
81///
82/// This is the default index size used by all [`VarZeroVec`](super::VarZeroVec) types.
83#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::marker::Copy for Index16 { }Copy, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::clone::Clone for Index16 {
#[inline]
fn clone(&self) -> Index16 { *self }
}Clone, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::fmt::Debug for Index16 {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Index16")
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::hash::Hash for Index16 {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialEq for Index16 {
#[inline]
fn eq(&self, other: &Index16) -> bool { true }
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Eq for Index16 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialOrd for Index16 {
#[inline]
fn partial_cmp(&self, other: &Index16)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
}PartialOrd, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Ord for Index16 {
#[inline]
fn cmp(&self, other: &Index16) -> ::core::cmp::Ordering {
::core::cmp::Ordering::Equal
}
}Ord)]
84#[allow(clippy::exhaustive_structs)] // marker
85pub struct Index16;
8687/// This is a [`VarZeroVecFormat`] that stores u32s in the index array, and a u32 for a length.
88/// Will have a larger data size, but will support large arrays without
89/// problems.
90#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::marker::Copy for Index32 { }Copy, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::clone::Clone for Index32 {
#[inline]
fn clone(&self) -> Index32 { *self }
}Clone, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::fmt::Debug for Index32 {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Index32")
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::hash::Hash for Index32 {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {}
}Hash, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialEq for Index32 {
#[inline]
fn eq(&self, other: &Index32) -> bool { true }
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Eq for Index32 {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialOrd for Index32 {
#[inline]
fn partial_cmp(&self, other: &Index32)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
}PartialOrd, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Ord for Index32 {
#[inline]
fn cmp(&self, other: &Index32) -> ::core::cmp::Ordering {
::core::cmp::Ordering::Equal
}
}Ord)]
91#[allow(clippy::exhaustive_structs)] // marker
92pub struct Index32;
9394impl VarZeroVecFormatfor Index8 {
95type Index = u8;
96type Len = u8;
97}
9899impl VarZeroVecFormatfor Index16 {
100type Index = RawBytesULE<2>;
101type Len = RawBytesULE<2>;
102}
103104impl VarZeroVecFormatfor Index32 {
105type Index = RawBytesULE<4>;
106type Len = RawBytesULE<4>;
107}
108109unsafe impl IntegerULEfor u8 {
110const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
111 cumulatively are larger than a u8 in size";
112const SIZE: usize = size_of::<Self>();
113const MAX_VALUE: u32 = u8::MAXas u32;
114#[inline]
115fn iule_to_usize(self) -> usize {
116selfas usize117 }
118#[inline]
119fn iule_from_usize(u: usize) -> Option<Self> {
120u8::try_from(u).ok()
121 }
122#[inline]
123 #[cfg(feature = "alloc")]
124fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
125 bytes
126 }
127}
128129unsafe impl IntegerULEfor RawBytesULE<2> {
130const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
131 cumulatively are larger than a u16 in size";
132const SIZE: usize = size_of::<Self>();
133const MAX_VALUE: u32 = u16::MAXas u32;
134#[inline]
135fn iule_to_usize(self) -> usize {
136self.as_unsigned_int() as usize137 }
138#[inline]
139fn iule_from_usize(u: usize) -> Option<Self> {
140u16::try_from(u).ok().map(u16::to_unaligned)
141 }
142#[inline]
143 #[cfg(feature = "alloc")]
144fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
145Self::from_bytes_unchecked_mut(bytes)
146 }
147}
148149unsafe impl IntegerULEfor RawBytesULE<4> {
150const TOO_LARGE_ERROR: &'static str = "Attempted to build VarZeroVec out of elements that \
151 cumulatively are larger than a u32 in size";
152const SIZE: usize = size_of::<Self>();
153const MAX_VALUE: u32 = u32::MAX;
154#[inline]
155fn iule_to_usize(self) -> usize {
156self.as_unsigned_int() as usize157 }
158#[inline]
159fn iule_from_usize(u: usize) -> Option<Self> {
160u32::try_from(u).ok().map(u32::to_unaligned)
161 }
162#[inline]
163 #[cfg(feature = "alloc")]
164fn iule_from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
165Self::from_bytes_unchecked_mut(bytes)
166 }
167}
168169/// A more parsed version of [`VarZeroSlice`](super::VarZeroSlice). This type is where most of the[ `VarZeroVec`](super::VarZeroVec)
170/// internal representation code lies.
171///
172/// This is *basically* an `&'a [u8]` to a zero copy buffer, but split out into
173/// the buffer components. Logically this is capable of behaving as
174/// a `&'a [T::VarULE]`, but since `T::VarULE` is unsized that type does not actually
175/// exist.
176///
177/// See [`VarZeroVecComponents::parse_bytes()`] for information on the internal invariants involved
178#[derive(#[automatically_derived]
impl<'a, T: ::core::fmt::Debug + ?Sized, F: ::core::fmt::Debug>
::core::fmt::Debug for VarZeroVecComponents<'a, T, F> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f,
"VarZeroVecComponents", "len", &self.len, "indices",
&self.indices, "things", &self.things, "marker", &&self.marker)
}
}Debug)]
179pub struct VarZeroVecComponents<'a, T: ?Sized, F> {
180/// The number of elements
181len: u32,
182/// The list of indices into the `things` slice
183 /// Since the first element is always at things[0], the first element of the indices array is for the *second* element
184indices: &'a [u8],
185/// The contiguous list of `T::VarULE`s
186things: &'a [u8],
187 marker: PhantomData<(&'a T, F)>,
188}
189190// #[derive()] won't work here since we do not want it to be
191// bound on T: Copy
192impl<'a, T: ?Sized, F> Copyfor VarZeroVecComponents<'a, T, F> {}
193impl<'a, T: ?Sized, F> Clonefor VarZeroVecComponents<'a, T, F> {
194fn clone(&self) -> Self {
195*self196 }
197}
198199impl<'a, T: VarULE + ?Sized, F> Defaultfor VarZeroVecComponents<'a, T, F> {
200#[inline]
201fn default() -> Self {
202Self::new()
203 }
204}
205206impl<'a, T: VarULE + ?Sized, F> VarZeroVecComponents<'a, T, F> {
207#[inline]
208pub fn new() -> Self {
209Self {
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/// Construct a new [`VarZeroVecComponents`], checking invariants about the overall buffer size:
219 ///
220 /// - There must be either zero or at least four bytes (if four, this is the "length" parsed as a usize)
221 /// - There must be at least `4*(length - 1) + 4` bytes total, to form the array `indices` of indices
222 /// - `0..indices[0]` must index into a valid section of
223 /// `things` (the data after `indices`), such that it parses to a `T::VarULE`
224 /// - `indices[i - 1]..indices[i]` must index into a valid section of
225 /// `things` (the data after `indices`), such that it parses to a `T::VarULE`
226 /// - `indices[len - 2]..things.len()` must index into a valid section of
227 /// `things`, such that it parses to a `T::VarULE`
228#[inline]
229pub fn parse_bytes(slice: &'a [u8]) -> Result<Self, VarZeroVecFormatError> {
230// The empty VZV is special-cased to the empty slice
231if slice.is_empty() {
232return Ok(VarZeroVecComponents {
233 len: 0,
234 indices: &[],
235 things: &[],
236 marker: PhantomData,
237 });
238 }
239let len_bytes = slice240 .get(0..F::Len::SIZE)
241 .ok_or(VarZeroVecFormatError::Metadata)?;
242let len_ule =
243 F::Len::parse_bytes_to_slice(len_bytes).map_err(|_| VarZeroVecFormatError::Metadata)?;
244245let len = len_ule246 .first()
247 .ok_or(VarZeroVecFormatError::Metadata)?
248.iule_to_usize();
249250let rest = slice251 .get(F::Len::SIZE..)
252 .ok_or(VarZeroVecFormatError::Metadata)?;
253let len_u32 = u32::try_from(len).map_err(|_| VarZeroVecFormatError::Metadata);
254// We pass down the rest of the invariants
255Self::parse_bytes_with_length(len_u32?, rest)
256 }
257258/// Construct a new [`VarZeroVecComponents`], checking invariants about the overall buffer size:
259 ///
260 /// - There must be at least `4*len` bytes total, to form the array `indices` of indices.
261 /// - `indices[i]..indices[i+1]` must index into a valid section of
262 /// `things` (the data after `indices`), such that it parses to a `T::VarULE`
263 /// - `indices[len - 1]..things.len()` must index into a valid section of
264 /// `things`, such that it parses to a `T::VarULE`
265#[inline]
266pub fn parse_bytes_with_length(
267 len: u32,
268 slice: &'a [u8],
269 ) -> Result<Self, VarZeroVecFormatError> {
270let len_minus_one = len.checked_sub(1);
271// The empty VZV is special-cased to the empty slice
272let Some(len_minus_one) = len_minus_oneelse {
273return Ok(VarZeroVecComponents {
274 len: 0,
275 indices: &[],
276 things: &[],
277 marker: PhantomData,
278 });
279 };
280// The indices array is one element shorter since the first index is always 0,
281 // so we use len_minus_one
282let indices_bytes = slice283 .get(..F::Index::SIZE * (len_minus_one as usize))
284 .ok_or(VarZeroVecFormatError::Metadata)?;
285let things = slice286 .get(F::Index::SIZE * (len_minus_one as usize)..)
287 .ok_or(VarZeroVecFormatError::Metadata)?;
288289let borrowed = VarZeroVecComponents {
290len,
291 indices: indices_bytes,
292things,
293 marker: PhantomData,
294 };
295296borrowed.check_indices_and_things()?;
297298Ok(borrowed)
299 }
300301/// Construct a [`VarZeroVecComponents`] from a byte slice that has previously
302 /// successfully returned a [`VarZeroVecComponents`] when passed to
303 /// [`VarZeroVecComponents::parse_bytes()`]. Will return the same
304 /// object as one would get from calling [`VarZeroVecComponents::parse_bytes()`].
305 ///
306 /// # Safety
307 /// The bytes must have previously successfully run through
308 /// [`VarZeroVecComponents::parse_bytes()`]
309pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
310// The empty VZV is special-cased to the empty slice
311if slice.is_empty() {
312return VarZeroVecComponents {
313 len: 0,
314 indices: &[],
315 things: &[],
316 marker: PhantomData,
317 };
318 }
319let (len_bytes, data_bytes) = unsafe { slice.split_at_unchecked(F::Len::SIZE) };
320// Safety: F::Len allows all byte sequences
321let len_ule = F::Len::slice_from_bytes_unchecked(len_bytes);
322323let len = len_ule.get_unchecked(0).iule_to_usize();
324let len_u32 = lenas u32;
325326// Safety: This method requires the bytes to have passed through `parse_bytes()`
327 // whereas we're calling something that asks for `parse_bytes_with_length()`.
328 // The two methods perform similar validation, with parse_bytes() validating an additional
329 // 4-byte `length` header.
330Self::from_bytes_unchecked_with_length(len_u32, data_bytes)
331 }
332333/// Construct a [`VarZeroVecComponents`] from a byte slice that has previously
334 /// successfully returned a [`VarZeroVecComponents`] when passed to
335 /// [`VarZeroVecComponents::parse_bytes()`]. Will return the same
336 /// object as one would get from calling [`VarZeroVecComponents::parse_bytes()`].
337 ///
338 /// # Safety
339 /// The len,bytes must have previously successfully run through
340 /// [`VarZeroVecComponents::parse_bytes_with_length()`]
341pub unsafe fn from_bytes_unchecked_with_length(len: u32, slice: &'a [u8]) -> Self {
342let len_minus_one = len.checked_sub(1);
343// The empty VZV is special-cased to the empty slice
344let Some(len_minus_one) = len_minus_oneelse {
345return VarZeroVecComponents {
346 len: 0,
347 indices: &[],
348 things: &[],
349 marker: PhantomData,
350 };
351 };
352// The indices array is one element shorter since the first index is always 0,
353 // so we use len_minus_one
354let indices_bytes = slice.get_unchecked(..F::Index::SIZE * (len_minus_one as usize));
355let things = slice.get_unchecked(F::Index::SIZE * (len_minus_one as usize)..);
356357VarZeroVecComponents {
358len,
359 indices: indices_bytes,
360things,
361 marker: PhantomData,
362 }
363 }
364365/// Get the number of elements in this vector
366#[inline]
367pub fn len(self) -> usize {
368self.len as usize369 }
370371/// Returns `true` if the vector contains no elements.
372#[inline]
373pub fn is_empty(self) -> bool {
374self.len == 0
375}
376377/// Get the idx'th element out of this slice. Returns `None` if out of bounds.
378#[inline]
379pub fn get(self, idx: usize) -> Option<&'a T> {
380if idx >= self.len() {
381return None;
382 }
383Some(unsafe { self.get_unchecked(idx) })
384 }
385386/// Get the idx'th element out of this slice. Does not bounds check.
387 ///
388 /// Safety:
389 /// - `idx` must be in bounds (`idx < self.len()`)
390#[inline]
391pub(crate) unsafe fn get_unchecked(self, idx: usize) -> &'a T {
392let range = self.get_things_range(idx);
393let things_slice = self.things.get_unchecked(range);
394 T::from_bytes_unchecked(things_slice)
395 }
396397/// Get the range in `things` for the element at `idx`. Does not bounds check.
398 ///
399 /// Safety:
400 /// - `idx` must be in bounds (`idx < self.len()`)
401#[inline]
402pub(crate) unsafe fn get_things_range(self, idx: usize) -> Range<usize> {
403let start = if let Some(idx_minus_one) = idx.checked_sub(1) {
404self.indices_slice()
405 .get_unchecked(idx_minus_one)
406 .iule_to_usize()
407 } else {
4080
409};
410let end = if idx + 1 == self.len() {
411self.things.len()
412 } else {
413self.indices_slice().get_unchecked(idx).iule_to_usize()
414 };
415if true {
if !(start <= end) {
::core::panicking::panic("assertion failed: start <= end")
};
};debug_assert!(start <= end);
416 start..end
417 }
418419/// Get the size, in bytes, of the indices array
420pub(crate) unsafe fn get_indices_size(self) -> usize {
421self.indices.len()
422 }
423424/// Check the internal invariants of [`VarZeroVecComponents`]:
425 ///
426 /// - `indices[i]..indices[i+1]` must index into a valid section of
427 /// `things`, such that it parses to a `T::VarULE`
428 /// - `indices[len - 1]..things.len()` must index into a valid section of
429 /// `things`, such that it parses to a `T::VarULE`
430 /// - `indices` is monotonically increasing
431 ///
432 /// This method is NOT allowed to call any other methods on [`VarZeroVecComponents`] since all other methods
433 /// assume that the slice has been passed through [`Self::check_indices_and_things`]
434#[inline]
435 #[expect(clippy::len_zero)] // more explicit to enforce safety invariants
436fn check_indices_and_things(self) -> Result<(), VarZeroVecFormatError> {
437if self.len() == 0 {
438if self.things.len() > 0 {
439return Err(VarZeroVecFormatError::Metadata);
440 } else {
441return Ok(());
442 }
443 }
444let indices_slice = self.indices_slice();
445match (&self.len(), &(indices_slice.len() + 1)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(self.len(), indices_slice.len() + 1);
446// Safety: i is in bounds (assertion above)
447let mut start = 0;
448for i in 0..self.len() {
449// The indices array is offset by 1: indices[0] is the end of the first
450 // element and the start of the next, since the start of the first element
451 // is always things[0]. So to get the end we get element `i`.
452let end = if let Some(end) = indices_slice.get(i) {
453 end.iule_to_usize()
454 } else {
455// This only happens at i = self.len() - 1 = indices_slice.len() + 1 - 1
456 // = indices_slice.len(). This is the last `end`, which is always the size of
457 // `things` and thus never stored in the array
458self.things.len()
459 };
460461if start > end {
462return Err(VarZeroVecFormatError::Metadata);
463 }
464if end > self.things.len() {
465return Err(VarZeroVecFormatError::Metadata);
466 }
467// Safety: start..end is a valid range in self.things
468let bytes = unsafe { self.things.get_unchecked(start..end) };
469 T::parse_bytes(bytes).map_err(VarZeroVecFormatError::Values)?;
470 start = end;
471 }
472Ok(())
473 }
474475/// Create an iterator over the Ts contained in [`VarZeroVecComponents`]
476#[inline]
477pub fn iter(self) -> VarZeroSliceIter<'a, T, F> {
478VarZeroSliceIter::new(self)
479 }
480481#[cfg(feature = "alloc")]
482pub fn to_vec(self) -> alloc::vec::Vec<alloc::boxed::Box<T>> {
483self.iter().map(T::to_boxed).collect()
484 }
485486#[inline]
487fn indices_slice(&self) -> &'a [F::Index] {
488unsafe { F::Index::slice_from_bytes_unchecked(self.indices) }
489 }
490491// Dump a debuggable representation of this type
492#[allow(unused)] // useful for debugging
493#[cfg(feature = "alloc")]
494pub(crate) fn dump(&self) -> alloc::string::String {
495let indices = self
496.indices_slice()
497 .iter()
498 .copied()
499 .map(IntegerULE::iule_to_usize)
500 .collect::<alloc::vec::Vec<_>>();
501alloc::format!("VarZeroVecComponents {{ indices: {indices:?} }}")
502 }
503}
504505/// An iterator over [`VarZeroSlice`](super::VarZeroSlice)
506#[derive(#[automatically_derived]
impl<'a, T: ::core::fmt::Debug + ?Sized, F: ::core::fmt::Debug>
::core::fmt::Debug for VarZeroSliceIter<'a, T, F> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"VarZeroSliceIter", "components", &self.components, "index",
&self.index, "start_index", &&self.start_index)
}
}Debug)]
507pub struct VarZeroSliceIter<'a, T: ?Sized, F = Index16> {
508 components: VarZeroVecComponents<'a, T, F>,
509 index: usize,
510// Safety invariant: must be a valid index into the data segment of `components`, or an index at the end
511 // i.e. start_index <= components.things.len()
512 //
513 // It must be a valid index into the `things` array of components, coming from `components.indices_slice()`
514start_index: usize,
515}
516517impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> Clonefor VarZeroSliceIter<'a, T, F> {
518fn clone(&self) -> Self {
519Self {
520 components: self.components,
521 index: self.index,
522 start_index: self.start_index,
523 }
524 }
525}
526527impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroSliceIter<'a, T, F> {
528fn new(c: VarZeroVecComponents<'a, T, F>) -> Self {
529Self {
530 components: c,
531 index: 0,
532// Invariant upheld, 0 is always a valid index-or-end
533start_index: 0,
534 }
535 }
536}
537impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> Iteratorfor VarZeroSliceIter<'a, T, F> {
538type Item = &'a T;
539540fn next(&mut self) -> Option<Self::Item> {
541// Note: the indices array doesn't contain 0 or len, we need to specially handle those edges. The 0 is handled
542 // by start_index, and the len is handled by the code for `end`.
543544if self.index >= self.components.len() {
545return None;
546 }
547548// Invariant established: self.index is in bounds for self.components.len(),
549 // which means it is in bounds for self.components.indices_slice() since that has the same length
550551let end = if self.index + 1 == self.components.len() {
552// We don't store the end index since it is computable, so the last element should use self.components.things.len()
553self.components.things.len()
554 } else {
555// Safety: self.index was known to be in bounds from the bounds check above.
556unsafe {
557self.components
558 .indices_slice()
559 .get_unchecked(self.index)
560 .iule_to_usize()
561 }
562 };
563// Invariant established: end has the same invariant as self.start_index since it comes from indices_slice, which is guaranteed
564 // to only contain valid indexes
565566let item = unsafe {
567// Safety: self.start_index and end both have in-range invariants, plus they are valid indices from indices_slice
568 // which means we can treat this data as a T
569T::from_bytes_unchecked(self.components.things.get_unchecked(self.start_index..end))
570 };
571self.index += 1;
572// Invariant upheld: end has the same invariant as self.start_index
573self.start_index = end;
574Some(item)
575 }
576577fn size_hint(&self) -> (usize, Option<usize>) {
578let remainder = self.components.len() - self.index;
579 (remainder, Some(remainder))
580 }
581}
582583impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> ExactSizeIteratorfor VarZeroSliceIter<'a, T, F> {
584fn len(&self) -> usize {
585self.components.len() - self.index
586 }
587}
588589impl<'a, T, F> VarZeroVecComponents<'a, T, F>
590where
591T: VarULE,
592 T: ?Sized,
593 T: Ord,
594 F: VarZeroVecFormat,
595{
596/// Binary searches a sorted `VarZeroVecComponents<T>` for the given element. For more information, see
597 /// the primitive function [`binary_search`](slice::binary_search).
598pub fn binary_search(&self, needle: &T) -> Result<usize, usize> {
599self.binary_search_by(|probe| probe.cmp(needle))
600 }
601602pub fn binary_search_in_range(
603&self,
604 needle: &T,
605 range: Range<usize>,
606 ) -> Option<Result<usize, usize>> {
607self.binary_search_in_range_by(|probe| probe.cmp(needle), range)
608 }
609}
610611impl<'a, T, F> VarZeroVecComponents<'a, T, F>
612where
613T: VarULE,
614 T: ?Sized,
615 F: VarZeroVecFormat,
616{
617/// Binary searches a sorted `VarZeroVecComponents<T>` for the given predicate. For more information, see
618 /// the primitive function [`binary_search_by`](slice::binary_search_by).
619pub fn binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> {
620// Safety: 0 and len are in range
621unsafe { self.binary_search_in_range_unchecked(predicate, 0..self.len()) }
622 }
623624// Binary search within a range.
625 // Values returned are relative to the range start!
626pub fn binary_search_in_range_by(
627&self,
628 predicate: impl FnMut(&T) -> Ordering,
629 range: Range<usize>,
630 ) -> Option<Result<usize, usize>> {
631if range.end > self.len() {
632return None;
633 }
634if range.end < range.start {
635return None;
636 }
637// Safety: We bounds checked above: end is in-bounds or len, and start is <= end
638let range_absolute =
639unsafe { self.binary_search_in_range_unchecked(predicate, range.clone()) };
640// The values returned are relative to the range start
641Some(
642range_absolute643 .map(|o| o - range.start)
644 .map_err(|e| e - range.start),
645 )
646 }
647648/// Safety: range must be in range for the slice (start <= len, end <= len, start <= end)
649unsafe fn binary_search_in_range_unchecked(
650&self,
651mut predicate: impl FnMut(&T) -> Ordering,
652 range: Range<usize>,
653 ) -> Result<usize, usize> {
654// Function invariant: size is always end - start
655let mut start = range.start;
656let mut end = range.end;
657let mut size;
658659// Loop invariant: 0 <= start < end <= len
660 // This invariant is initialized by the function safety invariants and the loop condition
661while start < end {
662 size = end - start;
663// This establishes mid < end (which implies mid < len)
664 // size is end - start. start + size is end (which is <= len).
665 // mid = start + size/2 will be less than end
666let mid = start + size / 2;
667668// Safety: mid is < end <= len, so in-range
669let cmp = predicate(self.get_unchecked(mid));
670671match cmp {
672 Ordering::Less => {
673// This retains the loop invariant since it
674 // increments start, and we already have 0 <= start
675 // start < end is enforced by the loop condition
676start = mid + 1;
677 }
678 Ordering::Greater => {
679// mid < end, so this decreases end.
680 // This means end <= len is still true, and
681 // end > start is enforced by the loop condition
682end = mid;
683 }
684 Ordering::Equal => return Ok(mid),
685 }
686 }
687Err(start)
688 }
689}
690691/// Collects the bytes for a [`VarZeroSlice`](super::VarZeroSlice) into a [`Vec`].
692#[cfg(feature = "alloc")]
693pub fn get_serializable_bytes_non_empty<T, A, F>(elements: &[A]) -> Option<alloc::vec::Vec<u8>>
694where
695T: VarULE + ?Sized,
696 A: EncodeAsVarULE<T>,
697 F: VarZeroVecFormat,
698{
699debug_assert!(!elements.is_empty());
700let len = compute_serializable_len::<T, A, F>(elements)?;
701debug_assert!(
702 len >= F::Len::SIZE as u32,
703"Must have at least F::Len::SIZE bytes to hold the length of the vector"
704);
705let mut output = alloc::vec![0u8; len as usize];
706 write_serializable_bytes::<T, A, F>(elements, &mut output);
707Some(output)
708}
709710/// Writes the bytes for a [`VarZeroLengthlessSlice`](super::lenghtless::VarZeroLengthlessSlice) into an output buffer.
711/// Usable for a [`VarZeroSlice`](super::VarZeroSlice) if you first write the length bytes.
712///
713/// Every byte in the buffer will be initialized after calling this function.
714///
715/// # Panics
716///
717/// Panics if the buffer is not exactly the correct length.
718pub fn write_serializable_bytes_without_length<T, A, F>(elements: &[A], output: &mut [u8])
719where
720T: VarULE + ?Sized,
721 A: EncodeAsVarULE<T>,
722 F: VarZeroVecFormat,
723{
724if !(elements.len() <= F::Len::MAX_VALUE as usize) {
::core::panicking::panic("assertion failed: elements.len() <= F::Len::MAX_VALUE as usize")
};assert!(elements.len() <= F::Len::MAX_VALUE as usize);
725if elements.is_empty() {
726return;
727 }
728729// idx_offset = offset from the start of the buffer for the next index
730let mut idx_offset: usize = 0;
731// first_dat_offset = offset from the start of the buffer of the first data block
732let first_dat_offset: usize = idx_offset + (elements.len() - 1) * F::Index::SIZE;
733// dat_offset = offset from the start of the buffer of the next data block
734let mut dat_offset: usize = first_dat_offset;
735736for (i, element) in elements.iter().enumerate() {
737let element_len = element.encode_var_ule_len();
738739// The first index is always 0. We don't write it, or update the idx offset.
740if i != 0 {
741let idx_limit = idx_offset + F::Index::SIZE;
742#[expect(clippy::indexing_slicing)] // Function contract allows panicky behavior
743let idx_slice = &mut output[idx_offset..idx_limit];
744// VZV expects data offsets to be stored relative to the first data block
745let idx = dat_offset - first_dat_offset;
746if !(idx <= F::Index::MAX_VALUE as usize) {
::core::panicking::panic("assertion failed: idx <= F::Index::MAX_VALUE as usize")
};assert!(idx <= F::Index::MAX_VALUE as usize);
747#[expect(clippy::expect_used)] // this function is explicitly panicky
748let bytes_to_write = F::Index::iule_from_usize(idx).expect(F::Index::TOO_LARGE_ERROR);
749 idx_slice.copy_from_slice(ULE::slice_as_bytes(&[bytes_to_write]));
750751 idx_offset = idx_limit;
752 }
753754let dat_limit = dat_offset + element_len;
755#[expect(clippy::indexing_slicing)] // Function contract allows panicky behavior
756let dat_slice = &mut output[dat_offset..dat_limit];
757 element.encode_var_ule_write(dat_slice);
758if true {
match (&T::validate_bytes(dat_slice), &Ok(())) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(T::validate_bytes(dat_slice), Ok(()));
759 dat_offset = dat_limit;
760 }
761762if true {
match (&idx_offset, &(F::Index::SIZE * (elements.len() - 1))) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};debug_assert_eq!(idx_offset, F::Index::SIZE * (elements.len() - 1));
763match (&dat_offset, &output.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(dat_offset, output.len());
764}
765766/// Writes the bytes for a [`VarZeroSlice`](super::VarZeroSlice) into an output buffer.
767///
768/// Every byte in the buffer will be initialized after calling this function.
769///
770/// # Panics
771///
772/// Panics if the buffer is not exactly the correct length.
773pub fn write_serializable_bytes<T, A, F>(elements: &[A], output: &mut [u8])
774where
775T: VarULE + ?Sized,
776 A: EncodeAsVarULE<T>,
777 F: VarZeroVecFormat,
778{
779if elements.is_empty() {
780return;
781 }
782if !(elements.len() <= F::Len::MAX_VALUE as usize) {
::core::panicking::panic("assertion failed: elements.len() <= F::Len::MAX_VALUE as usize")
};assert!(elements.len() <= F::Len::MAX_VALUE as usize);
783#[expect(clippy::expect_used)] // This function is explicitly panicky
784let num_elements_ule = F::Len::iule_from_usize(elements.len()).expect(F::Len::TOO_LARGE_ERROR);
785#[expect(clippy::indexing_slicing)] // Function contract allows panicky behavior
786output[0..F::Len::SIZE].copy_from_slice(ULE::slice_as_bytes(&[num_elements_ule]));
787788#[expect(clippy::indexing_slicing)] // Function contract allows panicky behavior
789write_serializable_bytes_without_length::<T, A, F>(elements, &mut output[F::Len::SIZE..]);
790}
791792pub fn compute_serializable_len_without_length<T, A, F>(elements: &[A]) -> Option<u32>
793where
794T: VarULE + ?Sized,
795 A: EncodeAsVarULE<T>,
796 F: VarZeroVecFormat,
797{
798let elements_len = elements.len();
799let Some(elements_len_minus_one) = elements_len.checked_sub(1) else {
800// Empty vec is optimized to an empty byte representation
801return Some(0);
802 };
803let idx_len: u32 = u32::try_from(elements_len_minus_one)
804 .ok()?
805.checked_mul(F::Index::SIZEas u32)?;
806let data_len: u32 = elements807 .iter()
808 .map(|v| u32::try_from(v.encode_var_ule_len()).ok())
809 .try_fold(0u32, |s, v| s.checked_add(v?))?;
810let ret = idx_len.checked_add(data_len);
811if let Some(r) = ret {
812if r >= F::Index::MAX_VALUE {
813return None;
814 }
815 }
816ret817}
818819pub fn compute_serializable_len<T, A, F>(elements: &[A]) -> Option<u32>
820where
821T: VarULE + ?Sized,
822 A: EncodeAsVarULE<T>,
823 F: VarZeroVecFormat,
824{
825 compute_serializable_len_without_length::<T, A, F>(elements).map(|x| x + F::Len::SIZEas u32)
826}