Coverage Report

Created: 2025-10-31 06:57

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