Coverage Report

Created: 2025-07-23 07:04

/rust/registry/src/index.crates.io-6f17d22bba15001f/zerovec-0.10.4/src/varzerovec/owned.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
// The mutation operations in this file should panic to prevent undefined behavior
6
#![allow(clippy::unwrap_used)]
7
#![allow(clippy::expect_used)]
8
#![allow(clippy::indexing_slicing)]
9
#![allow(clippy::panic)]
10
11
use super::*;
12
use crate::ule::*;
13
use alloc::boxed::Box;
14
use alloc::vec::Vec;
15
use core::any;
16
use core::convert::TryInto;
17
use core::marker::PhantomData;
18
use core::ops::Deref;
19
use core::ops::Range;
20
use core::{fmt, ptr, slice};
21
22
use super::components::LENGTH_WIDTH;
23
use super::components::MAX_INDEX;
24
use super::components::MAX_LENGTH;
25
use super::components::METADATA_WIDTH;
26
27
/// A fully-owned [`VarZeroVec`]. This type has no lifetime but has the same
28
/// internal buffer representation of [`VarZeroVec`], making it cheaply convertible to
29
/// [`VarZeroVec`] and [`VarZeroSlice`].
30
///
31
/// The `F` type parameter is a [`VarZeroVecFormat`] (see its docs for more details), which can be used to select the
32
/// precise format of the backing buffer with various size and performance tradeoffs. It defaults to [`Index16`].
33
pub struct VarZeroVecOwned<T: ?Sized, F = Index16> {
34
    marker: PhantomData<(Box<T>, F)>,
35
    // safety invariant: must parse into a valid VarZeroVecComponents
36
    entire_slice: Vec<u8>,
37
}
38
39
impl<T: ?Sized, F> Clone for VarZeroVecOwned<T, F> {
40
0
    fn clone(&self) -> Self {
41
0
        VarZeroVecOwned {
42
0
            marker: self.marker,
43
0
            entire_slice: self.entire_slice.clone(),
44
0
        }
45
0
    }
46
}
47
48
// The effect of a shift on the indices in the varzerovec.
49
#[derive(PartialEq)]
50
enum ShiftType {
51
    Insert,
52
    Replace,
53
    Remove,
54
}
55
56
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> Deref for VarZeroVecOwned<T, F> {
57
    type Target = VarZeroSlice<T, F>;
58
0
    fn deref(&self) -> &VarZeroSlice<T, F> {
59
0
        self.as_slice()
60
0
    }
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_properties::provider::names::NormalizedPropertyNameStr> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::StrStrPairVarULE> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::LanguageStrStrPairVarULE> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::ule::unvalidated::UnvalidatedStr> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<str> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<str> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<_, _> as core::ops::deref::Deref>::deref
61
}
62
63
impl<T: VarULE + ?Sized, F> VarZeroVecOwned<T, F> {
64
    /// Construct an empty VarZeroVecOwned
65
0
    pub fn new() -> Self {
66
0
        Self {
67
0
            marker: PhantomData,
68
0
            entire_slice: Vec::new(),
69
0
        }
70
0
    }
71
}
72
73
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> {
74
    /// Construct a VarZeroVecOwned from a [`VarZeroSlice`] by cloning the internal data
75
0
    pub fn from_slice(slice: &VarZeroSlice<T, F>) -> Self {
76
0
        Self {
77
0
            marker: PhantomData,
78
0
            entire_slice: slice.as_bytes().into(),
79
0
        }
80
0
    }
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::LanguageStrStrPairVarULE>>::from_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<_, _>>::from_slice
81
82
    /// Construct a VarZeroVecOwned from a list of elements
83
0
    pub fn try_from_elements<A>(elements: &[A]) -> Result<Self, &'static str>
84
0
    where
85
0
        A: EncodeAsVarULE<T>,
86
0
    {
87
0
        Ok(if elements.is_empty() {
88
0
            Self::from_slice(VarZeroSlice::new_empty())
89
        } else {
90
            Self {
91
0
                marker: PhantomData,
92
0
                // TODO(#1410): Rethink length errors in VZV.
93
0
                entire_slice: components::get_serializable_bytes_non_empty::<T, A, F>(elements)
94
0
                    .ok_or(
95
0
                        "Attempted to build VarZeroVec out of elements that \
96
0
                                     cumulatively are larger than a u32 in size",
97
0
                    )?,
98
            }
99
        })
100
0
    }
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::LanguageStrStrPairVarULE>>::try_from_elements::<icu_locid_transform::provider::LanguageStrStrPair>
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<_, _>>::try_from_elements::<_>
101
102
    /// Obtain this `VarZeroVec` as a [`VarZeroSlice`]
103
0
    pub fn as_slice(&self) -> &VarZeroSlice<T, F> {
104
0
        let slice: &[u8] = &self.entire_slice;
105
0
        unsafe {
106
0
            // safety: the slice is known to come from a valid parsed VZV
107
0
            VarZeroSlice::from_byte_slice_unchecked(slice)
108
0
        }
109
0
    }
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::zerovec::slice::ZeroSlice<icu_properties::props::Script>>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_properties::provider::names::NormalizedPropertyNameStr>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::zerovec::slice::ZeroSlice<icu_locid::subtags::region::Region>>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::StrStrPairVarULE>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<icu_locid_transform::provider::LanguageStrStrPairVarULE>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::ule::unvalidated::UnvalidatedStr>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<str>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<str>>::as_slice
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<_, _>>::as_slice
110
111
    /// Try to allocate a buffer with enough capacity for `capacity`
112
    /// elements. Since `T` can take up an arbitrary size this will
113
    /// just allocate enough space for 4-byte Ts
114
0
    pub(crate) fn with_capacity(capacity: usize) -> Self {
115
0
        Self {
116
0
            marker: PhantomData,
117
0
            entire_slice: Vec::with_capacity(capacity * (F::INDEX_WIDTH + 4)),
118
0
        }
119
0
    }
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<zerovec::ule::unvalidated::UnvalidatedStr>>::with_capacity
Unexecuted instantiation: <zerovec::varzerovec::owned::VarZeroVecOwned<_, _>>::with_capacity
120
121
    /// Try to reserve space for `capacity`
122
    /// elements. Since `T` can take up an arbitrary size this will
123
    /// just allocate enough space for 4-byte Ts
124
0
    pub(crate) fn reserve(&mut self, capacity: usize) {
125
0
        self.entire_slice.reserve(capacity * (F::INDEX_WIDTH + 4))
126
0
    }
127
128
    /// Get the position of a specific element in the data segment.
129
    ///
130
    /// If `idx == self.len()`, it will return the size of the data segment (where a new element would go).
131
    ///
132
    /// ## Safety
133
    /// `idx <= self.len()` and `self.as_encoded_bytes()` is well-formed.
134
0
    unsafe fn element_position_unchecked(&self, idx: usize) -> usize {
135
0
        let len = self.len();
136
0
        let out = if idx == len {
137
0
            self.entire_slice.len() - LENGTH_WIDTH - METADATA_WIDTH - (F::INDEX_WIDTH * len)
138
        } else {
139
0
            F::rawbytes_to_usize(*self.index_data(idx))
140
        };
141
0
        debug_assert!(
142
0
            out + LENGTH_WIDTH + METADATA_WIDTH + len * F::INDEX_WIDTH <= self.entire_slice.len()
143
        );
144
0
        out
145
0
    }
146
147
    /// Get the range of a specific element in the data segment.
148
    ///
149
    /// ## Safety
150
    /// `idx < self.len()` and `self.as_encoded_bytes()` is well-formed.
151
0
    unsafe fn element_range_unchecked(&self, idx: usize) -> core::ops::Range<usize> {
152
0
        let start = self.element_position_unchecked(idx);
153
0
        let end = self.element_position_unchecked(idx + 1);
154
0
        debug_assert!(start <= end, "{start} > {end}");
155
0
        start..end
156
0
    }
157
158
    /// Set the number of elements in the list without any checks.
159
    ///
160
    /// ## Safety
161
    /// No safe functions may be called until `self.as_encoded_bytes()` is well-formed.
162
0
    unsafe fn set_len(&mut self, len: usize) {
163
0
        assert!(len <= MAX_LENGTH);
164
0
        let len_bytes = len.to_le_bytes();
165
0
        self.entire_slice[0..LENGTH_WIDTH].copy_from_slice(&len_bytes[0..LENGTH_WIDTH]);
166
0
        // Double-check that the length fits in the length field
167
0
        assert_eq!(len_bytes[LENGTH_WIDTH..].iter().sum::<u8>(), 0);
168
0
    }
169
170
0
    fn index_range(index: usize) -> Range<usize> {
171
0
        let pos = LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * index;
172
0
        pos..pos + F::INDEX_WIDTH
173
0
    }
174
175
    /// Return the raw bytes representing the given `index`.
176
    ///
177
    /// ## Safety
178
    /// The index must be valid, and self.as_encoded_bytes() must be well-formed
179
0
    unsafe fn index_data(&self, index: usize) -> &F::RawBytes {
180
0
        &F::RawBytes::from_byte_slice_unchecked(&self.entire_slice[Self::index_range(index)])[0]
181
0
    }
182
183
    /// Return the mutable slice representing the given `index`.
184
    ///
185
    /// ## Safety
186
    /// The index must be valid. self.as_encoded_bytes() must have allocated space
187
    /// for this index, but need not have its length appropriately set.
188
0
    unsafe fn index_data_mut(&mut self, index: usize) -> &mut F::RawBytes {
189
0
        let ptr = self.entire_slice.as_mut_ptr();
190
0
        let range = Self::index_range(index);
191
0
192
0
        // Doing this instead of just `get_unchecked_mut()` because it's unclear
193
0
        // if `get_unchecked_mut()` can be called out of bounds on a slice even
194
0
        // if we know the buffer is larger.
195
0
        let data = slice::from_raw_parts_mut(ptr.add(range.start), F::INDEX_WIDTH);
196
0
197
0
        &mut F::rawbytes_from_byte_slice_unchecked_mut(data)[0]
198
0
    }
199
200
    /// Shift the indices starting with and after `starting_index` by the provided `amount`.
201
    ///
202
    /// ## Safety
203
    /// Adding `amount` to each index after `starting_index` must not result in the slice from becoming malformed.
204
    /// The length of the slice must be correctly set.
205
0
    unsafe fn shift_indices(&mut self, starting_index: usize, amount: i32) {
206
0
        let len = self.len();
207
0
        let indices = F::rawbytes_from_byte_slice_unchecked_mut(
208
0
            &mut self.entire_slice[LENGTH_WIDTH + METADATA_WIDTH
209
0
                ..LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * len],
210
0
        );
211
0
        for idx in &mut indices[starting_index..] {
212
0
            let mut new_idx = F::rawbytes_to_usize(*idx);
213
0
            if amount > 0 {
214
0
                new_idx = new_idx.checked_add(amount.try_into().unwrap()).unwrap();
215
0
            } else {
216
0
                new_idx = new_idx.checked_sub((-amount).try_into().unwrap()).unwrap();
217
0
            }
218
0
            *idx = F::usize_to_rawbytes(new_idx);
219
        }
220
0
    }
221
222
    /// Get this [`VarZeroVecOwned`] as a borrowed [`VarZeroVec`]
223
    ///
224
    /// If you wish to repeatedly call methods on this [`VarZeroVecOwned`],
225
    /// it is more efficient to perform this conversion first
226
0
    pub fn as_varzerovec<'a>(&'a self) -> VarZeroVec<'a, T, F> {
227
0
        self.as_slice().into()
228
0
    }
229
230
    /// Empty the vector
231
0
    pub fn clear(&mut self) {
232
0
        self.entire_slice.clear()
233
0
    }
234
235
    /// Consume this vector and return the backing buffer
236
    #[inline]
237
0
    pub fn into_bytes(self) -> Vec<u8> {
238
0
        self.entire_slice
239
0
    }
240
241
    /// Invalidate and resize the data at an index, optionally inserting or removing the index.
242
    /// Also updates affected indices and the length.
243
    /// Returns a slice to the new element data - it doesn't contain uninitialized data but its value is indeterminate.
244
    ///
245
    /// ## Safety
246
    /// - `index` must be a valid index, or, if `shift_type == ShiftType::Insert`, `index == self.len()` is allowed.
247
    /// - `new_size` musn't result in the data segment growing larger than `F::MAX_VALUE`.
248
0
    unsafe fn shift(&mut self, index: usize, new_size: usize, shift_type: ShiftType) -> &mut [u8] {
249
0
        // The format of the encoded data is:
250
0
        //  - four bytes of "len"
251
0
        //  - len*4 bytes for an array of indices
252
0
        //  - the actual data to which the indices point
253
0
        //
254
0
        // When inserting or removing an element, the size of the indices segment must be changed,
255
0
        // so the data before the target element must be shifted by 4 bytes in addition to the
256
0
        // shifting needed for the new element size.
257
0
        let len = self.len();
258
0
        let slice_len = self.entire_slice.len();
259
260
0
        let prev_element = match shift_type {
261
            ShiftType::Insert => {
262
0
                let pos = self.element_position_unchecked(index);
263
0
                // In the case of an insert, there's no previous element,
264
0
                // so it's an empty range at the new position.
265
0
                pos..pos
266
            }
267
0
            _ => self.element_range_unchecked(index),
268
        };
269
270
        // How much shifting must be done in bytes due to removal/insertion of an index.
271
0
        let index_shift: i64 = match shift_type {
272
0
            ShiftType::Insert => F::INDEX_WIDTH as i64,
273
0
            ShiftType::Replace => 0,
274
0
            ShiftType::Remove => -(F::INDEX_WIDTH as i64),
275
        };
276
        // The total shift in byte size of the owned slice.
277
0
        let shift: i64 =
278
0
            new_size as i64 - (prev_element.end - prev_element.start) as i64 + index_shift;
279
0
        let new_slice_len = slice_len.wrapping_add(shift as usize);
280
0
        if shift > 0 {
281
0
            if new_slice_len > F::MAX_VALUE as usize {
282
0
                panic!(
283
0
                    "Attempted to grow VarZeroVec to an encoded size that does not fit within the length size used by {}",
284
0
                    any::type_name::<F>()
285
0
                );
286
0
            }
287
0
            self.entire_slice.resize(new_slice_len, 0);
288
0
        }
289
290
        // Now that we've ensured there's enough space, we can shift the data around.
291
        {
292
            // Note: There are no references introduced between pointer creation and pointer use, and all
293
            //       raw pointers are derived from a single &mut. This preserves pointer provenance.
294
0
            let slice_range = self.entire_slice.as_mut_ptr_range();
295
0
            let old_slice_end = slice_range.start.add(slice_len);
296
0
            let data_start = slice_range
297
0
                .start
298
0
                .add(LENGTH_WIDTH + METADATA_WIDTH + len * F::INDEX_WIDTH);
299
0
            let prev_element_p =
300
0
                data_start.add(prev_element.start)..data_start.add(prev_element.end);
301
0
302
0
            // The memory range of the affected index.
303
0
            // When inserting: where the new index goes.
304
0
            // When removing:  where the index being removed is.
305
0
            // When replacing: unused.
306
0
            let index_range = {
307
0
                let index_start = slice_range
308
0
                    .start
309
0
                    .add(LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH * index);
310
0
                index_start..index_start.add(F::INDEX_WIDTH)
311
            };
312
313
0
            unsafe fn shift_bytes(block: Range<*const u8>, to: *mut u8) {
314
0
                debug_assert!(block.end >= block.start);
315
0
                ptr::copy(block.start, to, block.end.offset_from(block.start) as usize);
316
0
            }
317
318
0
            if shift_type == ShiftType::Remove {
319
0
                // Move the data before the element back by 4 to remove the index.
320
0
                shift_bytes(index_range.end..prev_element_p.start, index_range.start);
321
0
            }
322
323
            // Shift data after the element to its new position.
324
0
            shift_bytes(
325
0
                prev_element_p.end..old_slice_end,
326
0
                prev_element_p
327
0
                    .start
328
0
                    .offset((new_size as i64 + index_shift) as isize),
329
0
            );
330
331
0
            let first_affected_index = match shift_type {
332
                ShiftType::Insert => {
333
                    // Move data before the element forward by 4 to make space for a new index.
334
0
                    shift_bytes(index_range.start..prev_element_p.start, index_range.end);
335
0
336
0
                    *self.index_data_mut(index) = F::usize_to_rawbytes(prev_element.start);
337
0
                    self.set_len(len + 1);
338
0
                    index + 1
339
                }
340
                ShiftType::Remove => {
341
0
                    self.set_len(len - 1);
342
0
                    index
343
                }
344
0
                ShiftType::Replace => index + 1,
345
            };
346
            // No raw pointer use should occur after this point (because of self.index_data and self.set_len).
347
348
            // Set the new slice length. This must be done after shifting data around to avoid uninitialized data.
349
0
            self.entire_slice.set_len(new_slice_len);
350
0
351
0
            // Shift the affected indices.
352
0
            self.shift_indices(first_affected_index, (shift - index_shift) as i32);
353
0
        };
354
0
355
0
        debug_assert!(self.verify_integrity());
356
357
        // Return a mut slice to the new element data.
358
0
        let element_pos = LENGTH_WIDTH
359
0
            + METADATA_WIDTH
360
0
            + self.len() * F::INDEX_WIDTH
361
0
            + self.element_position_unchecked(index);
362
0
        &mut self.entire_slice[element_pos..element_pos + new_size]
363
0
    }
364
365
    /// Checks the internal invariants of the vec to ensure safe code will not cause UB.
366
    /// Returns whether integrity was verified.
367
    ///
368
    /// Note: an index is valid if it doesn't point to data past the end of the slice and is
369
    /// less than or equal to all future indices. The length of the index segment is not part of each index.
370
0
    fn verify_integrity(&self) -> bool {
371
0
        if self.is_empty() && !self.entire_slice.is_empty() {
372
0
            return false;
373
0
        }
374
0
        let slice_len = self.entire_slice.len();
375
0
        match slice_len {
376
0
            0 => return true,
377
0
            1..=3 => return false,
378
0
            _ => (),
379
0
        }
380
0
        let len = unsafe {
381
0
            RawBytesULE::<LENGTH_WIDTH>::from_byte_slice_unchecked(
382
0
                &self.entire_slice[..LENGTH_WIDTH],
383
0
            )[0]
384
0
            .as_unsigned_int()
385
0
        };
386
0
        if len == 0 {
387
            // An empty vec must have an empty slice: there is only a single valid byte representation.
388
0
            return false;
389
0
        }
390
0
        if slice_len < LENGTH_WIDTH + METADATA_WIDTH + len as usize * F::INDEX_WIDTH {
391
            // Not enough room for the indices.
392
0
            return false;
393
0
        }
394
0
        let data_len =
395
0
            self.entire_slice.len() - LENGTH_WIDTH - METADATA_WIDTH - len as usize * F::INDEX_WIDTH;
396
0
        if data_len > MAX_INDEX {
397
            // The data segment is too long.
398
0
            return false;
399
0
        }
400
0
401
0
        // Test index validity.
402
0
        let indices = unsafe {
403
0
            F::RawBytes::from_byte_slice_unchecked(
404
0
                &self.entire_slice[LENGTH_WIDTH + METADATA_WIDTH
405
0
                    ..LENGTH_WIDTH + METADATA_WIDTH + len as usize * F::INDEX_WIDTH],
406
0
            )
407
        };
408
0
        for idx in indices {
409
0
            if F::rawbytes_to_usize(*idx) > data_len {
410
                // Indices must not point past the data segment.
411
0
                return false;
412
0
            }
413
        }
414
0
        for window in indices.windows(2) {
415
0
            if F::rawbytes_to_usize(window[0]) > F::rawbytes_to_usize(window[1]) {
416
                // Indices must be in non-decreasing order.
417
0
                return false;
418
0
            }
419
        }
420
0
        true
421
0
    }
422
423
    /// Insert an element at the end of this vector
424
0
    pub fn push<A: EncodeAsVarULE<T> + ?Sized>(&mut self, element: &A) {
425
0
        self.insert(self.len(), element)
426
0
    }
427
428
    /// Insert an element at index `idx`
429
0
    pub fn insert<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A) {
430
0
        let len = self.len();
431
0
        if index > len {
432
0
            panic!("Called out-of-bounds insert() on VarZeroVec, index {index} len {len}");
433
0
        }
434
0
435
0
        let value_len = element.encode_var_ule_len();
436
0
437
0
        if len == 0 {
438
0
            let header_len = LENGTH_WIDTH + METADATA_WIDTH + F::INDEX_WIDTH;
439
0
            let cap = header_len + value_len;
440
0
            self.entire_slice.resize(cap, 0);
441
0
            self.entire_slice[0] = 1; // set length
442
0
            element.encode_var_ule_write(&mut self.entire_slice[header_len..]);
443
0
            return;
444
0
        }
445
0
446
0
        assert!(value_len < MAX_INDEX);
447
0
        unsafe {
448
0
            let place = self.shift(index, value_len, ShiftType::Insert);
449
0
            element.encode_var_ule_write(place);
450
0
        }
451
0
    }
452
453
    /// Remove the element at index `idx`
454
0
    pub fn remove(&mut self, index: usize) {
455
0
        let len = self.len();
456
0
        if index >= len {
457
0
            panic!("Called out-of-bounds remove() on VarZeroVec, index {index} len {len}");
458
0
        }
459
0
        if len == 1 {
460
            // This is removing the last element. Set the slice to empty to ensure all empty vecs have empty data slices.
461
0
            self.entire_slice.clear();
462
0
            return;
463
0
        }
464
0
        unsafe {
465
0
            self.shift(index, 0, ShiftType::Remove);
466
0
        }
467
0
    }
468
469
    /// Replace the element at index `idx` with another
470
0
    pub fn replace<A: EncodeAsVarULE<T> + ?Sized>(&mut self, index: usize, element: &A) {
471
0
        let len = self.len();
472
0
        if index >= len {
473
0
            panic!("Called out-of-bounds replace() on VarZeroVec, index {index} len {len}");
474
0
        }
475
0
476
0
        let value_len = element.encode_var_ule_len();
477
0
478
0
        assert!(value_len < MAX_INDEX);
479
0
        unsafe {
480
0
            let place = self.shift(index, value_len, ShiftType::Replace);
481
0
            element.encode_var_ule_write(place);
482
0
        }
483
0
    }
484
}
485
486
impl<T: VarULE + ?Sized, F: VarZeroVecFormat> fmt::Debug for VarZeroVecOwned<T, F>
487
where
488
    T: fmt::Debug,
489
{
490
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
491
0
        VarZeroSlice::fmt(self, f)
492
0
    }
493
}
494
495
impl<T: VarULE + ?Sized, F> Default for VarZeroVecOwned<T, F> {
496
0
    fn default() -> Self {
497
0
        Self::new()
498
0
    }
499
}
500
501
impl<T, A, F> PartialEq<&'_ [A]> for VarZeroVecOwned<T, F>
502
where
503
    T: VarULE + ?Sized,
504
    T: PartialEq,
505
    A: AsRef<T>,
506
    F: VarZeroVecFormat,
507
{
508
    #[inline]
509
0
    fn eq(&self, other: &&[A]) -> bool {
510
0
        self.iter().eq(other.iter().map(|t| t.as_ref()))
511
0
    }
512
}
513
514
impl<'a, T: ?Sized + VarULE, F: VarZeroVecFormat> From<&'a VarZeroSlice<T, F>>
515
    for VarZeroVecOwned<T, F>
516
{
517
0
    fn from(other: &'a VarZeroSlice<T, F>) -> Self {
518
0
        Self::from_slice(other)
519
0
    }
520
}
521
522
#[cfg(test)]
523
mod test {
524
    use super::VarZeroVecOwned;
525
    #[test]
526
    fn test_insert_integrity() {
527
        let mut items: Vec<String> = Vec::new();
528
        let mut zerovec = VarZeroVecOwned::<str>::new();
529
530
        // Insert into an empty vec.
531
        items.insert(0, "1234567890".into());
532
        zerovec.insert(0, "1234567890");
533
        assert_eq!(zerovec, &*items);
534
535
        zerovec.insert(1, "foo3");
536
        items.insert(1, "foo3".into());
537
        assert_eq!(zerovec, &*items);
538
539
        // Insert at the end.
540
        items.insert(items.len(), "qwertyuiop".into());
541
        zerovec.insert(zerovec.len(), "qwertyuiop");
542
        assert_eq!(zerovec, &*items);
543
544
        items.insert(0, "asdfghjkl;".into());
545
        zerovec.insert(0, "asdfghjkl;");
546
        assert_eq!(zerovec, &*items);
547
548
        items.insert(2, "".into());
549
        zerovec.insert(2, "");
550
        assert_eq!(zerovec, &*items);
551
    }
552
553
    #[test]
554
    // ensure that inserting empty items works
555
    fn test_empty_inserts() {
556
        let mut items: Vec<String> = Vec::new();
557
        let mut zerovec = VarZeroVecOwned::<str>::new();
558
559
        // Insert into an empty vec.
560
        items.insert(0, "".into());
561
        zerovec.insert(0, "");
562
        assert_eq!(zerovec, &*items);
563
564
        items.insert(0, "".into());
565
        zerovec.insert(0, "");
566
        assert_eq!(zerovec, &*items);
567
568
        items.insert(0, "1234567890".into());
569
        zerovec.insert(0, "1234567890");
570
        assert_eq!(zerovec, &*items);
571
572
        items.insert(0, "".into());
573
        zerovec.insert(0, "");
574
        assert_eq!(zerovec, &*items);
575
    }
576
577
    #[test]
578
    fn test_small_insert_integrity() {
579
        // Tests that insert() works even when there
580
        // is not enough space for the new index in entire_slice.len()
581
        let mut items: Vec<String> = Vec::new();
582
        let mut zerovec = VarZeroVecOwned::<str>::new();
583
584
        // Insert into an empty vec.
585
        items.insert(0, "abc".into());
586
        zerovec.insert(0, "abc");
587
        assert_eq!(zerovec, &*items);
588
589
        zerovec.insert(1, "def");
590
        items.insert(1, "def".into());
591
        assert_eq!(zerovec, &*items);
592
    }
593
594
    #[test]
595
    #[should_panic]
596
    fn test_insert_past_end() {
597
        VarZeroVecOwned::<str>::new().insert(1, "");
598
    }
599
600
    #[test]
601
    fn test_remove_integrity() {
602
        let mut items: Vec<&str> = vec!["apples", "bananas", "eeples", "", "baneenees", "five", ""];
603
        let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&items).unwrap();
604
605
        for index in [0, 2, 4, 0, 1, 1, 0] {
606
            items.remove(index);
607
            zerovec.remove(index);
608
            assert_eq!(zerovec, &*items, "index {}, len {}", index, items.len());
609
        }
610
    }
611
612
    #[test]
613
    fn test_removing_last_element_clears() {
614
        let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&["buy some apples"]).unwrap();
615
        assert!(!zerovec.as_bytes().is_empty());
616
        zerovec.remove(0);
617
        assert!(zerovec.as_bytes().is_empty());
618
    }
619
620
    #[test]
621
    #[should_panic]
622
    fn test_remove_past_end() {
623
        VarZeroVecOwned::<str>::new().remove(0);
624
    }
625
626
    #[test]
627
    fn test_replace_integrity() {
628
        let mut items: Vec<&str> = vec!["apples", "bananas", "eeples", "", "baneenees", "five", ""];
629
        let mut zerovec = VarZeroVecOwned::<str>::try_from_elements(&items).unwrap();
630
631
        // Replace with an element of the same size (and the first element)
632
        items[0] = "blablah";
633
        zerovec.replace(0, "blablah");
634
        assert_eq!(zerovec, &*items);
635
636
        // Replace with a smaller element
637
        items[1] = "twily";
638
        zerovec.replace(1, "twily");
639
        assert_eq!(zerovec, &*items);
640
641
        // Replace an empty element
642
        items[3] = "aoeuidhtns";
643
        zerovec.replace(3, "aoeuidhtns");
644
        assert_eq!(zerovec, &*items);
645
646
        // Replace the last element
647
        items[6] = "0123456789";
648
        zerovec.replace(6, "0123456789");
649
        assert_eq!(zerovec, &*items);
650
651
        // Replace with an empty element
652
        items[2] = "";
653
        zerovec.replace(2, "");
654
        assert_eq!(zerovec, &*items);
655
    }
656
657
    #[test]
658
    #[should_panic]
659
    fn test_replace_past_end() {
660
        VarZeroVecOwned::<str>::new().replace(0, "");
661
    }
662
}