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