Skip to main content

sharky_arrayvec/
nightly.rs

1use core::marker::Destruct;
2use core::mem::MaybeUninit;
3use core::ops;
4
5use super::ArrayVec;
6
7pub(crate) const fn write_filled_const<T: [const] Clone + [const] Destruct>(
8    slice: &mut [MaybeUninit<T>],
9    value: T,
10) {
11    if slice.is_empty() {
12        return;
13    }
14
15    // NOTE: `.wrapping_sub` can be used here because slice.len() is greater than
16    // zero as checked above.
17    konst::iter::for_each! { elem in konst::slice::get_up_to_mut(slice, slice.len().wrapping_sub(1)).unwrap() =>
18        elem.write(value.clone());
19    }
20    slice[slice.len().wrapping_sub(1)].write(value);
21}
22
23impl<const C: usize, T> const ops::Deref for ArrayVec<C, T> {
24    type Target = [T];
25
26    #[inline]
27    fn deref(&self) -> &Self::Target {
28        self.as_slice()
29    }
30}
31
32impl<const C: usize, T> const ops::DerefMut for ArrayVec<C, T> {
33    #[inline]
34    fn deref_mut(&mut self) -> &mut Self::Target {
35        self.as_slice_mut()
36    }
37}
38
39impl<const C: usize, T> const ops::Index<usize> for ArrayVec<C, T> {
40    type Output = T;
41
42    #[inline]
43    fn index(&self, index: usize) -> &Self::Output {
44        &self.as_slice()[index]
45    }
46}
47
48impl<const C: usize, T> const ops::IndexMut<usize> for ArrayVec<C, T> {
49    #[inline]
50    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
51        &mut self.as_slice_mut()[index]
52    }
53}
54impl<const C: usize, T> const Default for ArrayVec<C, T> {
55    #[inline]
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl<const C: usize, T: PartialEq> PartialEq for ArrayVec<C, T> {
62    #[inline]
63    default fn eq(&self, other: &ArrayVec<C, T>) -> bool {
64        self.len() == other.len() && self.as_slice().eq(other.as_slice())
65    }
66}
67
68impl<const C: usize, T: [const] PartialEq> const PartialEq for ArrayVec<C, T> {
69    #[inline]
70    fn eq(&self, other: &ArrayVec<C, T>) -> bool {
71        self.len() == other.len() && self.as_slice().eq(other.as_slice())
72    }
73}
74
75impl<const C: usize, T: [const] Eq> const Eq for ArrayVec<C, T> {}
76
77impl<const C: usize, T: PartialOrd> PartialOrd for ArrayVec<C, T> {
78    #[inline]
79    default fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
80        self.as_slice().partial_cmp(other.as_slice())
81    }
82}
83
84impl<const C: usize, T: [const] PartialOrd> const PartialOrd for ArrayVec<C, T> {
85    #[inline]
86    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
87        self.as_slice().partial_cmp(other.as_slice())
88    }
89}
90
91impl<const C: usize, T: Ord> Ord for ArrayVec<C, T> {
92    #[inline]
93    default fn cmp(&self, other: &Self) -> core::cmp::Ordering {
94        self.as_slice().cmp(other.as_slice())
95    }
96}
97
98impl<const C: usize, T: [const] Ord> const Ord for ArrayVec<C, T> {
99    #[inline]
100    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
101        self.as_slice().cmp(other.as_slice())
102    }
103}
104
105impl<const C: usize, T> ArrayVec<C, T> {
106    /// See [`ArrayVec::from_slice`].
107    #[inline]
108    pub const fn from_slice_const(slice: &[T]) -> Option<Self>
109    where
110        T: const Clone, {
111        if slice.len() > C {
112            return None;
113        }
114
115        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<T, C>::V;
116
117        konst::iter::for_each! {idx in 0..slice.len() =>
118            let item = slice[idx].clone();
119            array[idx] = MaybeUninit::new(item);
120        }
121
122        Some(Self {
123            array,
124            len: slice.len(),
125        })
126    }
127
128    /// See [`ArrayVec::truncate`].
129    #[inline]
130    pub const fn truncate_const(&mut self, len: usize)
131    where
132        T: [const] Destruct, {
133        if len >= self.len {
134            return;
135        }
136
137        // SAFETY: These elements can be dropped because everything from `0..self.len`
138        // is initialized. The dropped elements will not be accessed again because
139        // `self.len` is set to `len`
140        unsafe { self.array[len..self.len].assume_init_drop() };
141        self.len = len;
142    }
143
144    /// See [`ArrayVec::resize`].
145    ///
146    /// # Panics
147    ///
148    /// This function panics when:
149    ///
150    /// 1. `new_len > C`
151    #[inline]
152    pub const fn resize_const(&mut self, new_len: usize, value: T)
153    where
154        T: [const] Clone + [const] Destruct, {
155        assert!(new_len <= C, "Tried to resize beyond capacity.");
156
157        if new_len < self.len {
158            self.truncate_const(new_len);
159        } else if new_len > self.len {
160            write_filled_const(&mut self.array[self.len..new_len], value);
161            self.len = new_len;
162        }
163    }
164}
165
166#[cfg(test)]
167#[cfg_attr(coverage_nightly, coverage(off))]
168mod tests {
169
170    use super::*;
171    use proptest::prelude::*;
172
173    fn proptest_config() -> ProptestConfig {
174        ProptestConfig {
175            #[cfg(miri)]
176            failure_persistence: None,
177            #[cfg(miri)]
178            cases: 32,
179            ..ProptestConfig::default()
180        }
181    }
182
183    #[test]
184    fn const_partial_eq() {
185        static A: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
186        static B: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
187        static C: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 4]);
188
189        assert_eq!(A, B);
190        assert_ne!(A, C);
191    }
192
193    #[test]
194    fn const_ord() {
195        static A: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 3]);
196        static B: ArrayVec<3, u8> = ArrayVec::from_array([1u8, 2, 4]);
197        assert!(A < B);
198    }
199
200    #[test]
201    fn write_filled_const_empty() {
202        let mut vec: ArrayVec<0, ()> = ArrayVec::default();
203        write_filled_const(&mut vec.array, ());
204        assert!(vec.is_empty());
205    }
206
207    #[test]
208    fn from_slice_const() {
209        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
210        let vec: ArrayVec<4, u32> = ArrayVec::<4, _>::from_slice_const(&EXPECTED).unwrap();
211        assert_eq!(vec.as_slice(), EXPECTED);
212    }
213
214    #[test]
215    fn from_slice_overflow() {
216        assert!(ArrayVec::<4, u32>::from_slice_const(&[1; 8]).is_none());
217    }
218
219    #[test]
220    fn truncate_const() {
221        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
222
223        vec.truncate_const(2);
224        assert_eq!(vec.as_slice(), [1, 2]);
225        vec.push(0);
226        assert_eq!(vec.as_slice(), [1, 2, 0]);
227        vec.truncate_const(0);
228        assert_eq!(vec.as_slice(), []);
229        vec.truncate_const(0xcafebabe);
230        assert!(vec.is_empty());
231    }
232
233    #[test]
234    fn truncate_const_heap_types() {
235        let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
236
237        vec.truncate_const(1);
238        assert_eq!(vec.as_slice(), [String::from("hey")]);
239        core::mem::drop(vec);
240    }
241
242    #[test]
243    fn truncate_const_noop() {
244        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
245
246        // Anything >= len is a no-op
247        vec.truncate_const(4);
248        assert_eq!(vec.len(), 4);
249        vec.truncate_const(10);
250        assert_eq!(vec.len(), 4);
251    }
252
253    #[derive(Debug, Clone)]
254    enum Op {
255        Push(u8),
256        TryPush(u8),
257        Pop,
258        Insert(u8, usize),
259        TryInsert(u8, usize),
260        Truncate(usize),
261        Resize(usize, u8),
262        TruncateConst(usize),
263        ResizeConst(usize, u8),
264    }
265
266    fn arbatrary_op() -> impl Strategy<Value = Op> {
267        prop_oneof![
268            any::<u8>().prop_map(Op::Push),
269            any::<u8>().prop_map(Op::TryPush),
270            Just(Op::Pop),
271            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Insert(v, i)),
272            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::TryInsert(v, i)),
273            any::<usize>().prop_map(Op::Truncate),
274            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Resize(i, v)),
275            any::<usize>().prop_map(Op::TruncateConst),
276            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::ResizeConst(i, v)),
277        ]
278    }
279
280    fn model_try_push(v: &mut Vec<u8>, value: u8) -> Result<(), u8> {
281        if v.len() >= v.capacity() {
282            return Err(value);
283        }
284
285        v.push(value);
286        Ok(())
287    }
288
289    fn model_try_insert(v: &mut Vec<u8>, value: u8, idx: usize) -> Result<(), u8> {
290        if v.len() >= v.capacity() || idx > v.len() {
291            return Err(value);
292        }
293
294        v.insert(idx, value);
295        Ok(())
296    }
297
298    proptest! {
299        #![proptest_config(proptest_config())]
300        #[test]
301        fn model_based(ops in prop::collection::vec(arbatrary_op(), 0..50)) {
302            const C: usize = 8;
303            let mut vec: ArrayVec<C, u8> = ArrayVec::new();
304            let mut model: Vec<u8> = Vec::with_capacity(C);
305
306            for op in ops {
307                match op {
308                    Op::Push(v) => {
309                        if model.len() < C {
310                            vec.push(v);
311                            model.push(v);
312                        }
313                    }
314                    Op::TryPush(x) => {
315                        assert_eq!(vec.try_push(x), model_try_push(&mut model, x));
316                    }
317                    Op::Pop => {
318                        assert_eq!(vec.pop(), model.pop());
319                    }
320                    Op::Insert(v, i) => {
321                        if model.len() < C {
322                            let idx = i % (model.len() + 1);
323                            vec.insert(v, idx);
324                            model.insert(idx, v);
325                        }
326                    }
327                    Op::TryInsert(val, idx) => {
328                        assert_eq!(
329                            vec.try_insert(val, idx),
330                            model_try_insert(&mut model, val, idx)
331                        );
332                    }
333                    Op::Truncate(n) => {
334                        let n = n % (C + 1);
335                        vec.truncate(n);
336                        model.truncate(n);
337                    }
338                    Op::Resize(n, x) => {
339                        let n = n % (C + 1);
340                        vec.resize(n, x);
341                        model.resize(n,x);
342                    }
343                    Op::TruncateConst(n) => {
344                        let n = n % (C + 1);
345                        vec.truncate_const(n);
346                        model.truncate(n);
347                    }
348                    Op::ResizeConst(n, x) => {
349                        let n = n % (C + 1);
350                        vec.resize_const(n, x);
351                        model.resize(n,x);
352                    }
353                }
354                assert_eq!(vec.as_slice(), model.as_slice());
355                assert!(vec.len() <= C);
356            }
357        }
358    }
359}