Coverage Report

Created: 2025-07-12 07:16

/rust/registry/src/index.crates.io-6f17d22bba15001f/zerovec-0.10.4/src/flexzerovec/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
use alloc::vec;
6
use alloc::vec::Vec;
7
use core::fmt;
8
use core::iter::FromIterator;
9
use core::ops::Deref;
10
11
use super::FlexZeroSlice;
12
use super::FlexZeroVec;
13
14
/// The fully-owned variant of [`FlexZeroVec`]. Contains all mutation methods.
15
// Safety invariant: the inner bytes must deref to a valid `FlexZeroSlice`
16
#[derive(Clone, PartialEq, Eq)]
17
pub struct FlexZeroVecOwned(Vec<u8>);
18
19
impl FlexZeroVecOwned {
20
    /// Creates a new [`FlexZeroVecOwned`] with zero elements.
21
0
    pub fn new_empty() -> Self {
22
0
        Self(vec![1])
23
0
    }
24
25
    /// Creates a [`FlexZeroVecOwned`] from a [`FlexZeroSlice`].
26
0
    pub fn from_slice(other: &FlexZeroSlice) -> FlexZeroVecOwned {
27
0
        // safety: the bytes originate from a valid FlexZeroSlice
28
0
        Self(other.as_bytes().to_vec())
29
0
    }
30
31
    /// Obtains this [`FlexZeroVecOwned`] as a [`FlexZeroSlice`].
32
0
    pub fn as_slice(&self) -> &FlexZeroSlice {
33
0
        let slice: &[u8] = &self.0;
34
0
        unsafe {
35
0
            // safety: the slice is known to come from a valid parsed FlexZeroSlice
36
0
            FlexZeroSlice::from_byte_slice_unchecked(slice)
37
0
        }
38
0
    }
39
40
    /// Mutably obtains this `FlexZeroVecOwned` as a [`FlexZeroSlice`].
41
0
    pub(crate) fn as_mut_slice(&mut self) -> &mut FlexZeroSlice {
42
0
        let slice: &mut [u8] = &mut self.0;
43
0
        unsafe {
44
0
            // safety: the slice is known to come from a valid parsed FlexZeroSlice
45
0
            FlexZeroSlice::from_byte_slice_mut_unchecked(slice)
46
0
        }
47
0
    }
48
49
    /// Converts this `FlexZeroVecOwned` into a [`FlexZeroVec::Owned`].
50
    #[inline]
51
0
    pub fn into_flexzerovec(self) -> FlexZeroVec<'static> {
52
0
        FlexZeroVec::Owned(self)
53
0
    }
54
55
    /// Clears all values out of this `FlexZeroVecOwned`.
56
    #[inline]
57
0
    pub fn clear(&mut self) {
58
0
        *self = Self::new_empty()
59
0
    }
60
61
    /// Appends an item to the end of the vector.
62
    ///
63
    /// # Panics
64
    ///
65
    /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
66
    ///
67
    /// # Examples
68
    ///
69
    /// ```
70
    /// use zerovec::vecs::FlexZeroVec;
71
    ///
72
    /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
73
    /// zv.to_mut().push(33);
74
    /// assert_eq!(zv.to_vec(), vec![22, 44, 66, 33]);
75
    /// ```
76
0
    pub fn push(&mut self, item: usize) {
77
0
        let insert_info = self.get_insert_info(item);
78
0
        self.0.resize(insert_info.new_bytes_len, 0);
79
0
        let insert_index = insert_info.new_count - 1;
80
0
        self.as_mut_slice().insert_impl(insert_info, insert_index);
81
0
    }
82
83
    /// Inserts an element into the middle of the vector.
84
    ///
85
    /// Caution: Both arguments to this function are of type `usize`. Please be careful to pass
86
    /// the index first followed by the value second.
87
    ///
88
    /// # Panics
89
    ///
90
    /// Panics if `index > len`.
91
    ///
92
    /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
93
    ///
94
    /// # Examples
95
    ///
96
    /// ```
97
    /// use zerovec::vecs::FlexZeroVec;
98
    ///
99
    /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
100
    /// zv.to_mut().insert(2, 33);
101
    /// assert_eq!(zv.to_vec(), vec![22, 44, 33, 66]);
102
    /// ```
103
0
    pub fn insert(&mut self, index: usize, item: usize) {
104
0
        #[allow(clippy::panic)] // panic is documented in function contract
105
0
        if index > self.len() {
106
0
            panic!("index {} out of range {}", index, self.len());
107
0
        }
108
0
        let insert_info = self.get_insert_info(item);
109
0
        self.0.resize(insert_info.new_bytes_len, 0);
110
0
        self.as_mut_slice().insert_impl(insert_info, index);
111
0
    }
112
113
    /// Inserts an element into an ascending sorted vector
114
    /// at a position that keeps the vector sorted.
115
    ///
116
    /// # Panics
117
    ///
118
    /// Panics if inserting the element would require allocating more than `usize::MAX` bytes.
119
    ///
120
    /// # Examples
121
    ///
122
    /// ```
123
    /// use zerovec::vecs::FlexZeroVecOwned;
124
    ///
125
    /// let mut fzv = FlexZeroVecOwned::new_empty();
126
    /// fzv.insert_sorted(10);
127
    /// fzv.insert_sorted(5);
128
    /// fzv.insert_sorted(8);
129
    ///
130
    /// assert!(Iterator::eq(fzv.iter(), [5, 8, 10].iter().copied()));
131
    /// ```
132
0
    pub fn insert_sorted(&mut self, item: usize) {
133
0
        let index = match self.binary_search(item) {
134
0
            Ok(i) => i,
135
0
            Err(i) => i,
136
        };
137
0
        let insert_info = self.get_insert_info(item);
138
0
        self.0.resize(insert_info.new_bytes_len, 0);
139
0
        self.as_mut_slice().insert_impl(insert_info, index);
140
0
    }
141
142
    /// Removes and returns the element at the specified index.
143
    ///
144
    /// # Panics
145
    ///
146
    /// Panics if `index >= len`.
147
    ///
148
    /// # Examples
149
    ///
150
    /// ```
151
    /// use zerovec::vecs::FlexZeroVec;
152
    ///
153
    /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
154
    /// let removed_item = zv.to_mut().remove(1);
155
    /// assert_eq!(44, removed_item);
156
    /// assert_eq!(zv.to_vec(), vec![22, 66]);
157
    /// ```
158
0
    pub fn remove(&mut self, index: usize) -> usize {
159
0
        #[allow(clippy::panic)] // panic is documented in function contract
160
0
        if index >= self.len() {
161
0
            panic!("index {} out of range {}", index, self.len());
162
0
        }
163
0
        let remove_info = self.get_remove_info(index);
164
0
        // Safety: `remove_index` is a valid index
165
0
        let item = unsafe { self.get_unchecked(remove_info.remove_index) };
166
0
        let new_bytes_len = remove_info.new_bytes_len;
167
0
        self.as_mut_slice().remove_impl(remove_info);
168
0
        self.0.truncate(new_bytes_len);
169
0
        item
170
0
    }
171
172
    /// Removes and returns the last element from an ascending sorted vector.
173
    ///
174
    /// If the vector is not sorted, use [`FlexZeroVecOwned::remove()`] instead. Calling this
175
    /// function would leave the FlexZeroVec in a safe, well-defined state; however, information
176
    /// may be lost and/or the equality invariant might not hold.
177
    ///
178
    /// # Panics
179
    ///
180
    /// Panics if `self.is_empty()`.
181
    ///
182
    /// # Examples
183
    ///
184
    /// ```
185
    /// use zerovec::vecs::FlexZeroVec;
186
    ///
187
    /// let mut zv: FlexZeroVec = [22, 44, 66].iter().copied().collect();
188
    /// let popped_item = zv.to_mut().pop_sorted();
189
    /// assert_eq!(66, popped_item);
190
    /// assert_eq!(zv.to_vec(), vec![22, 44]);
191
    /// ```
192
    ///
193
    /// Calling this function on a non-ascending vector could cause surprising results:
194
    ///
195
    /// ```
196
    /// use zerovec::vecs::FlexZeroVec;
197
    ///
198
    /// let mut zv1: FlexZeroVec = [444, 222, 111].iter().copied().collect();
199
    /// let popped_item = zv1.to_mut().pop_sorted();
200
    /// assert_eq!(111, popped_item);
201
    ///
202
    /// // Oops!
203
    /// assert_eq!(zv1.to_vec(), vec![188, 222]);
204
    /// ```
205
0
    pub fn pop_sorted(&mut self) -> usize {
206
0
        #[allow(clippy::panic)] // panic is documented in function contract
207
0
        if self.is_empty() {
208
0
            panic!("cannot pop from an empty vector");
209
0
        }
210
0
        let remove_info = self.get_sorted_pop_info();
211
0
        // Safety: `remove_index` is a valid index
212
0
        let item = unsafe { self.get_unchecked(remove_info.remove_index) };
213
0
        let new_bytes_len = remove_info.new_bytes_len;
214
0
        self.as_mut_slice().remove_impl(remove_info);
215
0
        self.0.truncate(new_bytes_len);
216
0
        item
217
0
    }
218
}
219
220
impl Deref for FlexZeroVecOwned {
221
    type Target = FlexZeroSlice;
222
0
    fn deref(&self) -> &Self::Target {
223
0
        self.as_slice()
224
0
    }
225
}
226
227
impl fmt::Debug for FlexZeroVecOwned {
228
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229
0
        write!(f, "{:?}", self.to_vec())
230
0
    }
231
}
232
233
impl From<&FlexZeroSlice> for FlexZeroVecOwned {
234
0
    fn from(other: &FlexZeroSlice) -> Self {
235
0
        Self::from_slice(other)
236
0
    }
237
}
238
239
impl FromIterator<usize> for FlexZeroVecOwned {
240
    /// Creates a [`FlexZeroVecOwned`] from an iterator of `usize`.
241
0
    fn from_iter<I>(iter: I) -> Self
242
0
    where
243
0
        I: IntoIterator<Item = usize>,
244
0
    {
245
0
        let mut result = FlexZeroVecOwned::new_empty();
246
0
        for item in iter {
247
0
            result.push(item);
248
0
        }
249
0
        result
250
0
    }
251
}
252
253
#[cfg(test)]
254
mod test {
255
    use super::*;
256
257
    fn check_contents(fzv: &FlexZeroSlice, expected: &[usize]) {
258
        assert_eq!(fzv.len(), expected.len(), "len: {fzv:?} != {expected:?}");
259
        assert_eq!(
260
            fzv.is_empty(),
261
            expected.is_empty(),
262
            "is_empty: {fzv:?} != {expected:?}"
263
        );
264
        assert_eq!(
265
            fzv.first(),
266
            expected.first().copied(),
267
            "first: {fzv:?} != {expected:?}"
268
        );
269
        assert_eq!(
270
            fzv.last(),
271
            expected.last().copied(),
272
            "last:  {fzv:?} != {expected:?}"
273
        );
274
        for i in 0..(expected.len() + 1) {
275
            assert_eq!(
276
                fzv.get(i),
277
                expected.get(i).copied(),
278
                "@{i}: {fzv:?} != {expected:?}"
279
            );
280
        }
281
    }
282
283
    #[test]
284
    fn test_basic() {
285
        let mut fzv = FlexZeroVecOwned::new_empty();
286
        assert_eq!(fzv.get_width(), 1);
287
        check_contents(&fzv, &[]);
288
289
        fzv.push(42);
290
        assert_eq!(fzv.get_width(), 1);
291
        check_contents(&fzv, &[42]);
292
293
        fzv.push(77);
294
        assert_eq!(fzv.get_width(), 1);
295
        check_contents(&fzv, &[42, 77]);
296
297
        // Scale up
298
        fzv.push(300);
299
        assert_eq!(fzv.get_width(), 2);
300
        check_contents(&fzv, &[42, 77, 300]);
301
302
        // Does not need to be sorted
303
        fzv.insert(1, 325);
304
        assert_eq!(fzv.get_width(), 2);
305
        check_contents(&fzv, &[42, 325, 77, 300]);
306
307
        fzv.remove(3);
308
        assert_eq!(fzv.get_width(), 2);
309
        check_contents(&fzv, &[42, 325, 77]);
310
311
        // Scale down
312
        fzv.remove(1);
313
        assert_eq!(fzv.get_width(), 1);
314
        check_contents(&fzv, &[42, 77]);
315
    }
316
317
    #[test]
318
    fn test_build_sorted() {
319
        let nums: &[usize] = &[0, 50, 0, 77, 831, 29, 89182, 931, 0, 77, 712381];
320
        let mut fzv = FlexZeroVecOwned::new_empty();
321
322
        for num in nums {
323
            fzv.insert_sorted(*num);
324
        }
325
        assert_eq!(fzv.get_width(), 3);
326
        check_contents(&fzv, &[0, 0, 0, 29, 50, 77, 77, 831, 931, 89182, 712381]);
327
328
        for num in nums {
329
            let index = fzv.binary_search(*num).unwrap();
330
            fzv.remove(index);
331
        }
332
        assert_eq!(fzv.get_width(), 1);
333
        check_contents(&fzv, &[]);
334
    }
335
}