Coverage Report

Created: 2026-05-16 06:09

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