Skip to main content

sharky_arrayvec/
nightly.rs

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