Coverage Report

Created: 2025-09-27 06:48

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