Coverage Report

Created: 2026-01-09 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerovec-0.11.5/src/zerovec/mod.rs
Line
Count
Source
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")]
6
mod databake;
7
8
#[cfg(feature = "serde")]
9
mod serde;
10
11
mod slice;
12
13
pub use slice::ZeroSlice;
14
pub use slice::ZeroSliceIter;
15
16
use crate::ule::*;
17
#[cfg(feature = "alloc")]
18
use alloc::borrow::Cow;
19
#[cfg(feature = "alloc")]
20
use alloc::vec::Vec;
21
use core::cmp::{Ord, Ordering, PartialOrd};
22
use core::fmt;
23
#[cfg(feature = "alloc")]
24
use core::iter::FromIterator;
25
use core::marker::PhantomData;
26
use core::num::NonZeroUsize;
27
use core::ops::Deref;
28
use 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.
92
pub struct ZeroVec<'a, T>
93
where
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.
107
unsafe 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
109
unsafe impl<'a, T: AsULE> Sync for ZeroVec<'a, T> where T::ULE: Sync {}
110
111
impl<'a, T: AsULE> Deref for ZeroVec<'a, T> {
112
    type Target = ZeroSlice<T>;
113
    #[inline]
114
0
    fn deref(&self) -> &Self::Target {
115
0
        self.as_slice()
116
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::JoiningType> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::BidiClass> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::gc::GeneralCategory> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::script::ScriptWithExt> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<char> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u32> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<potential_utf::uchar::PotentialCodePoint> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u8> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u16> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_> as core::ops::deref::Deref>::deref
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]
128
struct 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
138
impl<U> EyepatchHackVector<U> {
139
    // Return a slice to the inner data for an arbitrary caller-specified lifetime
140
    #[inline]
141
0
    unsafe fn as_arbitrary_slice<'a>(&self) -> &'a [U] {
142
0
        self.buf.as_ref()
143
0
    }
144
    // Return a slice to the inner data
145
    #[inline]
146
0
    const fn as_slice<'a>(&'a self) -> &'a [U] {
147
        // Note: self.buf.as_ref() is not const until 1.73
148
0
        unsafe { &*(self.buf.as_ptr() as *const [U]) }
149
0
    }
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<icu_properties::props::gc::GeneralCategoryULE>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<zerovec::ule::niche::NichedOptionULE<icu_locale_core::subtags::script::Script, 4>>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<zerovec::ule::plain::RawBytesULE<4>>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<zerovec::ule::chars::CharULE>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<zerovec::ule::plain::RawBytesULE<2>>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<zerovec::ule::plain::RawBytesULE<3>>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<u8>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::EyepatchHackVector<_>>::as_slice
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
0
    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
0
        self.buf = unsafe {
177
0
            NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
178
0
                self.buf.as_mut().as_mut_ptr(),
179
0
                core::cmp::min(max, self.buf.as_ref().len()),
180
0
            ))
181
0
        };
182
0
    }
183
}
184
185
#[cfg(feature = "alloc")]
186
impl<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
198
impl<'a, T: AsULE> Clone for ZeroVec<'a, T> {
199
0
    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
0
        Self {
205
0
            vector: EyepatchHackVector {
206
0
                buf: self.vector.buf,
207
0
                #[cfg(feature = "alloc")]
208
0
                capacity: 0,
209
0
            },
210
0
            marker1: PhantomData,
211
0
            marker2: PhantomData,
212
0
        }
213
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u16> as core::clone::Clone>::clone
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_> as core::clone::Clone>::clone
214
}
215
216
impl<'a, T: AsULE> AsRef<ZeroSlice<T>> for ZeroVec<'a, T> {
217
0
    fn as_ref(&self) -> &ZeroSlice<T> {
218
0
        self.as_slice()
219
0
    }
220
}
221
222
impl<T> fmt::Debug for ZeroVec<'_, T>
223
where
224
    T: AsULE + fmt::Debug,
225
{
226
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227
0
        write!(f, "ZeroVec([")?;
228
0
        let mut first = true;
229
0
        for el in self.iter() {
230
0
            if !first {
231
0
                write!(f, ", ")?;
232
0
            }
233
0
            write!(f, "{el:?}")?;
234
0
            first = false;
235
        }
236
0
        write!(f, "])")
237
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<potential_utf::uchar::PotentialCodePoint> as core::fmt::Debug>::fmt
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_> as core::fmt::Debug>::fmt
238
}
239
240
impl<T> Eq for ZeroVec<'_, T> where T: AsULE + Eq {}
241
242
impl<'a, 'b, T> PartialEq<ZeroVec<'b, T>> for ZeroVec<'a, T>
243
where
244
    T: AsULE + PartialEq,
245
{
246
    #[inline]
247
0
    fn eq(&self, other: &ZeroVec<'b, T>) -> bool {
248
        // Note: T implements PartialEq but not T::ULE
249
0
        self.iter().eq(other.iter())
250
0
    }
251
}
252
253
impl<T> PartialEq<&[T]> for ZeroVec<'_, T>
254
where
255
    T: AsULE + PartialEq,
256
{
257
    #[inline]
258
0
    fn eq(&self, other: &&[T]) -> bool {
259
0
        self.iter().eq(other.iter().copied())
260
0
    }
261
}
262
263
impl<T, const N: usize> PartialEq<[T; N]> for ZeroVec<'_, T>
264
where
265
    T: AsULE + PartialEq,
266
{
267
    #[inline]
268
0
    fn eq(&self, other: &[T; N]) -> bool {
269
0
        self.iter().eq(other.iter().copied())
270
0
    }
271
}
272
273
impl<'a, T: AsULE> Default for ZeroVec<'a, T> {
274
    #[inline]
275
0
    fn default() -> Self {
276
0
        Self::new()
277
0
    }
278
}
279
280
impl<'a, T: AsULE + PartialOrd> PartialOrd for ZeroVec<'a, T> {
281
0
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
282
0
        self.iter().partial_cmp(other.iter())
283
0
    }
284
}
285
286
impl<'a, T: AsULE + Ord> Ord for ZeroVec<'a, T> {
287
0
    fn cmp(&self, other: &Self) -> Ordering {
288
0
        self.iter().cmp(other.iter())
289
0
    }
290
}
291
292
impl<'a, T: AsULE> AsRef<[T::ULE]> for ZeroVec<'a, T> {
293
0
    fn as_ref(&self) -> &[T::ULE] {
294
0
        self.as_ule_slice()
295
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u8> as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_> as core::convert::AsRef<[<_ as zerovec::ule::AsULE>::ULE]>>::as_ref
296
}
297
298
impl<'a, T: AsULE> From<&'a [T::ULE]> for ZeroVec<'a, T> {
299
0
    fn from(other: &'a [T::ULE]) -> Self {
300
0
        ZeroVec::new_borrowed(other)
301
0
    }
302
}
303
304
#[cfg(feature = "alloc")]
305
impl<'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
311
impl<'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
0
    pub const fn new() -> Self {
324
0
        Self::new_borrowed(&[])
325
0
    }
326
327
    /// Same as `ZeroSlice::len`, which is available through `Deref` and not `const`.
328
0
    pub const fn const_len(&self) -> usize {
329
0
        self.vector.as_slice().len()
330
0
    }
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
0
    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
0
        let slice = unsafe { NonNull::new_unchecked(slice as *const [_] as *mut [_]) };
369
0
        Self {
370
0
            vector: EyepatchHackVector {
371
0
                buf: slice,
372
0
                #[cfg(feature = "alloc")]
373
0
                capacity: 0,
374
0
            },
375
0
            marker1: PhantomData,
376
0
            marker2: PhantomData,
377
0
        }
378
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::script::ScriptWithExt>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<char>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u32>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<potential_utf::uchar::PotentialCodePoint>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u8>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u16>>::new_borrowed
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_>>::new_borrowed
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
0
    pub fn parse_bytes(bytes: &'a [u8]) -> Result<Self, UleError> {
413
0
        let slice: &'a [T::ULE] = T::ULE::parse_bytes_to_slice(bytes)?;
414
0
        Ok(Self::new_borrowed(slice))
415
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u8>>::parse_bytes
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u16>>::parse_bytes
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_>>::parse_bytes
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
0
    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
0
        Self::new_borrowed(core::slice::from_raw_parts(
425
0
            bytes.as_ptr() as *const T::ULE,
426
0
            bytes.len() / core::mem::size_of::<T::ULE>(),
427
0
        ))
428
0
    }
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
0
    pub const fn as_slice(&self) -> &ZeroSlice<T> {
485
0
        let slice: &[T::ULE] = self.vector.as_slice();
486
0
        ZeroSlice::from_ule_slice(slice)
487
0
    }
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::JoiningType>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::BidiClass>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::props::gc::GeneralCategory>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<icu_properties::script::ScriptWithExt>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<char>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u32>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<potential_utf::uchar::PotentialCodePoint>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u8>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<u16>>::as_slice
Unexecuted instantiation: <zerovec::zerovec::ZeroVec<_>>::as_slice
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
0
    pub fn is_owned(&self) -> bool {
630
        #[cfg(feature = "alloc")]
631
        return self.vector.capacity != 0;
632
        #[cfg(not(feature = "alloc"))]
633
0
        return false;
634
0
    }
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
0
    pub fn as_maybe_borrowed(&self) -> Option<&'a ZeroSlice<T>> {
643
0
        if self.is_owned() {
644
0
            None
645
        } else {
646
            // We can extend the lifetime of the slice to 'a
647
            // since we know it is borrowed
648
0
            let ule_slice = unsafe { self.vector.as_arbitrary_slice() };
649
0
            Some(ZeroSlice::from_ule_slice(ule_slice))
650
        }
651
0
    }
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
0
    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
0
        return None;
682
0
    }
683
}
684
685
impl<'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
734
impl<'a, T> ZeroVec<'a, T>
735
where
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
785
impl<'a, T> ZeroVec<'a, T>
786
where
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
0
    pub fn try_from_slice(slice: &'a [T]) -> Option<Self> {
809
0
        T::slice_to_unaligned(slice).map(|ule_slice| Self::new_borrowed(ule_slice))
810
0
    }
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
841
impl<'a, T> ZeroVec<'a, T>
842
where
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
0
    pub fn clear(&mut self) {
1006
0
        *self = Self::new_borrowed(&[])
1007
0
    }
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
0
    pub fn truncated(mut self, max: usize) -> Self {
1126
0
        self.vector.truncate(max);
1127
0
        self
1128
0
    }
1129
}
1130
1131
#[cfg(feature = "alloc")]
1132
impl<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]
1180
macro_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]
1206
macro_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)]
1216
mod 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
}