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}