Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/zerovec-0.10.4/src/varzerovec/components.rs
Line
Count
Source (jump to first uncovered line)
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 crate::ule::*;
6
use alloc::boxed::Box;
7
use alloc::format;
8
use alloc::string::String;
9
use alloc::vec::Vec;
10
use core::cmp::Ordering;
11
use core::convert::TryFrom;
12
use core::marker::PhantomData;
13
use core::ops::Range;
14
15
// Also used by owned.rs
16
pub(super) const LENGTH_WIDTH: usize = 4;
17
pub(super) const METADATA_WIDTH: usize = 0;
18
pub(super) const MAX_LENGTH: usize = u32::MAX as usize;
19
pub(super) const MAX_INDEX: usize = u32::MAX as usize;
20
21
/// This trait allows switching between different possible internal
22
/// representations of VarZeroVec.
23
///
24
/// Currently this crate supports two formats: [`Index16`] and [`Index32`],
25
/// with [`Index16`] being the default for all [`VarZeroVec`](super::VarZeroVec)
26
/// types unless explicitly specified otherwise.
27
///
28
/// Do not implement this trait, its internals may be changed in the future,
29
/// and all of its associated items are hidden from the docs.
30
#[allow(clippy::missing_safety_doc)] // no safety section for you, don't implement this trait period
31
pub unsafe trait VarZeroVecFormat: 'static + Sized {
32
    #[doc(hidden)]
33
    const INDEX_WIDTH: usize;
34
    #[doc(hidden)]
35
    const MAX_VALUE: u32;
36
    /// This is always `RawBytesULE<Self::INDEX_WIDTH>` however
37
    /// Rust does not currently support using associated constants in const
38
    /// generics
39
    #[doc(hidden)]
40
    type RawBytes: ULE;
41
42
    // various conversions because RawBytes is an associated constant now
43
    #[doc(hidden)]
44
    fn rawbytes_to_usize(raw: Self::RawBytes) -> usize;
45
    #[doc(hidden)]
46
    fn usize_to_rawbytes(u: usize) -> Self::RawBytes;
47
48
    #[doc(hidden)]
49
    fn rawbytes_from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self::RawBytes];
50
}
51
52
/// This is a [`VarZeroVecFormat`] that stores u16s in the index array.
53
/// Will have a smaller data size, but it's more likely for larger arrays
54
/// to be unrepresentable (and error on construction)
55
///
56
/// This is the default index size used by all [`VarZeroVec`](super::VarZeroVec) types.
57
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
58
#[allow(clippy::exhaustive_structs)] // marker
59
pub struct Index16;
60
61
/// This is a [`VarZeroVecFormat`] that stores u32s in the index array.
62
/// Will have a larger data size, but will support large arrays without
63
/// problems.
64
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
65
#[allow(clippy::exhaustive_structs)] // marker
66
pub struct Index32;
67
68
unsafe impl VarZeroVecFormat for Index16 {
69
    const INDEX_WIDTH: usize = 2;
70
    const MAX_VALUE: u32 = u16::MAX as u32;
71
    type RawBytes = RawBytesULE<2>;
72
    #[inline]
73
0
    fn rawbytes_to_usize(raw: Self::RawBytes) -> usize {
74
0
        raw.as_unsigned_int() as usize
75
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::Index16 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
Unexecuted instantiation: <zerovec::varzerovec::components::Index16 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
Unexecuted instantiation: <zerovec::varzerovec::components::Index16 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
Unexecuted instantiation: <zerovec::varzerovec::components::Index16 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
76
    #[inline]
77
0
    fn usize_to_rawbytes(u: usize) -> Self::RawBytes {
78
0
        (u as u16).to_unaligned()
79
0
    }
80
    #[inline]
81
0
    fn rawbytes_from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self::RawBytes] {
82
0
        Self::RawBytes::from_byte_slice_unchecked_mut(bytes)
83
0
    }
84
}
85
86
unsafe impl VarZeroVecFormat for Index32 {
87
    const INDEX_WIDTH: usize = 4;
88
    const MAX_VALUE: u32 = u32::MAX;
89
    type RawBytes = RawBytesULE<4>;
90
    #[inline]
91
0
    fn rawbytes_to_usize(raw: Self::RawBytes) -> usize {
92
0
        raw.as_unsigned_int() as usize
93
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::Index32 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
Unexecuted instantiation: <zerovec::varzerovec::components::Index32 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
Unexecuted instantiation: <zerovec::varzerovec::components::Index32 as zerovec::varzerovec::components::VarZeroVecFormat>::rawbytes_to_usize
94
    #[inline]
95
0
    fn usize_to_rawbytes(u: usize) -> Self::RawBytes {
96
0
        (u as u32).to_unaligned()
97
0
    }
98
    #[inline]
99
0
    fn rawbytes_from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self::RawBytes] {
100
0
        Self::RawBytes::from_byte_slice_unchecked_mut(bytes)
101
0
    }
102
}
103
104
/// A more parsed version of `VarZeroSlice`. This type is where most of the VarZeroVec
105
/// internal representation code lies.
106
///
107
/// This is *basically* an `&'a [u8]` to a zero copy buffer, but split out into
108
/// the buffer components. Logically this is capable of behaving as
109
/// a `&'a [T::VarULE]`, but since `T::VarULE` is unsized that type does not actually
110
/// exist.
111
///
112
/// See [`VarZeroVecComponents::parse_byte_slice()`] for information on the internal invariants involved
113
#[derive(Debug)]
114
pub struct VarZeroVecComponents<'a, T: ?Sized, F> {
115
    /// The number of elements
116
    len: u32,
117
    /// The list of indices into the `things` slice
118
    indices: &'a [u8],
119
    /// The contiguous list of `T::VarULE`s
120
    things: &'a [u8],
121
    /// The original slice this was constructed from
122
    entire_slice: &'a [u8],
123
    marker: PhantomData<(&'a T, F)>,
124
}
125
126
// #[derive()] won't work here since we do not want it to be
127
// bound on T: Copy
128
impl<'a, T: ?Sized, F> Copy for VarZeroVecComponents<'a, T, F> {}
129
impl<'a, T: ?Sized, F> Clone for VarZeroVecComponents<'a, T, F> {
130
0
    fn clone(&self) -> Self {
131
0
        *self
132
0
    }
133
}
134
135
impl<'a, T: VarULE + ?Sized, F> Default for VarZeroVecComponents<'a, T, F> {
136
    #[inline]
137
0
    fn default() -> Self {
138
0
        Self::new()
139
0
    }
140
}
141
142
impl<'a, T: VarULE + ?Sized, F> VarZeroVecComponents<'a, T, F> {
143
    #[inline]
144
0
    pub fn new() -> Self {
145
0
        Self {
146
0
            len: 0,
147
0
            indices: &[],
148
0
            things: &[],
149
0
            entire_slice: &[],
150
0
            marker: PhantomData,
151
0
        }
152
0
    }
153
}
154
impl<'a, T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecComponents<'a, T, F> {
155
    /// Construct a new VarZeroVecComponents, checking invariants about the overall buffer size:
156
    ///
157
    /// - There must be either zero or at least four bytes (if four, this is the "length" parsed as a usize)
158
    /// - There must be at least `4*length + 4` bytes total, to form the array `indices` of indices
159
    /// - `indices[i]..indices[i+1]` must index into a valid section of
160
    ///   `things`, such that it parses to a `T::VarULE`
161
    /// - `indices[len - 1]..things.len()` must index into a valid section of
162
    ///   `things`, such that it parses to a `T::VarULE`
163
    #[inline]
164
0
    pub fn parse_byte_slice(slice: &'a [u8]) -> Result<Self, ZeroVecError> {
165
0
        // The empty VZV is special-cased to the empty slice
166
0
        if slice.is_empty() {
167
0
            return Ok(VarZeroVecComponents {
168
0
                len: 0,
169
0
                indices: &[],
170
0
                things: &[],
171
0
                entire_slice: slice,
172
0
                marker: PhantomData,
173
0
            });
174
0
        }
175
0
        let len_bytes = slice
176
0
            .get(0..LENGTH_WIDTH)
177
0
            .ok_or(ZeroVecError::VarZeroVecFormatError)?;
178
0
        let len_ule = RawBytesULE::<LENGTH_WIDTH>::parse_byte_slice(len_bytes)
179
0
            .map_err(|_| ZeroVecError::VarZeroVecFormatError)?;
180
181
0
        let len = len_ule
182
0
            .first()
183
0
            .ok_or(ZeroVecError::VarZeroVecFormatError)?
184
0
            .as_unsigned_int();
185
0
        let indices_bytes = slice
186
0
            .get(
187
0
                LENGTH_WIDTH + METADATA_WIDTH
188
0
                    ..LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * (len as usize),
189
0
            )
190
0
            .ok_or(ZeroVecError::VarZeroVecFormatError)?;
191
0
        let things = slice
192
0
            .get(F::INDEX_WIDTH * (len as usize) + LENGTH_WIDTH + METADATA_WIDTH..)
193
0
            .ok_or(ZeroVecError::VarZeroVecFormatError)?;
194
195
0
        let borrowed = VarZeroVecComponents {
196
0
            len,
197
0
            indices: indices_bytes,
198
0
            things,
199
0
            entire_slice: slice,
200
0
            marker: PhantomData,
201
0
        };
202
0
203
0
        borrowed.check_indices_and_things()?;
204
205
0
        Ok(borrowed)
206
0
    }
207
208
    /// Construct a [`VarZeroVecComponents`] from a byte slice that has previously
209
    /// successfully returned a [`VarZeroVecComponents`] when passed to
210
    /// [`VarZeroVecComponents::parse_byte_slice()`]. Will return the same
211
    /// object as one would get from calling [`VarZeroVecComponents::parse_byte_slice()`].
212
    ///
213
    /// # Safety
214
    /// The bytes must have previously successfully run through
215
    /// [`VarZeroVecComponents::parse_byte_slice()`]
216
0
    pub unsafe fn from_bytes_unchecked(slice: &'a [u8]) -> Self {
217
0
        // The empty VZV is special-cased to the empty slice
218
0
        if slice.is_empty() {
219
0
            return VarZeroVecComponents {
220
0
                len: 0,
221
0
                indices: &[],
222
0
                things: &[],
223
0
                entire_slice: slice,
224
0
                marker: PhantomData,
225
0
            };
226
0
        }
227
0
        let len_bytes = slice.get_unchecked(0..LENGTH_WIDTH);
228
0
        let len_ule = RawBytesULE::<LENGTH_WIDTH>::from_byte_slice_unchecked(len_bytes);
229
0
230
0
        let len = len_ule.get_unchecked(0).as_unsigned_int();
231
0
        let indices_bytes = slice.get_unchecked(
232
0
            LENGTH_WIDTH + METADATA_WIDTH
233
0
                ..LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * (len as usize),
234
0
        );
235
0
        let things =
236
0
            slice.get_unchecked(LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * (len as usize)..);
237
0
238
0
        VarZeroVecComponents {
239
0
            len,
240
0
            indices: indices_bytes,
241
0
            things,
242
0
            entire_slice: slice,
243
0
            marker: PhantomData,
244
0
        }
245
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::StrStrPairVarULE, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::LanguageStrStrPairVarULE, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::from_bytes_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::from_bytes_unchecked
246
247
    /// Get the number of elements in this vector
248
    #[inline]
249
0
    pub fn len(self) -> usize {
250
0
        self.len as usize
251
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::len
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::len
252
253
    /// Returns `true` if the vector contains no elements.
254
    #[inline]
255
0
    pub fn is_empty(self) -> bool {
256
0
        self.indices.is_empty()
257
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::is_empty
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::is_empty
258
259
    /// Get the idx'th element out of this slice. Returns `None` if out of bounds.
260
    #[inline]
261
0
    pub fn get(self, idx: usize) -> Option<&'a T> {
262
0
        if idx >= self.len() {
263
0
            return None;
264
0
        }
265
0
        Some(unsafe { self.get_unchecked(idx) })
266
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::get
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::get
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::get
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::get
267
268
    /// Get the idx'th element out of this slice. Does not bounds check.
269
    ///
270
    /// Safety:
271
    /// - `idx` must be in bounds (`idx < self.len()`)
272
    #[inline]
273
0
    pub(crate) unsafe fn get_unchecked(self, idx: usize) -> &'a T {
274
0
        let range = self.get_things_range(idx);
275
0
        let things_slice = self.things.get_unchecked(range);
276
0
        T::from_byte_slice_unchecked(things_slice)
277
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::get_unchecked
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::get_unchecked
278
279
    /// Get the range in `things` for the element at `idx`. Does not bounds check.
280
    ///
281
    /// Safety:
282
    /// - `idx` must be in bounds (`idx < self.len()`)
283
    #[inline]
284
0
    unsafe fn get_things_range(self, idx: usize) -> Range<usize> {
285
0
        let start = F::rawbytes_to_usize(*self.indices_slice().get_unchecked(idx));
286
0
        let end = if idx + 1 == self.len() {
287
0
            self.things.len()
288
        } else {
289
0
            F::rawbytes_to_usize(*self.indices_slice().get_unchecked(idx + 1))
290
        };
291
0
        debug_assert!(start <= end);
292
0
        start..end
293
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::get_things_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::get_things_range
294
295
    /// Get the range in `entire_slice` for the element at `idx`. Does not bounds check.
296
    ///
297
    /// Safety:
298
    /// - `idx` must be in bounds (`idx < self.len()`)
299
    #[inline]
300
0
    pub(crate) unsafe fn get_range(self, idx: usize) -> Range<usize> {
301
0
        let range = self.get_things_range(idx);
302
0
        let offset = (self.things as *const [u8] as *const u8)
303
0
            .offset_from(self.entire_slice as *const [u8] as *const u8)
304
0
            as usize;
305
0
        range.start + offset..range.end + offset
306
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::get_range
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::get_range
307
308
    /// Check the internal invariants of VarZeroVecComponents:
309
    ///
310
    /// - `indices[i]..indices[i+1]` must index into a valid section of
311
    ///   `things`, such that it parses to a `T::VarULE`
312
    /// - `indices[len - 1]..things.len()` must index into a valid section of
313
    ///   `things`, such that it parses to a `T::VarULE`
314
    /// - `indices` is monotonically increasing
315
    ///
316
    /// This method is NOT allowed to call any other methods on VarZeroVecComponents since all other methods
317
    /// assume that the slice has been passed through check_indices_and_things
318
    #[inline]
319
    #[allow(clippy::len_zero)] // more explicit to enforce safety invariants
320
0
    fn check_indices_and_things(self) -> Result<(), ZeroVecError> {
321
0
        assert_eq!(self.len(), self.indices_slice().len());
322
0
        if self.len() == 0 {
323
0
            if self.things.len() > 0 {
324
0
                return Err(ZeroVecError::VarZeroVecFormatError);
325
            } else {
326
0
                return Ok(());
327
            }
328
0
        }
329
0
        // Safety: i is in bounds (assertion above)
330
0
        let mut start = F::rawbytes_to_usize(unsafe { *self.indices_slice().get_unchecked(0) });
331
0
        if start != 0 {
332
0
            return Err(ZeroVecError::VarZeroVecFormatError);
333
0
        }
334
0
        for i in 0..self.len() {
335
0
            let end = if i == self.len() - 1 {
336
0
                self.things.len()
337
            } else {
338
                // Safety: i+1 is in bounds (assertion above)
339
0
                F::rawbytes_to_usize(unsafe { *self.indices_slice().get_unchecked(i + 1) })
340
            };
341
0
            if start > end {
342
0
                return Err(ZeroVecError::VarZeroVecFormatError);
343
0
            }
344
0
            if end > self.things.len() {
345
0
                return Err(ZeroVecError::VarZeroVecFormatError);
346
0
            }
347
0
            // Safety: start..end is a valid range in self.things
348
0
            let bytes = unsafe { self.things.get_unchecked(start..end) };
349
0
            T::parse_byte_slice(bytes)?;
350
0
            start = end;
351
        }
352
0
        Ok(())
353
0
    }
354
355
    /// Create an iterator over the Ts contained in VarZeroVecComponents
356
    #[inline]
357
0
    pub fn iter(self) -> impl Iterator<Item = &'a T> {
358
0
        self.indices_slice()
359
0
            .iter()
360
0
            .copied()
361
0
            .map(F::rawbytes_to_usize)
362
0
            .zip(
363
0
                self.indices_slice()
364
0
                    .iter()
365
0
                    .copied()
366
0
                    .map(F::rawbytes_to_usize)
367
0
                    .skip(1)
368
0
                    .chain([self.things.len()]),
369
0
            )
370
0
            .map(move |(start, end)| unsafe { self.things.get_unchecked(start..end) })
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::StrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::LanguageStrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::iter::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::iter::{closure#0}
371
0
            .map(|bytes| unsafe { T::from_byte_slice_unchecked(bytes) })
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::StrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter::{closure#1}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::LanguageStrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter::{closure#1}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::iter::{closure#1}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::iter::{closure#1}
372
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::StrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::LanguageStrStrPairVarULE, zerovec::varzerovec::components::Index16>>::iter
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::iter
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::iter
373
374
0
    pub fn to_vec(self) -> Vec<Box<T>> {
375
0
        self.iter().map(T::to_boxed).collect()
376
0
    }
377
378
    #[inline]
379
0
    fn indices_slice(&self) -> &'a [F::RawBytes] {
380
0
        unsafe { F::RawBytes::from_byte_slice_unchecked(self.indices) }
381
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::StrStrPairVarULE, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_locid_transform::provider::LanguageStrStrPairVarULE, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<[u8], zerovec::varzerovec::components::Index32>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::indices_slice
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::indices_slice
382
383
    // Dump a debuggable representation of this type
384
    #[allow(unused)] // useful for debugging
385
0
    pub(crate) fn dump(&self) -> String {
386
0
        let indices = self
387
0
            .indices_slice()
388
0
            .iter()
389
0
            .copied()
390
0
            .map(F::rawbytes_to_usize)
391
0
            .collect::<Vec<_>>();
392
0
        format!("VarZeroVecComponents {{ indices: {indices:?} }}")
393
0
    }
394
}
395
396
impl<'a, T, F> VarZeroVecComponents<'a, T, F>
397
where
398
    T: VarULE,
399
    T: ?Sized,
400
    T: Ord,
401
    F: VarZeroVecFormat,
402
{
403
    /// Binary searches a sorted `VarZeroVecComponents<T>` for the given element. For more information, see
404
    /// the primitive function [`binary_search`](slice::binary_search).
405
0
    pub fn binary_search(&self, needle: &T) -> Result<usize, usize> {
406
0
        self.binary_search_impl(|probe| probe.cmp(needle), self.indices_slice())
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::binary_search::{closure#0}
407
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::binary_search
408
409
0
    pub fn binary_search_in_range(
410
0
        &self,
411
0
        needle: &T,
412
0
        range: Range<usize>,
413
0
    ) -> Option<Result<usize, usize>> {
414
0
        let indices_slice = self.indices_slice().get(range)?;
415
0
        Some(self.binary_search_impl(|probe| probe.cmp(needle), indices_slice))
416
0
    }
417
}
418
419
impl<'a, T, F> VarZeroVecComponents<'a, T, F>
420
where
421
    T: VarULE,
422
    T: ?Sized,
423
    F: VarZeroVecFormat,
424
{
425
    /// Binary searches a sorted `VarZeroVecComponents<T>` for the given predicate. For more information, see
426
    /// the primitive function [`binary_search_by`](slice::binary_search_by).
427
0
    pub fn binary_search_by(&self, predicate: impl FnMut(&T) -> Ordering) -> Result<usize, usize> {
428
0
        self.binary_search_impl(predicate, self.indices_slice())
429
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search_by::<icu_properties::props::get_loose_u16::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_by::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#0}::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_by::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#1}::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::binary_search_by::<_>
430
431
0
    pub fn binary_search_in_range_by(
432
0
        &self,
433
0
        predicate: impl FnMut(&T) -> Ordering,
434
0
        range: Range<usize>,
435
0
    ) -> Option<Result<usize, usize>> {
436
0
        let indices_slice = self.indices_slice().get(range)?;
437
0
        Some(self.binary_search_impl(predicate, indices_slice))
438
0
    }
439
440
    /// Binary searches a sorted `VarZeroVecComponents<T>` with the given predicate. For more information, see
441
    /// the primitive function [`binary_search`](slice::binary_search).
442
0
    fn binary_search_impl(
443
0
        &self,
444
0
        mut predicate: impl FnMut(&T) -> Ordering,
445
0
        indices_slice: &[F::RawBytes],
446
0
    ) -> Result<usize, usize> {
447
0
        // This code is an absolute atrocity. This code is not a place of honor. This
448
0
        // code is known to the State of California to cause cancer.
449
0
        //
450
0
        // Unfortunately, the stdlib's `binary_search*` functions can only operate on slices.
451
0
        // We do not have a slice. We have something we can .get() and index on, but that is not
452
0
        // a slice.
453
0
        //
454
0
        // The `binary_search*` functions also do not have a variant where they give you the element's
455
0
        // index, which we could otherwise use to directly index `self`.
456
0
        // We do have `self.indices`, but these are indices into a byte buffer, which cannot in
457
0
        // isolation be used to recoup the logical index of the element they refer to.
458
0
        //
459
0
        // However, `binary_search_by()` provides references to the elements of the slice being iterated.
460
0
        // Since the layout of Rust slices is well-defined, we can do pointer arithmetic on these references
461
0
        // to obtain the index being used by the search.
462
0
        //
463
0
        // It's worth noting that the slice we choose to search is irrelevant, as long as it has the appropriate
464
0
        // length. `self.indices` is defined to have length `self.len()`, so it is convenient to use
465
0
        // here and does not require additional allocations.
466
0
        //
467
0
        // The alternative to doing this is to implement our own binary search. This is significantly less fun.
468
0
469
0
        // Note: We always use zero_index relative to the whole indices array, even if we are
470
0
        // only searching a subslice of it.
471
0
        let zero_index = self.indices.as_ptr() as *const _ as usize;
472
0
        indices_slice.binary_search_by(|probe: &_| {
473
0
            // `self.indices` is a vec of unaligned F::INDEX_WIDTH values, so we divide by F::INDEX_WIDTH
474
0
            // to get the actual index
475
0
            let index = (probe as *const _ as usize - zero_index) / F::INDEX_WIDTH;
476
0
            // safety: we know this is in bounds
477
0
            let actual_probe = unsafe { self.get_unchecked(index) };
478
0
            predicate(actual_probe)
479
0
        })
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}>::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<icu_properties::props::get_loose_u16::{closure#0}>::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#0}::{closure#0}>::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#1}::{closure#0}>::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}>::{closure#0}
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::binary_search_impl::<_>::{closure#0}
480
0
    }
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<icu_properties::provider::names::NormalizedPropertyNameStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<icu_properties::props::get_loose_u16::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#0}::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<zerovec::ule::unvalidated::UnvalidatedStr, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<icu_locid_transform::fallback::LocaleFallbackIteratorInner>::get_explicit_parent::{closure#1}::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search_impl::<<zerovec::varzerovec::components::VarZeroVecComponents<str, zerovec::varzerovec::components::Index16>>::binary_search::{closure#0}>
Unexecuted instantiation: <zerovec::varzerovec::components::VarZeroVecComponents<_, _>>::binary_search_impl::<_>
481
}
482
483
/// Collects the bytes for a VarZeroSlice into a Vec.
484
0
pub fn get_serializable_bytes_non_empty<T, A, F>(elements: &[A]) -> Option<Vec<u8>>
485
0
where
486
0
    T: VarULE + ?Sized,
487
0
    A: EncodeAsVarULE<T>,
488
0
    F: VarZeroVecFormat,
489
0
{
490
0
    debug_assert!(!elements.is_empty());
491
0
    let len = compute_serializable_len::<T, A, F>(elements)?;
492
0
    debug_assert!(len >= LENGTH_WIDTH as u32);
493
0
    let mut output: Vec<u8> = alloc::vec![0; len as usize];
494
0
    write_serializable_bytes::<T, A, F>(elements, &mut output);
495
0
    Some(output)
496
0
}
Unexecuted instantiation: zerovec::varzerovec::components::get_serializable_bytes_non_empty::<icu_locid_transform::provider::LanguageStrStrPairVarULE, icu_locid_transform::provider::LanguageStrStrPair, zerovec::varzerovec::components::Index16>
Unexecuted instantiation: zerovec::varzerovec::components::get_serializable_bytes_non_empty::<_, _, _>
497
498
/// Writes the bytes for a VarZeroSlice into an output buffer.
499
///
500
/// Every byte in the buffer will be initialized after calling this function.
501
///
502
/// # Panics
503
///
504
/// Panics if the buffer is not exactly the correct length.
505
0
pub fn write_serializable_bytes<T, A, F>(elements: &[A], output: &mut [u8])
506
0
where
507
0
    T: VarULE + ?Sized,
508
0
    A: EncodeAsVarULE<T>,
509
0
    F: VarZeroVecFormat,
510
0
{
511
0
    assert!(elements.len() <= MAX_LENGTH);
512
0
    let num_elements_bytes = elements.len().to_le_bytes();
513
0
    #[allow(clippy::indexing_slicing)] // Function contract allows panicky behavior
514
0
    output[0..LENGTH_WIDTH].copy_from_slice(&num_elements_bytes[0..LENGTH_WIDTH]);
515
0
516
0
    // idx_offset = offset from the start of the buffer for the next index
517
0
    let mut idx_offset: usize = LENGTH_WIDTH + METADATA_WIDTH;
518
0
    // first_dat_offset = offset from the start of the buffer of the first data block
519
0
    let first_dat_offset: usize = idx_offset + elements.len() * F::INDEX_WIDTH;
520
0
    // dat_offset = offset from the start of the buffer of the next data block
521
0
    let mut dat_offset: usize = first_dat_offset;
522
523
0
    for element in elements.iter() {
524
0
        let element_len = element.encode_var_ule_len();
525
0
526
0
        let idx_limit = idx_offset + F::INDEX_WIDTH;
527
0
        #[allow(clippy::indexing_slicing)] // Function contract allows panicky behavior
528
0
        let idx_slice = &mut output[idx_offset..idx_limit];
529
0
        // VZV expects data offsets to be stored relative to the first data block
530
0
        let idx = dat_offset - first_dat_offset;
531
0
        assert!(idx <= MAX_INDEX);
532
        #[allow(clippy::indexing_slicing)] // this function is explicitly panicky
533
0
        idx_slice.copy_from_slice(&idx.to_le_bytes()[..F::INDEX_WIDTH]);
534
0
535
0
        let dat_limit = dat_offset + element_len;
536
0
        #[allow(clippy::indexing_slicing)] // Function contract allows panicky behavior
537
0
        let dat_slice = &mut output[dat_offset..dat_limit];
538
0
        element.encode_var_ule_write(dat_slice);
539
0
        debug_assert_eq!(T::validate_byte_slice(dat_slice), Ok(()));
540
541
0
        idx_offset = idx_limit;
542
0
        dat_offset = dat_limit;
543
    }
544
545
0
    debug_assert_eq!(
546
        idx_offset,
547
0
        LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * elements.len()
548
    );
549
0
    assert_eq!(dat_offset, output.len());
550
0
}
Unexecuted instantiation: zerovec::varzerovec::components::write_serializable_bytes::<icu_locid_transform::provider::LanguageStrStrPairVarULE, icu_locid_transform::provider::LanguageStrStrPair, zerovec::varzerovec::components::Index16>
Unexecuted instantiation: zerovec::varzerovec::components::write_serializable_bytes::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>
551
552
0
pub fn compute_serializable_len<T, A, F>(elements: &[A]) -> Option<u32>
553
0
where
554
0
    T: VarULE + ?Sized,
555
0
    A: EncodeAsVarULE<T>,
556
0
    F: VarZeroVecFormat,
557
0
{
558
0
    let idx_len: u32 = u32::try_from(elements.len())
559
0
        .ok()?
560
0
        .checked_mul(F::INDEX_WIDTH as u32)?
561
0
        .checked_add(LENGTH_WIDTH as u32)?
562
0
        .checked_add(METADATA_WIDTH as u32)?;
563
0
    let data_len: u32 = elements
564
0
        .iter()
565
0
        .map(|v| u32::try_from(v.encode_var_ule_len()).ok())
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<icu_locid_transform::provider::LanguageStrStrPairVarULE, icu_locid_transform::provider::LanguageStrStrPair, zerovec::varzerovec::components::Index16>::{closure#0}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>::{closure#0}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>::{closure#0}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<_, _, _>::{closure#0}
566
0
        .try_fold(0u32, |s, v| s.checked_add(v?))?;
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<icu_locid_transform::provider::LanguageStrStrPairVarULE, icu_locid_transform::provider::LanguageStrStrPair, zerovec::varzerovec::components::Index16>::{closure#1}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>::{closure#1}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>::{closure#1}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<_, _, _>::{closure#1}
567
0
    let ret = idx_len.checked_add(data_len);
568
0
    if let Some(r) = ret {
569
0
        if r >= F::MAX_VALUE {
570
0
            return None;
571
0
        }
572
0
    }
573
0
    ret
574
0
}
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<icu_locid_transform::provider::LanguageStrStrPairVarULE, icu_locid_transform::provider::LanguageStrStrPair, zerovec::varzerovec::components::Index16>
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<[u8], zerovec::ule::multi::BlankSliceEncoder, zerovec::varzerovec::components::Index32>
Unexecuted instantiation: zerovec::varzerovec::components::compute_serializable_len::<_, _, _>