zerovec/zerovec/
mod.rs

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 ).
4
5#[cfg(feature = "databake")]
6mod databake;
7
8#[cfg(feature = "serde")]
9mod serde;
10
11mod slice;
12
13pub use slice::ZeroSlice;
14
15use crate::ule::*;
16use alloc::borrow::Cow;
17use alloc::vec::Vec;
18use core::cmp::{Ord, Ordering, PartialOrd};
19use core::fmt;
20use core::iter::FromIterator;
21use core::marker::PhantomData;
22use core::mem;
23use core::num::NonZeroUsize;
24use core::ops::Deref;
25use core::ptr::{self, NonNull};
26
27/// A zero-copy, byte-aligned vector for fixed-width types.
28///
29/// `ZeroVec<T>` is designed as a drop-in replacement for `Vec<T>` in situations where it is
30/// desirable to borrow data from an unaligned byte slice, such as zero-copy deserialization.
31///
32/// `T` must implement [`AsULE`], which is auto-implemented for a number of built-in types,
33/// including all fixed-width multibyte integers. For variable-width types like [`str`],
34/// see [`VarZeroVec`](crate::VarZeroVec). [`zerovec::make_ule`](crate::make_ule) may
35/// be used to automatically implement [`AsULE`] for a type and generate the underlying [`ULE`] type.
36///
37/// Typically, the zero-copy equivalent of a `Vec<T>` will simply be `ZeroVec<'a, T>`.
38///
39/// Most of the methods on `ZeroVec<'a, T>` come from its [`Deref`] implementation to [`ZeroSlice<T>`](ZeroSlice).
40///
41/// For creating zero-copy vectors of fixed-size types, see [`VarZeroVec`](crate::VarZeroVec).
42///
43/// `ZeroVec<T>` behaves much like [`Cow`](alloc::borrow::Cow), where it can be constructed from
44/// owned data (and then mutated!) but can also borrow from some buffer.
45///
46/// # Example
47///
48/// ```
49/// use zerovec::ZeroVec;
50///
51/// // The little-endian bytes correspond to the numbers on the following line.
52/// let nums: &[u16] = &[211, 281, 421, 461];
53///
54/// #[derive(serde::Serialize, serde::Deserialize)]
55/// struct Data<'a> {
56///     #[serde(borrow)]
57///     nums: ZeroVec<'a, u16>,
58/// }
59///
60/// // The owned version will allocate
61/// let data = Data {
62///     nums: ZeroVec::alloc_from_slice(nums),
63/// };
64/// let bincode_bytes =
65///     bincode::serialize(&data).expect("Serialization should be successful");
66///
67/// // Will deserialize without allocations
68/// let deserialized: Data = bincode::deserialize(&bincode_bytes)
69///     .expect("Deserialization should be successful");
70///
71/// // This deserializes without allocation!
72/// assert!(!deserialized.nums.is_owned());
73/// assert_eq!(deserialized.nums.get(2), Some(421));
74/// assert_eq!(deserialized.nums, nums);
75/// ```
76///
77/// [`ule`]: crate::ule
78///
79/// # How it Works
80///
81/// `ZeroVec<T>` represents a slice of `T` as a slice of `T::ULE`. The difference between `T` and
82/// `T::ULE` is that `T::ULE` must be encoded in little-endian with 1-byte alignment. When accessing
83/// items from `ZeroVec<T>`, we fetch the `T::ULE`, convert it on the fly to `T`, and return `T` by
84/// value.
85///
86/// Benchmarks can be found in the project repository, with some results found in the [crate-level documentation](crate).
87///
88/// See [the design doc](https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md) for more details.
89pub struct ZeroVec<'a, T>
90where
91    T: AsULE,
92{
93    vector: EyepatchHackVector<T::ULE>,
94
95    /// Marker type, signalling variance and dropck behavior
96    /// by containing all potential types this type represents
97    #[allow(clippy::type_complexity)] // needed to get correct marker type behavior
98    marker: PhantomData<(Vec<T::ULE>, &'a [T::ULE])>,
99}
100
101// Send inherits as long as all fields are Send, but also references are Send only
102// when their contents are Sync (this is the core purpose of Sync), so
103// we need a Send+Sync bound since this struct can logically be a vector or a slice.
104unsafe impl<'a, T: AsULE> Send for ZeroVec<'a, T> where T::ULE: Send + Sync {}
105// Sync typically inherits as long as all fields are Sync
106unsafe impl<'a, T: AsULE> Sync for ZeroVec<'a, T> where T::ULE: Sync {}
107
108impl<'a, T: AsULE> Deref for ZeroVec<'a, T> {
109    type Target = ZeroSlice<T>;
110    #[inline]
111    fn deref(&self) -> &Self::Target {
112        let slice: &[T::ULE] = self.vector.as_slice();
113        ZeroSlice::from_ule_slice(slice)
114    }
115}
116
117// Represents an unsafe potentially-owned vector/slice type, without a lifetime
118// working around dropck limitations.
119//
120// Must either be constructed by deconstructing a Vec<U>, or from &[U] with capacity set to
121// zero. Should not outlive its source &[U] in the borrowed case; this type does not in
122// and of itself uphold this guarantee, but the .as_slice() method assumes it.
123//
124// After https://github.com/rust-lang/rust/issues/34761 stabilizes,
125// we should remove this type and use #[may_dangle]
126struct EyepatchHackVector<U> {
127    /// Pointer to data
128    /// This pointer is *always* valid, the reason it is represented as a raw pointer
129    /// is that it may logically represent an `&[T::ULE]` or the ptr,len of a `Vec<T::ULE>`
130    buf: NonNull<[U]>,
131    /// Borrowed if zero. Capacity of buffer above if not
132    capacity: usize,
133}
134
135impl<U> EyepatchHackVector<U> {
136    // Return a slice to the inner data for an arbitrary caller-specified lifetime
137    #[inline]
138    unsafe fn as_arbitrary_slice<'a>(&self) -> &'a [U] {
139        self.buf.as_ref()
140    }
141    // Return a slice to the inner data
142    #[inline]
143    const fn as_slice<'a>(&'a self) -> &'a [U] {
144        // Note: self.buf.as_ref() is not const until 1.73
145        unsafe { &*(self.buf.as_ptr() as *const [U]) }
146    }
147
148    /// Return this type as a vector
149    ///
150    /// Data MUST be known to be owned beforehand
151    ///
152    /// Because this borrows self, this is effectively creating two owners to the same
153    /// data, make sure that `self` is cleaned up after this
154    ///
155    /// (this does not simply take `self` since then it wouldn't be usable from the Drop impl)
156    unsafe fn get_vec(&self) -> Vec<U> {
157        debug_assert!(self.capacity != 0);
158        let slice: &[U] = self.as_slice();
159        let len = slice.len();
160        // Safety: we are assuming owned, and in owned cases
161        // this always represents a valid vector
162        Vec::from_raw_parts(self.buf.as_ptr() as *mut U, len, self.capacity)
163    }
164}
165
166impl<U> Drop for EyepatchHackVector<U> {
167    #[inline]
168    fn drop(&mut self) {
169        if self.capacity != 0 {
170            unsafe {
171                // we don't need to clean up self here since we're already in a Drop impl
172                let _ = self.get_vec();
173            }
174        }
175    }
176}
177
178impl<'a, T: AsULE> Clone for ZeroVec<'a, T> {
179    fn clone(&self) -> Self {
180        if self.is_owned() {
181            ZeroVec::new_owned(self.as_ule_slice().into())
182        } else {
183            Self {
184                vector: EyepatchHackVector {
185                    buf: self.vector.buf,
186                    capacity: 0,
187                },
188                marker: PhantomData,
189            }
190        }
191    }
192}
193
194impl<'a, T: AsULE> AsRef<ZeroSlice<T>> for ZeroVec<'a, T> {
195    fn as_ref(&self) -> &ZeroSlice<T> {
196        self.deref()
197    }
198}
199
200impl<T> fmt::Debug for ZeroVec<'_, T>
201where
202    T: AsULE + fmt::Debug,
203{
204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205        write!(f, "ZeroVec({:?})", self.to_vec())
206    }
207}
208
209impl<T> Eq for ZeroVec<'_, T> where T: AsULE + Eq + ?Sized {}
210
211impl<'a, 'b, T> PartialEq<ZeroVec<'b, T>> for ZeroVec<'a, T>
212where
213    T: AsULE + PartialEq + ?Sized,
214{
215    #[inline]
216    fn eq(&self, other: &ZeroVec<'b, T>) -> bool {
217        // Note: T implements PartialEq but not T::ULE
218        self.iter().eq(other.iter())
219    }
220}
221
222impl<T> PartialEq<&[T]> for ZeroVec<'_, T>
223where
224    T: AsULE + PartialEq + ?Sized,
225{
226    #[inline]
227    fn eq(&self, other: &&[T]) -> bool {
228        self.iter().eq(other.iter().copied())
229    }
230}
231
232impl<T, const N: usize> PartialEq<[T; N]> for ZeroVec<'_, T>
233where
234    T: AsULE + PartialEq + ?Sized,
235{
236    #[inline]
237    fn eq(&self, other: &[T; N]) -> bool {
238        self.iter().eq(other.iter().copied())
239    }
240}
241
242impl<'a, T: AsULE> Default for ZeroVec<'a, T> {
243    #[inline]
244    fn default() -> Self {
245        Self::new()
246    }
247}
248
249impl<'a, T: AsULE + PartialOrd> PartialOrd for ZeroVec<'a, T> {
250    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
251        self.iter().partial_cmp(other.iter())
252    }
253}
254
255impl<'a, T: AsULE + Ord> Ord for ZeroVec<'a, T> {
256    fn cmp(&self, other: &Self) -> Ordering {
257        self.iter().cmp(other.iter())
258    }
259}
260
261impl<'a, T: AsULE> AsRef<[T::ULE]> for ZeroVec<'a, T> {
262    fn as_ref(&self) -> &[T::ULE] {
263        self.as_ule_slice()
264    }
265}
266
267impl<'a, T: AsULE> From<&'a [T::ULE]> for ZeroVec<'a, T> {
268    fn from(other: &'a [T::ULE]) -> Self {
269        ZeroVec::new_borrowed(other)
270    }
271}
272
273impl<'a, T: AsULE> From<Vec<T::ULE>> for ZeroVec<'a, T> {
274    fn from(other: Vec<T::ULE>) -> Self {
275        ZeroVec::new_owned(other)
276    }
277}
278
279impl<'a, T> ZeroVec<'a, T>
280where
281    T: AsULE + ?Sized,
282{
283    /// Creates a new, borrowed, empty `ZeroVec<T>`.
284    ///
285    /// # Examples
286    ///
287    /// ```
288    /// use zerovec::ZeroVec;
289    ///
290    /// let zv: ZeroVec<u16> = ZeroVec::new();
291    /// assert!(zv.is_empty());
292    /// ```
293    #[inline]
294    pub const fn new() -> Self {
295        Self::new_borrowed(&[])
296    }
297
298    /// Same as `ZeroSlice::len`, which is available through `Deref` and not `const`.
299    pub const fn const_len(&self) -> usize {
300        self.vector.as_slice().len()
301    }
302
303    /// Creates a new owned `ZeroVec` using an existing
304    /// allocated backing buffer
305    ///
306    /// If you have a slice of `&[T]`s, prefer using
307    /// [`Self::alloc_from_slice()`].
308    #[inline]
309    pub fn new_owned(vec: Vec<T::ULE>) -> Self {
310        // Deconstruct the vector into parts
311        // This is the only part of the code that goes from Vec
312        // to ZeroVec, all other such operations should use this function
313        let capacity = vec.capacity();
314        let len = vec.len();
315        let ptr = mem::ManuallyDrop::new(vec).as_mut_ptr();
316        // Note: starting in 1.70 we can use NonNull::slice_from_raw_parts
317        let slice = ptr::slice_from_raw_parts_mut(ptr, len);
318        Self {
319            vector: EyepatchHackVector {
320                // Safety: `ptr` comes from Vec::as_mut_ptr, which says:
321                // "Returns an unsafe mutable pointer to the vector’s buffer,
322                // or a dangling raw pointer valid for zero sized reads"
323                buf: unsafe { NonNull::new_unchecked(slice) },
324                capacity,
325            },
326            marker: PhantomData,
327        }
328    }
329
330    /// Creates a new borrowed `ZeroVec` using an existing
331    /// backing buffer
332    #[inline]
333    pub const fn new_borrowed(slice: &'a [T::ULE]) -> Self {
334        // Safety: references in Rust cannot be null.
335        // The safe function `impl From<&T> for NonNull<T>` is not const.
336        let slice = unsafe { NonNull::new_unchecked(slice as *const [_] as *mut [_]) };
337        Self {
338            vector: EyepatchHackVector {
339                buf: slice,
340                capacity: 0,
341            },
342            marker: PhantomData,
343        }
344    }
345
346    /// Creates a new, owned, empty `ZeroVec<T>`, with a certain capacity pre-allocated.
347    pub fn with_capacity(capacity: usize) -> Self {
348        Self::new_owned(Vec::with_capacity(capacity))
349    }
350
351    /// Parses a `&[u8]` buffer into a `ZeroVec<T>`.
352    ///
353    /// This function is infallible for built-in integer types, but fallible for other types,
354    /// such as `char`. For more information, see [`ULE::parse_byte_slice`].
355    ///
356    /// The bytes within the byte buffer must remain constant for the life of the ZeroVec.
357    ///
358    /// # Endianness
359    ///
360    /// The byte buffer must be encoded in little-endian, even if running in a big-endian
361    /// environment. This ensures a consistent representation of data across platforms.
362    ///
363    /// # Example
364    ///
365    /// ```
366    /// use zerovec::ZeroVec;
367    ///
368    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
369    /// let zerovec: ZeroVec<u16> =
370    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
371    ///
372    /// assert!(!zerovec.is_owned());
373    /// assert_eq!(zerovec.get(2), Some(421));
374    /// ```
375    pub fn parse_byte_slice(bytes: &'a [u8]) -> Result<Self, ZeroVecError> {
376        let slice: &'a [T::ULE] = T::ULE::parse_byte_slice(bytes)?;
377        Ok(Self::new_borrowed(slice))
378    }
379
380    /// Uses a `&[u8]` buffer as a `ZeroVec<T>` without any verification.
381    ///
382    /// # Safety
383    ///
384    /// `bytes` need to be an output from [`ZeroSlice::as_bytes()`].
385    pub const unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> Self {
386        // &[u8] and &[T::ULE] are the same slice with different length metadata.
387        Self::new_borrowed(core::slice::from_raw_parts(
388            bytes.as_ptr() as *const T::ULE,
389            bytes.len() / core::mem::size_of::<T::ULE>(),
390        ))
391    }
392
393    /// Converts a `ZeroVec<T>` into a `ZeroVec<u8>`, retaining the current ownership model.
394    ///
395    /// Note that the length of the ZeroVec may change.
396    ///
397    /// # Examples
398    ///
399    /// Convert a borrowed `ZeroVec`:
400    ///
401    /// ```
402    /// use zerovec::ZeroVec;
403    ///
404    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
405    /// let zerovec: ZeroVec<u16> =
406    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
407    /// let zv_bytes = zerovec.into_bytes();
408    ///
409    /// assert!(!zv_bytes.is_owned());
410    /// assert_eq!(zv_bytes.get(0), Some(0xD3));
411    /// ```
412    ///
413    /// Convert an owned `ZeroVec`:
414    ///
415    /// ```
416    /// use zerovec::ZeroVec;
417    ///
418    /// let nums: &[u16] = &[211, 281, 421, 461];
419    /// let zerovec = ZeroVec::alloc_from_slice(nums);
420    /// let zv_bytes = zerovec.into_bytes();
421    ///
422    /// assert!(zv_bytes.is_owned());
423    /// assert_eq!(zv_bytes.get(0), Some(0xD3));
424    /// ```
425    pub fn into_bytes(self) -> ZeroVec<'a, u8> {
426        match self.into_cow() {
427            Cow::Borrowed(slice) => {
428                let bytes: &'a [u8] = T::ULE::as_byte_slice(slice);
429                ZeroVec::new_borrowed(bytes)
430            }
431            Cow::Owned(vec) => {
432                let bytes = Vec::from(T::ULE::as_byte_slice(&vec));
433                ZeroVec::new_owned(bytes)
434            }
435        }
436    }
437
438    /// Casts a `ZeroVec<T>` to a compatible `ZeroVec<P>`.
439    ///
440    /// `T` and `P` are compatible if they have the same `ULE` representation.
441    ///
442    /// If the `ULE`s of `T` and `P` are different types but have the same size,
443    /// use [`Self::try_into_converted()`].
444    ///
445    /// # Examples
446    ///
447    /// ```
448    /// use zerovec::ZeroVec;
449    ///
450    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
451    ///
452    /// let zerovec_u16: ZeroVec<u16> =
453    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
454    /// assert_eq!(zerovec_u16.get(3), Some(32973));
455    ///
456    /// let zerovec_i16: ZeroVec<i16> = zerovec_u16.cast();
457    /// assert_eq!(zerovec_i16.get(3), Some(-32563));
458    /// ```
459    pub fn cast<P>(self) -> ZeroVec<'a, P>
460    where
461        P: AsULE<ULE = T::ULE>,
462    {
463        match self.into_cow() {
464            Cow::Owned(v) => ZeroVec::new_owned(v),
465            Cow::Borrowed(v) => ZeroVec::new_borrowed(v),
466        }
467    }
468
469    /// Converts a `ZeroVec<T>` into a `ZeroVec<P>`, retaining the current ownership model.
470    ///
471    /// If `T` and `P` have the exact same `ULE`, use [`Self::cast()`].
472    ///
473    /// # Panics
474    ///
475    /// Panics if `T::ULE` and `P::ULE` are not the same size.
476    ///
477    /// # Examples
478    ///
479    /// Convert a borrowed `ZeroVec`:
480    ///
481    /// ```
482    /// use zerovec::ZeroVec;
483    ///
484    /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01];
485    /// let zv_char: ZeroVec<char> =
486    ///     ZeroVec::parse_byte_slice(bytes).expect("valid code points");
487    /// let zv_u8_3: ZeroVec<[u8; 3]> =
488    ///     zv_char.try_into_converted().expect("infallible conversion");
489    ///
490    /// assert!(!zv_u8_3.is_owned());
491    /// assert_eq!(zv_u8_3.get(0), Some([0x7F, 0xF3, 0x01]));
492    /// ```
493    ///
494    /// Convert an owned `ZeroVec`:
495    ///
496    /// ```
497    /// use zerovec::ZeroVec;
498    ///
499    /// let chars: &[char] = &['🍿', '🙉'];
500    /// let zv_char = ZeroVec::alloc_from_slice(chars);
501    /// let zv_u8_3: ZeroVec<[u8; 3]> =
502    ///     zv_char.try_into_converted().expect("length is divisible");
503    ///
504    /// assert!(zv_u8_3.is_owned());
505    /// assert_eq!(zv_u8_3.get(0), Some([0x7F, 0xF3, 0x01]));
506    /// ```
507    ///
508    /// If the types are not the same size, we refuse to convert:
509    ///
510    /// ```should_panic
511    /// use zerovec::ZeroVec;
512    ///
513    /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01];
514    /// let zv_char: ZeroVec<char> =
515    ///     ZeroVec::parse_byte_slice(bytes).expect("valid code points");
516    ///
517    /// // Panics! mem::size_of::<char::ULE> != mem::size_of::<u16::ULE>
518    /// zv_char.try_into_converted::<u16>();
519    /// ```
520    ///
521    /// Instead, convert to bytes and then parse:
522    ///
523    /// ```
524    /// use zerovec::ZeroVec;
525    ///
526    /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01];
527    /// let zv_char: ZeroVec<char> =
528    ///     ZeroVec::parse_byte_slice(bytes).expect("valid code points");
529    /// let zv_u16: ZeroVec<u16> =
530    ///     zv_char.into_bytes().try_into_parsed().expect("infallible");
531    ///
532    /// assert!(!zv_u16.is_owned());
533    /// assert_eq!(zv_u16.get(0), Some(0xF37F));
534    /// ```
535    pub fn try_into_converted<P: AsULE>(self) -> Result<ZeroVec<'a, P>, ZeroVecError> {
536        assert_eq!(
537            core::mem::size_of::<<T as AsULE>::ULE>(),
538            core::mem::size_of::<<P as AsULE>::ULE>()
539        );
540        match self.into_cow() {
541            Cow::Borrowed(old_slice) => {
542                let bytes: &'a [u8] = T::ULE::as_byte_slice(old_slice);
543                let new_slice = P::ULE::parse_byte_slice(bytes)?;
544                Ok(ZeroVec::new_borrowed(new_slice))
545            }
546            Cow::Owned(old_vec) => {
547                let bytes: &[u8] = T::ULE::as_byte_slice(&old_vec);
548                P::ULE::validate_byte_slice(bytes)?;
549                // Feature "vec_into_raw_parts" is not yet stable (#65816). Polyfill:
550                let (ptr, len, cap) = {
551                    // Take ownership of the pointer
552                    let mut v = mem::ManuallyDrop::new(old_vec);
553                    // Fetch the pointer, length, and capacity
554                    (v.as_mut_ptr(), v.len(), v.capacity())
555                };
556                // Safety checklist for Vec::from_raw_parts:
557                // 1. ptr came from a Vec<T>
558                // 2. P and T are asserted above to be the same size
559                // 3. length is what it was before
560                // 4. capacity is what it was before
561                let new_vec = unsafe {
562                    let ptr = ptr as *mut P::ULE;
563                    Vec::from_raw_parts(ptr, len, cap)
564                };
565                Ok(ZeroVec::new_owned(new_vec))
566            }
567        }
568    }
569
570    /// Check if this type is fully owned
571    #[inline]
572    pub fn is_owned(&self) -> bool {
573        self.vector.capacity != 0
574    }
575
576    /// If this is a borrowed ZeroVec, return it as a slice that covers
577    /// its lifetime parameter
578    #[inline]
579    pub fn as_maybe_borrowed(&self) -> Option<&'a ZeroSlice<T>> {
580        if self.is_owned() {
581            None
582        } else {
583            // We can extend the lifetime of the slice to 'a
584            // since we know it is borrowed
585            let ule_slice = unsafe { self.vector.as_arbitrary_slice() };
586            Some(ZeroSlice::from_ule_slice(ule_slice))
587        }
588    }
589
590    /// If the ZeroVec is owned, returns the capacity of the vector.
591    ///
592    /// Otherwise, if the ZeroVec is borrowed, returns `None`.
593    ///
594    /// # Examples
595    ///
596    /// ```
597    /// use zerovec::ZeroVec;
598    ///
599    /// let mut zv = ZeroVec::<u8>::new_borrowed(&[0, 1, 2, 3]);
600    /// assert!(!zv.is_owned());
601    /// assert_eq!(zv.owned_capacity(), None);
602    ///
603    /// // Convert to owned without appending anything
604    /// zv.with_mut(|v| ());
605    /// assert!(zv.is_owned());
606    /// assert_eq!(zv.owned_capacity(), Some(4.try_into().unwrap()));
607    ///
608    /// // Double the size by appending
609    /// zv.with_mut(|v| v.push(0));
610    /// assert!(zv.is_owned());
611    /// assert_eq!(zv.owned_capacity(), Some(8.try_into().unwrap()));
612    /// ```
613    #[inline]
614    pub fn owned_capacity(&self) -> Option<NonZeroUsize> {
615        NonZeroUsize::try_from(self.vector.capacity).ok()
616    }
617}
618
619impl<'a> ZeroVec<'a, u8> {
620    /// Converts a `ZeroVec<u8>` into a `ZeroVec<T>`, retaining the current ownership model.
621    ///
622    /// Note that the length of the ZeroVec may change.
623    ///
624    /// # Examples
625    ///
626    /// Convert a borrowed `ZeroVec`:
627    ///
628    /// ```
629    /// use zerovec::ZeroVec;
630    ///
631    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
632    /// let zv_bytes = ZeroVec::new_borrowed(bytes);
633    /// let zerovec: ZeroVec<u16> = zv_bytes.try_into_parsed().expect("infallible");
634    ///
635    /// assert!(!zerovec.is_owned());
636    /// assert_eq!(zerovec.get(0), Some(211));
637    /// ```
638    ///
639    /// Convert an owned `ZeroVec`:
640    ///
641    /// ```
642    /// use zerovec::ZeroVec;
643    ///
644    /// let bytes: Vec<u8> = vec![0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
645    /// let zv_bytes = ZeroVec::new_owned(bytes);
646    /// let zerovec: ZeroVec<u16> = zv_bytes.try_into_parsed().expect("infallible");
647    ///
648    /// assert!(zerovec.is_owned());
649    /// assert_eq!(zerovec.get(0), Some(211));
650    /// ```
651    pub fn try_into_parsed<T: AsULE>(self) -> Result<ZeroVec<'a, T>, ZeroVecError> {
652        match self.into_cow() {
653            Cow::Borrowed(bytes) => {
654                let slice: &'a [T::ULE] = T::ULE::parse_byte_slice(bytes)?;
655                Ok(ZeroVec::new_borrowed(slice))
656            }
657            Cow::Owned(vec) => {
658                let slice = Vec::from(T::ULE::parse_byte_slice(&vec)?);
659                Ok(ZeroVec::new_owned(slice))
660            }
661        }
662    }
663}
664
665impl<'a, T> ZeroVec<'a, T>
666where
667    T: AsULE,
668{
669    /// Creates a `ZeroVec<T>` from a `&[T]` by allocating memory.
670    ///
671    /// This function results in an `Owned` instance of `ZeroVec<T>`.
672    ///
673    /// # Example
674    ///
675    /// ```
676    /// use zerovec::ZeroVec;
677    ///
678    /// // The little-endian bytes correspond to the numbers on the following line.
679    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
680    /// let nums: &[u16] = &[211, 281, 421, 461];
681    ///
682    /// let zerovec = ZeroVec::alloc_from_slice(nums);
683    ///
684    /// assert!(zerovec.is_owned());
685    /// assert_eq!(bytes, zerovec.as_bytes());
686    /// ```
687    #[inline]
688    pub fn alloc_from_slice(other: &[T]) -> Self {
689        Self::new_owned(other.iter().copied().map(T::to_unaligned).collect())
690    }
691
692    /// Creates a `Vec<T>` from a `ZeroVec<T>`.
693    ///
694    /// # Example
695    ///
696    /// ```
697    /// use zerovec::ZeroVec;
698    ///
699    /// let nums: &[u16] = &[211, 281, 421, 461];
700    /// let vec: Vec<u16> = ZeroVec::alloc_from_slice(nums).to_vec();
701    ///
702    /// assert_eq!(nums, vec.as_slice());
703    /// ```
704    #[inline]
705    pub fn to_vec(&self) -> Vec<T> {
706        self.iter().collect()
707    }
708}
709
710impl<'a, T> ZeroVec<'a, T>
711where
712    T: EqULE,
713{
714    /// Attempts to create a `ZeroVec<'a, T>` from a `&'a [T]` by borrowing the argument.
715    ///
716    /// If this is not possible, such as on a big-endian platform, `None` is returned.
717    ///
718    /// # Example
719    ///
720    /// ```
721    /// use zerovec::ZeroVec;
722    ///
723    /// // The little-endian bytes correspond to the numbers on the following line.
724    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
725    /// let nums: &[u16] = &[211, 281, 421, 461];
726    ///
727    /// if let Some(zerovec) = ZeroVec::try_from_slice(nums) {
728    ///     assert!(!zerovec.is_owned());
729    ///     assert_eq!(bytes, zerovec.as_bytes());
730    /// }
731    /// ```
732    #[inline]
733    pub fn try_from_slice(slice: &'a [T]) -> Option<Self> {
734        T::slice_to_unaligned(slice).map(|ule_slice| Self::new_borrowed(ule_slice))
735    }
736
737    /// Creates a `ZeroVec<'a, T>` from a `&'a [T]`, either by borrowing the argument or by
738    /// allocating a new vector.
739    ///
740    /// This is a cheap operation on little-endian platforms, falling back to a more expensive
741    /// operation on big-endian platforms.
742    ///
743    /// # Example
744    ///
745    /// ```
746    /// use zerovec::ZeroVec;
747    ///
748    /// // The little-endian bytes correspond to the numbers on the following line.
749    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
750    /// let nums: &[u16] = &[211, 281, 421, 461];
751    ///
752    /// let zerovec = ZeroVec::from_slice_or_alloc(nums);
753    ///
754    /// // Note: zerovec could be either borrowed or owned.
755    /// assert_eq!(bytes, zerovec.as_bytes());
756    /// ```
757    #[inline]
758    pub fn from_slice_or_alloc(slice: &'a [T]) -> Self {
759        Self::try_from_slice(slice).unwrap_or_else(|| Self::alloc_from_slice(slice))
760    }
761}
762
763impl<'a, T> ZeroVec<'a, T>
764where
765    T: AsULE,
766{
767    /// Mutates each element according to a given function, meant to be
768    /// a more convenient version of calling `.iter_mut()` with
769    /// [`ZeroVec::with_mut()`] which serves fewer use cases.
770    ///
771    /// This will convert the ZeroVec into an owned ZeroVec if not already the case.
772    ///
773    /// # Example
774    ///
775    /// ```
776    /// use zerovec::ZeroVec;
777    ///
778    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
779    /// let mut zerovec: ZeroVec<u16> =
780    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
781    ///
782    /// zerovec.for_each_mut(|item| *item += 1);
783    ///
784    /// assert_eq!(zerovec.to_vec(), &[212, 282, 422, 462]);
785    /// assert!(zerovec.is_owned());
786    /// ```
787    #[inline]
788    pub fn for_each_mut(&mut self, mut f: impl FnMut(&mut T)) {
789        self.to_mut_slice().iter_mut().for_each(|item| {
790            let mut aligned = T::from_unaligned(*item);
791            f(&mut aligned);
792            *item = aligned.to_unaligned()
793        })
794    }
795
796    /// Same as [`ZeroVec::for_each_mut()`], but bubbles up errors.
797    ///
798    /// # Example
799    ///
800    /// ```
801    /// use zerovec::ZeroVec;
802    ///
803    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
804    /// let mut zerovec: ZeroVec<u16> =
805    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
806    ///
807    /// zerovec.try_for_each_mut(|item| {
808    ///     *item = item.checked_add(1).ok_or(())?;
809    ///     Ok(())
810    /// })?;
811    ///
812    /// assert_eq!(zerovec.to_vec(), &[212, 282, 422, 462]);
813    /// assert!(zerovec.is_owned());
814    /// # Ok::<(), ()>(())
815    /// ```
816    #[inline]
817    pub fn try_for_each_mut<E>(
818        &mut self,
819        mut f: impl FnMut(&mut T) -> Result<(), E>,
820    ) -> Result<(), E> {
821        self.to_mut_slice().iter_mut().try_for_each(|item| {
822            let mut aligned = T::from_unaligned(*item);
823            f(&mut aligned)?;
824            *item = aligned.to_unaligned();
825            Ok(())
826        })
827    }
828
829    /// Converts a borrowed ZeroVec to an owned ZeroVec. No-op if already owned.
830    ///
831    /// # Example
832    ///
833    /// ```
834    /// use zerovec::ZeroVec;
835    ///
836    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
837    /// let zerovec: ZeroVec<u16> =
838    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
839    /// assert!(!zerovec.is_owned());
840    ///
841    /// let owned = zerovec.into_owned();
842    /// assert!(owned.is_owned());
843    /// ```
844    pub fn into_owned(self) -> ZeroVec<'static, T> {
845        match self.into_cow() {
846            Cow::Owned(vec) => ZeroVec::new_owned(vec),
847            Cow::Borrowed(b) => {
848                let vec: Vec<T::ULE> = b.into();
849                ZeroVec::new_owned(vec)
850            }
851        }
852    }
853
854    /// Allows the ZeroVec to be mutated by converting it to an owned variant, and producing
855    /// a mutable vector of ULEs. If you only need a mutable slice, consider using [`Self::to_mut_slice()`]
856    /// instead.
857    ///
858    /// # Example
859    ///
860    /// ```rust
861    /// # use crate::zerovec::ule::AsULE;
862    /// use zerovec::ZeroVec;
863    ///
864    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
865    /// let mut zerovec: ZeroVec<u16> =
866    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
867    /// assert!(!zerovec.is_owned());
868    ///
869    /// zerovec.with_mut(|v| v.push(12_u16.to_unaligned()));
870    /// assert!(zerovec.is_owned());
871    /// ```
872    pub fn with_mut<R>(&mut self, f: impl FnOnce(&mut Vec<T::ULE>) -> R) -> R {
873        // We're in danger if f() panics whilst we've moved a vector out of self;
874        // replace it with an empty dummy vector for now
875        let this = mem::take(self);
876        let mut vec = match this.into_cow() {
877            Cow::Owned(v) => v,
878            Cow::Borrowed(s) => s.into(),
879        };
880        let ret = f(&mut vec);
881        *self = Self::new_owned(vec);
882        ret
883    }
884
885    /// Allows the ZeroVec to be mutated by converting it to an owned variant (if necessary)
886    /// and returning a slice to its backing buffer. [`Self::with_mut()`] allows for mutation
887    /// of the vector itself.
888    ///
889    /// # Example
890    ///
891    /// ```rust
892    /// # use crate::zerovec::ule::AsULE;
893    /// use zerovec::ZeroVec;
894    ///
895    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
896    /// let mut zerovec: ZeroVec<u16> =
897    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
898    /// assert!(!zerovec.is_owned());
899    ///
900    /// zerovec.to_mut_slice()[1] = 5u16.to_unaligned();
901    /// assert!(zerovec.is_owned());
902    /// ```
903    pub fn to_mut_slice(&mut self) -> &mut [T::ULE] {
904        if !self.is_owned() {
905            // `buf` is either a valid vector or slice of `T::ULE`s, either
906            // way it's always valid
907            let slice = self.vector.as_slice();
908            *self = ZeroVec::new_owned(slice.into());
909        }
910        unsafe { self.vector.buf.as_mut() }
911    }
912    /// Remove all elements from this ZeroVec and reset it to an empty borrowed state.
913    pub fn clear(&mut self) {
914        *self = Self::new_borrowed(&[])
915    }
916
917    /// Removes the first element of the ZeroVec. The ZeroVec remains in the same
918    /// borrowed or owned state.
919    ///
920    /// # Examples
921    ///
922    /// ```
923    /// # use crate::zerovec::ule::AsULE;
924    /// use zerovec::ZeroVec;
925    ///
926    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
927    /// let mut zerovec: ZeroVec<u16> =
928    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
929    /// assert!(!zerovec.is_owned());
930    ///
931    /// let first = zerovec.take_first().unwrap();
932    /// assert_eq!(first, 0x00D3);
933    /// assert!(!zerovec.is_owned());
934    ///
935    /// let mut zerovec = zerovec.into_owned();
936    /// assert!(zerovec.is_owned());
937    /// let first = zerovec.take_first().unwrap();
938    /// assert_eq!(first, 0x0119);
939    /// assert!(zerovec.is_owned());
940    /// ```
941    pub fn take_first(&mut self) -> Option<T> {
942        match core::mem::take(self).into_cow() {
943            Cow::Owned(mut vec) => {
944                if vec.is_empty() {
945                    return None;
946                }
947                let ule = vec.remove(0);
948                let rv = T::from_unaligned(ule);
949                *self = ZeroVec::new_owned(vec);
950                Some(rv)
951            }
952            Cow::Borrowed(b) => {
953                let (ule, remainder) = b.split_first()?;
954                let rv = T::from_unaligned(*ule);
955                *self = ZeroVec::new_borrowed(remainder);
956                Some(rv)
957            }
958        }
959    }
960
961    /// Removes the last element of the ZeroVec. The ZeroVec remains in the same
962    /// borrowed or owned state.
963    ///
964    /// # Examples
965    ///
966    /// ```
967    /// # use crate::zerovec::ule::AsULE;
968    /// use zerovec::ZeroVec;
969    ///
970    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01];
971    /// let mut zerovec: ZeroVec<u16> =
972    ///     ZeroVec::parse_byte_slice(bytes).expect("infallible");
973    /// assert!(!zerovec.is_owned());
974    ///
975    /// let last = zerovec.take_last().unwrap();
976    /// assert_eq!(last, 0x01CD);
977    /// assert!(!zerovec.is_owned());
978    ///
979    /// let mut zerovec = zerovec.into_owned();
980    /// assert!(zerovec.is_owned());
981    /// let last = zerovec.take_last().unwrap();
982    /// assert_eq!(last, 0x01A5);
983    /// assert!(zerovec.is_owned());
984    /// ```
985    pub fn take_last(&mut self) -> Option<T> {
986        match core::mem::take(self).into_cow() {
987            Cow::Owned(mut vec) => {
988                let ule = vec.pop()?;
989                let rv = T::from_unaligned(ule);
990                *self = ZeroVec::new_owned(vec);
991                Some(rv)
992            }
993            Cow::Borrowed(b) => {
994                let (ule, remainder) = b.split_last()?;
995                let rv = T::from_unaligned(*ule);
996                *self = ZeroVec::new_borrowed(remainder);
997                Some(rv)
998            }
999        }
1000    }
1001
1002    /// Converts the type into a `Cow<'a, [T::ULE]>`, which is
1003    /// the logical equivalent of this type's internal representation
1004    #[inline]
1005    pub fn into_cow(self) -> Cow<'a, [T::ULE]> {
1006        let this = mem::ManuallyDrop::new(self);
1007        if this.is_owned() {
1008            let vec = unsafe {
1009                // safe to call: we know it's owned,
1010                // and `self`/`this` are thenceforth no longer used or dropped
1011                { this }.vector.get_vec()
1012            };
1013            Cow::Owned(vec)
1014        } else {
1015            // We can extend the lifetime of the slice to 'a
1016            // since we know it is borrowed
1017            let slice = unsafe { { this }.vector.as_arbitrary_slice() };
1018            Cow::Borrowed(slice)
1019        }
1020    }
1021}
1022
1023impl<T: AsULE> FromIterator<T> for ZeroVec<'_, T> {
1024    /// Creates an owned [`ZeroVec`] from an iterator of values.
1025    fn from_iter<I>(iter: I) -> Self
1026    where
1027        I: IntoIterator<Item = T>,
1028    {
1029        ZeroVec::new_owned(iter.into_iter().map(|t| t.to_unaligned()).collect())
1030    }
1031}
1032
1033/// Convenience wrapper for [`ZeroSlice::from_ule_slice`]. The value will be created at compile-time,
1034/// meaning that all arguments must also be constant.
1035///
1036/// # Arguments
1037///
1038/// * `$aligned` - The type of an element in its canonical, aligned form, e.g., `char`.
1039/// * `$convert` - A const function that converts an `$aligned` into its unaligned equivalent, e.g.,
1040///                 `const fn from_aligned(a: CanonicalType) -> CanonicalType::ULE`.
1041/// * `$x` - The elements that the `ZeroSlice` will hold.
1042///
1043/// # Examples
1044///
1045/// Using array-conversion functions provided by this crate:
1046///
1047/// ```
1048/// use zerovec::{ZeroSlice, zeroslice, ule::AsULE};
1049/// use zerovec::ule::UnvalidatedChar;
1050///
1051/// const SIGNATURE: &ZeroSlice<char> = zeroslice!(char; <char as AsULE>::ULE::from_aligned; ['b', 'y', 'e', '✌']);
1052/// const EMPTY: &ZeroSlice<u32> = zeroslice![];
1053/// const UC: &ZeroSlice<UnvalidatedChar> =
1054///     zeroslice!(
1055///         UnvalidatedChar;
1056///         <UnvalidatedChar as AsULE>::ULE::from_unvalidated_char;
1057///         [UnvalidatedChar::from_char('a')]
1058///     );
1059/// let empty: &ZeroSlice<u32> = zeroslice![];
1060/// let nums = zeroslice!(u32; <u32 as AsULE>::ULE::from_unsigned; [1, 2, 3, 4, 5]);
1061/// assert_eq!(nums.last().unwrap(), 5);
1062/// ```
1063///
1064/// Using a custom array-conversion function:
1065///
1066/// ```
1067/// use zerovec::{ule::AsULE, ule::RawBytesULE, zeroslice, ZeroSlice};
1068///
1069/// const fn be_convert(num: i16) -> <i16 as AsULE>::ULE {
1070///     RawBytesULE(num.to_be_bytes())
1071/// }
1072///
1073/// const NUMBERS_BE: &ZeroSlice<i16> =
1074///     zeroslice!(i16; be_convert; [1, -2, 3, -4, 5]);
1075/// ```
1076#[macro_export]
1077macro_rules! zeroslice {
1078    () => (
1079        $crate::ZeroSlice::new_empty()
1080    );
1081    ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => (
1082        $crate::ZeroSlice::<$aligned>::from_ule_slice(
1083            {const X: &[<$aligned as $crate::ule::AsULE>::ULE] = &[
1084                $($convert($x)),*
1085            ]; X}
1086        )
1087    );
1088}
1089
1090/// Creates a borrowed `ZeroVec`. Convenience wrapper for `zeroslice!(...).as_zerovec()`. The value
1091/// will be created at compile-time, meaning that all arguments must also be constant.
1092///
1093/// See [`zeroslice!`](crate::zeroslice) for more information.
1094///
1095/// # Examples
1096///
1097/// ```
1098/// use zerovec::{ZeroVec, zerovec, ule::AsULE};
1099///
1100/// const SIGNATURE: ZeroVec<char> = zerovec!(char; <char as AsULE>::ULE::from_aligned; ['a', 'y', 'e', '✌']);
1101/// assert!(!SIGNATURE.is_owned());
1102///
1103/// const EMPTY: ZeroVec<u32> = zerovec![];
1104/// assert!(!EMPTY.is_owned());
1105/// ```
1106#[macro_export]
1107macro_rules! zerovec {
1108    () => (
1109        $crate::ZeroVec::new()
1110    );
1111    ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => (
1112        $crate::zeroslice![$aligned; $convert; [$($x),+]].as_zerovec()
1113    );
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118    use super::*;
1119    use crate::samples::*;
1120
1121    #[test]
1122    fn test_get() {
1123        {
1124            let zerovec = ZeroVec::from_slice_or_alloc(TEST_SLICE);
1125            assert_eq!(zerovec.get(0), Some(TEST_SLICE[0]));
1126            assert_eq!(zerovec.get(1), Some(TEST_SLICE[1]));
1127            assert_eq!(zerovec.get(2), Some(TEST_SLICE[2]));
1128        }
1129        {
1130            let zerovec = ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE).unwrap();
1131            assert_eq!(zerovec.get(0), Some(TEST_SLICE[0]));
1132            assert_eq!(zerovec.get(1), Some(TEST_SLICE[1]));
1133            assert_eq!(zerovec.get(2), Some(TEST_SLICE[2]));
1134        }
1135    }
1136
1137    #[test]
1138    fn test_binary_search() {
1139        {
1140            let zerovec = ZeroVec::from_slice_or_alloc(TEST_SLICE);
1141            assert_eq!(Ok(3), zerovec.binary_search(&0x0e0d0c));
1142            assert_eq!(Err(3), zerovec.binary_search(&0x0c0d0c));
1143        }
1144        {
1145            let zerovec = ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE).unwrap();
1146            assert_eq!(Ok(3), zerovec.binary_search(&0x0e0d0c));
1147            assert_eq!(Err(3), zerovec.binary_search(&0x0c0d0c));
1148        }
1149    }
1150
1151    #[test]
1152    fn test_odd_alignment() {
1153        assert_eq!(
1154            Some(0x020100),
1155            ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE)
1156                .unwrap()
1157                .get(0)
1158        );
1159        assert_eq!(
1160            Some(0x04000201),
1161            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[1..77])
1162                .unwrap()
1163                .get(0)
1164        );
1165        assert_eq!(
1166            Some(0x05040002),
1167            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[2..78])
1168                .unwrap()
1169                .get(0)
1170        );
1171        assert_eq!(
1172            Some(0x06050400),
1173            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[3..79])
1174                .unwrap()
1175                .get(0)
1176        );
1177        assert_eq!(
1178            Some(0x060504),
1179            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[4..])
1180                .unwrap()
1181                .get(0)
1182        );
1183        assert_eq!(
1184            Some(0x4e4d4c00),
1185            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[75..79])
1186                .unwrap()
1187                .get(0)
1188        );
1189        assert_eq!(
1190            Some(0x4e4d4c00),
1191            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[3..79])
1192                .unwrap()
1193                .get(18)
1194        );
1195        assert_eq!(
1196            Some(0x4e4d4c),
1197            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[76..])
1198                .unwrap()
1199                .get(0)
1200        );
1201        assert_eq!(
1202            Some(0x4e4d4c),
1203            ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE)
1204                .unwrap()
1205                .get(19)
1206        );
1207        // TODO(#1144): Check for correct slice length in RawBytesULE
1208        // assert_eq!(
1209        //     None,
1210        //     ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[77..])
1211        //         .unwrap()
1212        //         .get(0)
1213        // );
1214        assert_eq!(
1215            None,
1216            ZeroVec::<u32>::parse_byte_slice(TEST_BUFFER_LE)
1217                .unwrap()
1218                .get(20)
1219        );
1220        assert_eq!(
1221            None,
1222            ZeroVec::<u32>::parse_byte_slice(&TEST_BUFFER_LE[3..79])
1223                .unwrap()
1224                .get(19)
1225        );
1226    }
1227}