Skip to main content

zerovec/varzerovec/
owned.rs

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