Coverage Report

Created: 2026-11-12 06:36

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