Coverage Report

Created: 2025-09-27 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerovec-0.11.4/src/zerovec/slice.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
use super::*;
6
use core::cmp::Ordering;
7
use core::ops::Range;
8
9
/// A zero-copy "slice", i.e. the zero-copy version of `[T]`.
10
///
11
/// This behaves
12
/// similarly to [`ZeroVec<T>`], however [`ZeroVec<T>`] is allowed to contain
13
/// owned data and as such is ideal for deserialization since most human readable
14
/// serialization formats cannot unconditionally deserialize zero-copy.
15
///
16
/// This type can be used inside [`VarZeroVec<T>`](crate::VarZeroVec) and [`ZeroMap`](crate::ZeroMap):
17
/// This essentially allows for the construction of zero-copy types isomorphic to `Vec<Vec<T>>` by instead
18
/// using `VarZeroVec<ZeroSlice<T>>`. See the [`VarZeroVec`](crate::VarZeroVec) docs for an example.
19
///
20
/// # Examples
21
///
22
/// Const-construct a ZeroSlice of u16:
23
///
24
/// ```
25
/// use zerovec::ule::AsULE;
26
/// use zerovec::ZeroSlice;
27
///
28
/// const DATA: &ZeroSlice<u16> =
29
///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
30
///         211, 281, 421, 32973,
31
///     ]));
32
///
33
/// assert_eq!(DATA.get(1), Some(281));
34
/// ```
35
#[repr(transparent)]
36
pub struct ZeroSlice<T: AsULE>([T::ULE]);
37
38
impl<T> ZeroSlice<T>
39
where
40
    T: AsULE,
41
{
42
    /// Returns an empty slice.
43
0
    pub const fn new_empty() -> &'static Self {
44
0
        Self::from_ule_slice(&[])
45
0
    }
46
47
    /// Get this [`ZeroSlice`] as a borrowed [`ZeroVec`]
48
    ///
49
    /// [`ZeroSlice`] does not have most of the methods that [`ZeroVec`] does,
50
    /// so it is recommended to convert it to a [`ZeroVec`] before doing anything.
51
    #[inline]
52
0
    pub const fn as_zerovec(&self) -> ZeroVec<'_, T> {
53
0
        ZeroVec::new_borrowed(&self.0)
54
0
    }
55
56
    /// Attempt to construct a `&ZeroSlice<T>` from a byte slice, returning an error
57
    /// if it's not a valid byte sequence
58
0
    pub fn parse_bytes(bytes: &[u8]) -> Result<&Self, UleError> {
59
0
        T::ULE::parse_bytes_to_slice(bytes).map(Self::from_ule_slice)
60
0
    }
61
62
    /// Uses a `&[u8]` buffer as a `ZeroVec<T>` without any verification.
63
    ///
64
    /// # Safety
65
    ///
66
    /// `bytes` need to be an output from [`ZeroSlice::as_bytes()`].
67
0
    pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
68
        // &[u8] and &[T::ULE] are the same slice with different length metadata.
69
0
        Self::from_ule_slice(core::slice::from_raw_parts(
70
0
            bytes.as_ptr() as *const T::ULE,
71
0
            bytes.len() / core::mem::size_of::<T::ULE>(),
72
0
        ))
73
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<bool>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u8>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u32>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u128>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u64>>::from_bytes_unchecked
74
75
    /// Construct a `&ZeroSlice<T>` from a slice of ULEs.
76
    ///
77
    /// This function can be used for constructing ZeroVecs in a const context, avoiding
78
    /// parsing checks.
79
    ///
80
    /// See [`ZeroSlice`] for an example.
81
    #[inline]
82
2.56G
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
2.56G
        unsafe { &*(slice as *const _ as *const Self) }
86
2.56G
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::JoiningType>>::from_ule_slice
Line
Count
Source
82
544k
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
544k
        unsafe { &*(slice as *const _ as *const Self) }
86
544k
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::BidiClass>>::from_ule_slice
Line
Count
Source
82
19.9M
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
19.9M
        unsafe { &*(slice as *const _ as *const Self) }
86
19.9M
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::gc::GeneralCategory>>::from_ule_slice
Line
Count
Source
82
79.3M
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
79.3M
        unsafe { &*(slice as *const _ as *const Self) }
86
79.3M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>>>::from_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::from_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::script::ScriptWithExt>>::from_ule_slice
<zerovec::zerovec::slice::ZeroSlice<char>>::from_ule_slice
Line
Count
Source
82
158M
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
158M
        unsafe { &*(slice as *const _ as *const Self) }
86
158M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::from_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<bool>>::from_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u8>>::from_ule_slice
<zerovec::zerovec::slice::ZeroSlice<u32>>::from_ule_slice
Line
Count
Source
82
436M
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
436M
        unsafe { &*(slice as *const _ as *const Self) }
86
436M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u128>>::from_ule_slice
<zerovec::zerovec::slice::ZeroSlice<u16>>::from_ule_slice
Line
Count
Source
82
1.86G
    pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83
        // This is safe because ZeroSlice is transparent over [T::ULE]
84
        // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85
1.86G
        unsafe { &*(slice as *const _ as *const Self) }
86
1.86G
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u64>>::from_ule_slice
87
88
    /// Construct a `Box<ZeroSlice<T>>` from a boxed slice of ULEs
89
    #[inline]
90
    #[cfg(feature = "alloc")]
91
0
    pub fn from_boxed_slice(slice: alloc::boxed::Box<[T::ULE]>) -> alloc::boxed::Box<Self> {
92
        // This is safe because ZeroSlice is transparent over [T::ULE]
93
        // so Box<ZeroSlice<T>> can be safely cast from Box<[T::ULE]>
94
0
        unsafe { alloc::boxed::Box::from_raw(alloc::boxed::Box::into_raw(slice) as *mut Self) }
95
0
    }
96
97
    /// Returns this slice as its underlying `&[u8]` byte buffer representation.
98
    ///
99
    /// Useful for serialization.
100
    ///
101
    /// # Example
102
    ///
103
    /// ```
104
    /// use zerovec::ZeroVec;
105
    ///
106
    /// // The little-endian bytes correspond to the numbers on the following line.
107
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
108
    /// let nums: &[u16] = &[211, 281, 421, 32973];
109
    ///
110
    /// let zerovec = ZeroVec::alloc_from_slice(nums);
111
    ///
112
    /// assert_eq!(bytes, zerovec.as_bytes());
113
    /// ```
114
    #[inline]
115
0
    pub fn as_bytes(&self) -> &[u8] {
116
0
        T::ULE::slice_as_bytes(self.as_ule_slice())
117
0
    }
118
119
    /// Dereferences this slice as `&[T::ULE]`.
120
    #[inline]
121
6.13G
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
6.13G
        &self.0
123
6.13G
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::JoiningType>>::as_ule_slice
Line
Count
Source
121
544k
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
544k
        &self.0
123
544k
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::BidiClass>>::as_ule_slice
Line
Count
Source
121
19.9M
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
19.9M
        &self.0
123
19.9M
    }
<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::gc::GeneralCategory>>::as_ule_slice
Line
Count
Source
121
79.3M
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
79.3M
        &self.0
123
79.3M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>>>::as_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::as_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::script::ScriptWithExt>>::as_ule_slice
<zerovec::zerovec::slice::ZeroSlice<char>>::as_ule_slice
Line
Count
Source
121
160M
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
160M
        &self.0
123
160M
    }
<zerovec::zerovec::slice::ZeroSlice<u32>>::as_ule_slice
Line
Count
Source
121
436M
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
436M
        &self.0
123
436M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::as_ule_slice
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u8>>::as_ule_slice
<zerovec::zerovec::slice::ZeroSlice<u16>>::as_ule_slice
Line
Count
Source
121
5.44G
    pub const fn as_ule_slice(&self) -> &[T::ULE] {
122
5.44G
        &self.0
123
5.44G
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::as_ule_slice
124
125
    /// Returns the number of elements in this slice.
126
    ///
127
    /// # Example
128
    ///
129
    /// ```
130
    /// use zerovec::ule::AsULE;
131
    /// use zerovec::ZeroVec;
132
    ///
133
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
134
    /// let zerovec: ZeroVec<u16> =
135
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
136
    ///
137
    /// assert_eq!(4, zerovec.len());
138
    /// assert_eq!(
139
    ///     bytes.len(),
140
    ///     zerovec.len() * std::mem::size_of::<<u16 as AsULE>::ULE>()
141
    /// );
142
    /// ```
143
    #[inline]
144
482M
    pub const fn len(&self) -> usize {
145
482M
        self.as_ule_slice().len()
146
482M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::JoiningType>>::len
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::BidiClass>>::len
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::gc::GeneralCategory>>::len
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::len
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::script::ScriptWithExt>>::len
<zerovec::zerovec::slice::ZeroSlice<char>>::len
Line
Count
Source
144
160M
    pub const fn len(&self) -> usize {
145
160M
        self.as_ule_slice().len()
146
160M
    }
<zerovec::zerovec::slice::ZeroSlice<u32>>::len
Line
Count
Source
144
882
    pub const fn len(&self) -> usize {
145
882
        self.as_ule_slice().len()
146
882
    }
<zerovec::zerovec::slice::ZeroSlice<u16>>::len
Line
Count
Source
144
321M
    pub const fn len(&self) -> usize {
145
321M
        self.as_ule_slice().len()
146
321M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::len
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::len
147
148
    /// Returns whether this slice is empty.
149
    ///
150
    /// # Example
151
    ///
152
    /// ```
153
    /// use zerovec::ZeroVec;
154
    ///
155
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
156
    /// let zerovec: ZeroVec<u16> =
157
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
158
    /// assert!(!zerovec.is_empty());
159
    ///
160
    /// let emptyvec: ZeroVec<u16> = ZeroVec::parse_bytes(&[]).expect("infallible");
161
    /// assert!(emptyvec.is_empty());
162
    /// ```
163
    #[inline]
164
0
    pub const fn is_empty(&self) -> bool {
165
0
        self.as_ule_slice().is_empty()
166
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::is_empty
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::is_empty
167
}
168
169
impl<T> ZeroSlice<T>
170
where
171
    T: AsULE,
172
{
173
    /// Gets the element at the specified index. Returns `None` if out of range.
174
    ///
175
    /// # Example
176
    ///
177
    /// ```
178
    /// use zerovec::ZeroVec;
179
    ///
180
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
181
    /// let zerovec: ZeroVec<u16> =
182
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
183
    ///
184
    /// assert_eq!(zerovec.get(2), Some(421));
185
    /// assert_eq!(zerovec.get(4), None);
186
    /// ```
187
    #[inline]
188
5.01G
    pub fn get(&self, index: usize) -> Option<T> {
189
5.01G
        self.as_ule_slice()
190
5.01G
            .get(index)
191
5.01G
            .copied()
192
5.01G
            .map(T::from_unaligned)
193
5.01G
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::get
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::get
<zerovec::zerovec::slice::ZeroSlice<u16>>::get
Line
Count
Source
188
5.01G
    pub fn get(&self, index: usize) -> Option<T> {
189
5.01G
        self.as_ule_slice()
190
5.01G
            .get(index)
191
5.01G
            .copied()
192
5.01G
            .map(T::from_unaligned)
193
5.01G
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::get
194
195
    /// Gets the entire slice as an array of length `N`. Returns `None` if the slice
196
    /// does not have exactly `N` elements.
197
    ///
198
    /// # Example
199
    ///
200
    /// ```
201
    /// use zerovec::ZeroVec;
202
    ///
203
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
204
    /// let zerovec: ZeroVec<u16> =
205
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
206
    /// let array: [u16; 4] =
207
    ///     zerovec.get_as_array().expect("should be 4 items in array");
208
    ///
209
    /// assert_eq!(array[2], 421);
210
    /// ```
211
0
    pub fn get_as_array<const N: usize>(&self) -> Option<[T; N]> {
212
0
        let ule_array = <&[T::ULE; N]>::try_from(self.as_ule_slice()).ok()?;
213
0
        Some(ule_array.map(|u| T::from_unaligned(u)))
214
0
    }
215
216
    /// Gets a subslice of elements within a certain range. Returns `None` if the range
217
    /// is out of bounds of this `ZeroSlice`.
218
    ///
219
    /// # Example
220
    ///
221
    /// ```
222
    /// use zerovec::ZeroVec;
223
    ///
224
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
225
    /// let zerovec: ZeroVec<u16> =
226
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
227
    ///
228
    /// assert_eq!(
229
    ///     zerovec.get_subslice(1..3),
230
    ///     Some(&*ZeroVec::from_slice_or_alloc(&[0x0119, 0x01A5]))
231
    /// );
232
    /// assert_eq!(zerovec.get_subslice(3..5), None);
233
    /// ```
234
    #[inline]
235
107M
    pub fn get_subslice(&self, range: Range<usize>) -> Option<&ZeroSlice<T>> {
236
107M
        self.0.get(range).map(ZeroSlice::from_ule_slice)
237
107M
    }
<zerovec::zerovec::slice::ZeroSlice<char>>::get_subslice
Line
Count
Source
235
9.05k
    pub fn get_subslice(&self, range: Range<usize>) -> Option<&ZeroSlice<T>> {
236
9.05k
        self.0.get(range).map(ZeroSlice::from_ule_slice)
237
9.05k
    }
<zerovec::zerovec::slice::ZeroSlice<u16>>::get_subslice
Line
Count
Source
235
107M
    pub fn get_subslice(&self, range: Range<usize>) -> Option<&ZeroSlice<T>> {
236
107M
        self.0.get(range).map(ZeroSlice::from_ule_slice)
237
107M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::get_subslice
238
239
    /// Get a borrowed reference to the underlying ULE type at a specified index.
240
    ///
241
    /// Prefer [`Self::get()`] over this method where possible since working
242
    /// directly with `ULE` types is less ergonomic
243
0
    pub fn get_ule_ref(&self, index: usize) -> Option<&T::ULE> {
244
0
        self.as_ule_slice().get(index)
245
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<zerovec::ule::niche::NichedOption<icu_locale_core::subtags::script::Script, 4>>>::get_ule_ref
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::get_ule_ref
246
247
    /// Casts a `ZeroSlice<T>` to a compatible `ZeroSlice<P>`.
248
    ///
249
    /// `T` and `P` are compatible if they have the same `ULE` representation.
250
    ///
251
    /// If the `ULE`s of `T` and `P` are different, use [`Self::try_as_converted()`].
252
    ///
253
    /// # Examples
254
    ///
255
    /// ```
256
    /// use zerovec::ZeroSlice;
257
    ///
258
    /// const BYTES: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
259
    /// const ZS_U16: &ZeroSlice<u16> = {
260
    ///     match ZeroSlice::<u16>::try_from_bytes(BYTES) {
261
    ///         Ok(s) => s,
262
    ///         Err(_) => unreachable!(),
263
    ///     }
264
    /// };
265
    ///
266
    /// let zs_i16: &ZeroSlice<i16> = ZS_U16.cast();
267
    ///
268
    /// assert_eq!(ZS_U16.get(3), Some(32973));
269
    /// assert_eq!(zs_i16.get(3), Some(-32563));
270
    /// ```
271
    #[inline]
272
0
    pub const fn cast<P>(&self) -> &ZeroSlice<P>
273
0
    where
274
0
        P: AsULE<ULE = T::ULE>,
275
    {
276
0
        ZeroSlice::<P>::from_ule_slice(self.as_ule_slice())
277
0
    }
278
279
    /// Converts a `&ZeroSlice<T>` into a `&ZeroSlice<P>`.
280
    ///
281
    /// The resulting slice will have the same length as the original slice
282
    /// if and only if `T::ULE` and `P::ULE` are the same size.
283
    ///
284
    /// If `T` and `P` have the exact same `ULE`, use [`Self::cast()`].
285
    ///
286
    /// # Examples
287
    ///
288
    /// ```
289
    /// use zerovec::ZeroSlice;
290
    ///
291
    /// const BYTES: &[u8] = &[0x7F, 0xF3, 0x01, 0x00, 0x49, 0xF6, 0x01, 0x00];
292
    /// const ZS_U32: &ZeroSlice<u32> = {
293
    ///     match ZeroSlice::<u32>::try_from_bytes(BYTES) {
294
    ///         Ok(s) => s,
295
    ///         Err(_) => unreachable!(),
296
    ///     }
297
    /// };
298
    ///
299
    /// let zs_u8_4: &ZeroSlice<[u8; 4]> =
300
    ///     ZS_U32.try_as_converted().expect("valid code points");
301
    ///
302
    /// assert_eq!(ZS_U32.get(0), Some(127871));
303
    /// assert_eq!(zs_u8_4.get(0), Some([0x7F, 0xF3, 0x01, 0x00]));
304
    /// ```
305
    #[inline]
306
0
    pub fn try_as_converted<P: AsULE>(&self) -> Result<&ZeroSlice<P>, UleError> {
307
0
        let new_slice = P::ULE::parse_bytes_to_slice(self.as_bytes())?;
308
0
        Ok(ZeroSlice::from_ule_slice(new_slice))
309
0
    }
310
311
    /// Gets the first element. Returns `None` if empty.
312
    ///
313
    /// # Example
314
    ///
315
    /// ```
316
    /// use zerovec::ZeroVec;
317
    ///
318
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
319
    /// let zerovec: ZeroVec<u16> =
320
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
321
    ///
322
    /// assert_eq!(zerovec.first(), Some(211));
323
    /// ```
324
    #[inline]
325
53.5M
    pub fn first(&self) -> Option<T> {
326
53.5M
        self.as_ule_slice().first().copied().map(T::from_unaligned)
327
53.5M
    }
<zerovec::zerovec::slice::ZeroSlice<char>>::first
Line
Count
Source
325
4.52k
    pub fn first(&self) -> Option<T> {
326
4.52k
        self.as_ule_slice().first().copied().map(T::from_unaligned)
327
4.52k
    }
<zerovec::zerovec::slice::ZeroSlice<u16>>::first
Line
Count
Source
325
53.5M
    pub fn first(&self) -> Option<T> {
326
53.5M
        self.as_ule_slice().first().copied().map(T::from_unaligned)
327
53.5M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::first
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::first
328
329
    /// Gets the last element. Returns `None` if empty.
330
    ///
331
    /// # Example
332
    ///
333
    /// ```
334
    /// use zerovec::ZeroVec;
335
    ///
336
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
337
    /// let zerovec: ZeroVec<u16> =
338
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
339
    ///
340
    /// assert_eq!(zerovec.last(), Some(32973));
341
    /// ```
342
    #[inline]
343
0
    pub fn last(&self) -> Option<T> {
344
0
        self.as_ule_slice().last().copied().map(T::from_unaligned)
345
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::last
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u8>>::last
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::last
346
347
    /// Gets an iterator over the elements.
348
    ///
349
    /// # Example
350
    ///
351
    /// ```
352
    /// use zerovec::ZeroVec;
353
    ///
354
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
355
    /// let zerovec: ZeroVec<u16> =
356
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
357
    /// let mut it = zerovec.iter();
358
    ///
359
    /// assert_eq!(it.next(), Some(211));
360
    /// assert_eq!(it.next(), Some(281));
361
    /// assert_eq!(it.next(), Some(421));
362
    /// assert_eq!(it.next(), Some(32973));
363
    /// assert_eq!(it.next(), None);
364
    /// ```
365
    #[inline]
366
53.5M
    pub fn iter<'a>(&'a self) -> ZeroSliceIter<'a, T> {
367
53.5M
        ZeroSliceIter(self.as_ule_slice().iter())
368
53.5M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::iter
<zerovec::zerovec::slice::ZeroSlice<char>>::iter
Line
Count
Source
366
4.52k
    pub fn iter<'a>(&'a self) -> ZeroSliceIter<'a, T> {
367
4.52k
        ZeroSliceIter(self.as_ule_slice().iter())
368
4.52k
    }
<zerovec::zerovec::slice::ZeroSlice<u16>>::iter
Line
Count
Source
366
53.5M
    pub fn iter<'a>(&'a self) -> ZeroSliceIter<'a, T> {
367
53.5M
        ZeroSliceIter(self.as_ule_slice().iter())
368
53.5M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::iter
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::iter
369
370
    /// Returns a tuple with the first element and a subslice of the remaining elements.
371
    ///
372
    /// # Example
373
    ///
374
    /// ```
375
    /// use zerovec::ule::AsULE;
376
    /// use zerovec::ZeroSlice;
377
    ///
378
    /// const DATA: &ZeroSlice<u16> =
379
    ///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
380
    ///         211, 281, 421, 32973,
381
    ///     ]));
382
    /// const EXPECTED_VALUE: (u16, &ZeroSlice<u16>) = (
383
    ///     211,
384
    ///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
385
    ///         281, 421, 32973,
386
    ///     ])),
387
    /// );
388
    /// assert_eq!(EXPECTED_VALUE, DATA.split_first().unwrap());
389
    /// ```
390
    #[inline]
391
53.5M
    pub fn split_first(&self) -> Option<(T, &ZeroSlice<T>)> {
392
53.5M
        if let Some(first) = self.first() {
393
53.5M
            return Some((
394
53.5M
                first,
395
53.5M
                // `unwrap()` must succeed, because `first()` returned `Some`.
396
53.5M
                #[expect(clippy::unwrap_used)]
397
53.5M
                self.get_subslice(1..self.len()).unwrap(),
398
53.5M
            ));
399
0
        }
400
0
        None
401
53.5M
    }
<zerovec::zerovec::slice::ZeroSlice<char>>::split_first
Line
Count
Source
391
4.52k
    pub fn split_first(&self) -> Option<(T, &ZeroSlice<T>)> {
392
4.52k
        if let Some(first) = self.first() {
393
4.52k
            return Some((
394
4.52k
                first,
395
4.52k
                // `unwrap()` must succeed, because `first()` returned `Some`.
396
4.52k
                #[expect(clippy::unwrap_used)]
397
4.52k
                self.get_subslice(1..self.len()).unwrap(),
398
4.52k
            ));
399
0
        }
400
0
        None
401
4.52k
    }
<zerovec::zerovec::slice::ZeroSlice<u16>>::split_first
Line
Count
Source
391
53.5M
    pub fn split_first(&self) -> Option<(T, &ZeroSlice<T>)> {
392
53.5M
        if let Some(first) = self.first() {
393
53.5M
            return Some((
394
53.5M
                first,
395
53.5M
                // `unwrap()` must succeed, because `first()` returned `Some`.
396
53.5M
                #[expect(clippy::unwrap_used)]
397
53.5M
                self.get_subslice(1..self.len()).unwrap(),
398
53.5M
            ));
399
0
        }
400
0
        None
401
53.5M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::split_first
402
}
403
404
/// An iterator over elements in a VarZeroVec
405
#[derive(Debug)]
406
pub struct ZeroSliceIter<'a, T: AsULE>(core::slice::Iter<'a, T::ULE>);
407
408
impl<'a, T: AsULE> Iterator for ZeroSliceIter<'a, T> {
409
    type Item = T;
410
268M
    fn next(&mut self) -> Option<T> {
411
268M
        self.0.next().copied().map(T::from_unaligned)
412
268M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSliceIter<icu_properties::props::Script> as core::iter::traits::iterator::Iterator>::next
<zerovec::zerovec::slice::ZeroSliceIter<char> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
410
9.18k
    fn next(&mut self) -> Option<T> {
411
9.18k
        self.0.next().copied().map(T::from_unaligned)
412
9.18k
    }
<zerovec::zerovec::slice::ZeroSliceIter<u16> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
410
268M
    fn next(&mut self) -> Option<T> {
411
268M
        self.0.next().copied().map(T::from_unaligned)
412
268M
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSliceIter<potential_utf::uchar::PotentialCodePoint> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSliceIter<_> as core::iter::traits::iterator::Iterator>::next
413
414
14.5k
    fn size_hint(&self) -> (usize, Option<usize>) {
415
14.5k
        self.0.size_hint()
416
14.5k
    }
<zerovec::zerovec::slice::ZeroSliceIter<char> as core::iter::traits::iterator::Iterator>::size_hint
Line
Count
Source
414
2.71k
    fn size_hint(&self) -> (usize, Option<usize>) {
415
2.71k
        self.0.size_hint()
416
2.71k
    }
<zerovec::zerovec::slice::ZeroSliceIter<u16> as core::iter::traits::iterator::Iterator>::size_hint
Line
Count
Source
414
11.8k
    fn size_hint(&self) -> (usize, Option<usize>) {
415
11.8k
        self.0.size_hint()
416
11.8k
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSliceIter<_> as core::iter::traits::iterator::Iterator>::size_hint
417
}
418
419
impl<'a, T: AsULE> ExactSizeIterator for ZeroSliceIter<'a, T> {
420
0
    fn len(&self) -> usize {
421
0
        self.0.len()
422
0
    }
423
}
424
425
impl<'a, T: AsULE> DoubleEndedIterator for ZeroSliceIter<'a, T> {
426
0
    fn next_back(&mut self) -> Option<T> {
427
0
        self.0.next_back().copied().map(T::from_unaligned)
428
0
    }
429
}
430
431
impl<T> ZeroSlice<T>
432
where
433
    T: AsULE + Ord,
434
{
435
    /// Binary searches a sorted `ZeroVec<T>` for the given element. For more information, see
436
    /// the primitive function [`binary_search`].
437
    ///
438
    /// # Example
439
    ///
440
    /// ```
441
    /// use zerovec::ZeroVec;
442
    ///
443
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
444
    /// let zerovec: ZeroVec<u16> =
445
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
446
    ///
447
    /// assert_eq!(zerovec.binary_search(&281), Ok(1));
448
    /// assert_eq!(zerovec.binary_search(&282), Err(2));
449
    /// ```
450
    ///
451
    /// [`binary_search`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search
452
    #[inline]
453
0
    pub fn binary_search(&self, x: &T) -> Result<usize, usize> {
454
0
        self.as_ule_slice()
455
0
            .binary_search_by(|probe| T::from_unaligned(*probe).cmp(x))
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::binary_search::{closure#0}
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u16>>::binary_search::{closure#0}
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::binary_search::{closure#0}
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::binary_search::{closure#0}
456
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>::binary_search
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u16>>::binary_search
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint>>::binary_search
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_>>::binary_search
457
}
458
459
impl<T> ZeroSlice<T>
460
where
461
    T: AsULE,
462
{
463
    /// Binary searches a sorted `ZeroVec<T>` based on a given predicate. For more information, see
464
    /// the primitive function [`binary_search_by`].
465
    ///
466
    /// # Example
467
    ///
468
    /// ```
469
    /// use zerovec::ZeroVec;
470
    ///
471
    /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
472
    /// let zerovec: ZeroVec<u16> =
473
    ///     ZeroVec::parse_bytes(bytes).expect("infallible");
474
    ///
475
    /// assert_eq!(zerovec.binary_search_by(|x| x.cmp(&281)), Ok(1));
476
    /// assert_eq!(zerovec.binary_search_by(|x| x.cmp(&282)), Err(2));
477
    /// ```
478
    ///
479
    /// [`binary_search_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search_by
480
    #[inline]
481
0
    pub fn binary_search_by(
482
0
        &self,
483
0
        mut predicate: impl FnMut(T) -> Ordering,
484
0
    ) -> Result<usize, usize> {
485
0
        self.as_ule_slice()
486
0
            .binary_search_by(|probe| predicate(T::from_unaligned(*probe)))
487
0
    }
488
}
489
490
// Safety (based on the safety checklist on the VarULE trait):
491
// (`ZeroSlice<T>` is a transparent wrapper around [T::ULE])
492
//  1. [T::ULE] does not include any uninitialized or padding bytes (achieved by being a slice of a ULE type)
493
//  2. [T::ULE] is aligned to 1 byte (achieved by being a slice of a ULE type)
494
//  3. The impl of `validate_bytes()` returns an error if any byte is not valid.
495
//  4. The impl of `validate_bytes()` returns an error if the slice cannot be used in its entirety
496
//  5. The impl of `from_bytes_unchecked()` returns a reference to the same data.
497
//  6. `as_bytes()` and `parse_bytes()` are defaulted
498
//  7. `[T::ULE]` byte equality is semantic equality (relying on the guideline of the underlying `ULE` type)
499
unsafe impl<T: AsULE + 'static> VarULE for ZeroSlice<T> {
500
    #[inline]
501
0
    fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
502
0
        T::ULE::validate_bytes(bytes)
503
0
    }
504
505
    #[inline]
506
0
    unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
507
0
        Self::from_ule_slice(T::ULE::slice_from_bytes_unchecked(bytes))
508
0
    }
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint> as zerovec::ule::VarULE>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<_> as zerovec::ule::VarULE>::from_bytes_unchecked
509
}
510
511
impl<T> Eq for ZeroSlice<T> where T: AsULE + Eq {}
512
513
impl<T> PartialEq<ZeroSlice<T>> for ZeroSlice<T>
514
where
515
    T: AsULE + PartialEq,
516
{
517
    #[inline]
518
0
    fn eq(&self, other: &ZeroSlice<T>) -> bool {
519
0
        self.as_zerovec().eq(&other.as_zerovec())
520
0
    }
521
}
522
523
impl<T> PartialEq<[T]> for ZeroSlice<T>
524
where
525
    T: AsULE + PartialEq,
526
{
527
    #[inline]
528
0
    fn eq(&self, other: &[T]) -> bool {
529
0
        self.iter().eq(other.iter().copied())
530
0
    }
531
}
532
533
impl<'a, T> PartialEq<ZeroVec<'a, T>> for ZeroSlice<T>
534
where
535
    T: AsULE + PartialEq,
536
{
537
    #[inline]
538
0
    fn eq(&self, other: &ZeroVec<'a, T>) -> bool {
539
0
        self.as_zerovec().eq(other)
540
0
    }
541
}
542
543
impl<'a, T> PartialEq<ZeroSlice<T>> for ZeroVec<'a, T>
544
where
545
    T: AsULE + PartialEq,
546
{
547
    #[inline]
548
0
    fn eq(&self, other: &ZeroSlice<T>) -> bool {
549
0
        self.eq(&other.as_zerovec())
550
0
    }
551
}
552
553
impl<T> fmt::Debug for ZeroSlice<T>
554
where
555
    T: AsULE + fmt::Debug,
556
{
557
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558
0
        self.as_zerovec().fmt(f)
559
0
    }
560
}
561
562
impl<T: AsULE + PartialOrd> PartialOrd for ZeroSlice<T> {
563
0
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
564
0
        self.iter().partial_cmp(other.iter())
565
0
    }
566
}
567
568
impl<T: AsULE + Ord> Ord for ZeroSlice<T> {
569
0
    fn cmp(&self, other: &Self) -> Ordering {
570
0
        self.iter().cmp(other.iter())
571
0
    }
572
}
573
574
#[cfg(feature = "alloc")]
575
impl<T: AsULE> AsRef<ZeroSlice<T>> for alloc::vec::Vec<T::ULE> {
576
0
    fn as_ref(&self) -> &ZeroSlice<T> {
577
0
        ZeroSlice::<T>::from_ule_slice(self)
578
0
    }
579
}
580
581
impl<T: AsULE> AsRef<ZeroSlice<T>> for &[T::ULE] {
582
0
    fn as_ref(&self) -> &ZeroSlice<T> {
583
0
        ZeroSlice::<T>::from_ule_slice(self)
584
0
    }
585
}
586
587
impl<T> Default for &ZeroSlice<T>
588
where
589
    T: AsULE,
590
{
591
0
    fn default() -> Self {
592
0
        ZeroSlice::from_ule_slice(&[])
593
0
    }
Unexecuted instantiation: <&zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script> as core::default::Default>::default
Unexecuted instantiation: <&zerovec::zerovec::slice::ZeroSlice<_> as core::default::Default>::default
594
}
595
596
#[cfg(test)]
597
mod test {
598
    use super::*;
599
    use crate::zeroslice;
600
601
    #[test]
602
    fn test_split_first() {
603
        {
604
            // empty slice.
605
            assert_eq!(None, ZeroSlice::<u16>::new_empty().split_first());
606
        }
607
        {
608
            // single element slice
609
            const DATA: &ZeroSlice<u16> =
610
                zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211]);
611
            assert_eq!((211, zeroslice![]), DATA.split_first().unwrap());
612
        }
613
        {
614
            // slice with many elements.
615
            const DATA: &ZeroSlice<u16> =
616
                zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211, 281, 421, 32973]);
617
            const EXPECTED_VALUE: (u16, &ZeroSlice<u16>) = (
618
                211,
619
                zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [281, 421, 32973]),
620
            );
621
622
            assert_eq!(EXPECTED_VALUE, DATA.split_first().unwrap());
623
        }
624
    }
625
}