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}