Skip to main content

sharky_arrayvec/
lib.rs

1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
2#![cfg_attr(
3    feature = "nightly",
4    feature(
5        const_clone,
6        const_trait_impl,
7        const_index,
8        const_default,
9        const_convert,
10        const_destruct,
11        const_drop_in_place,
12        min_specialization,
13        const_cmp,
14    )
15)]
16#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
17
18use core::mem;
19use core::mem::MaybeUninit;
20
21mod iter;
22pub use iter::ArrayVecIter;
23
24#[cfg(feature = "deku")]
25pub mod deku;
26
27#[cfg(feature = "nightly")]
28mod nightly;
29
30#[cfg(not(feature = "nightly"))]
31mod stable;
32
33fn write_filled<T: Clone>(slice: &mut [MaybeUninit<T>], value: T) {
34    if slice.is_empty() {
35        return;
36    }
37
38    let len = slice.len();
39    for elem in &mut slice[..len.saturating_sub(1)] {
40        elem.write(value.clone());
41    }
42    slice[len.saturating_sub(1)].write(value);
43}
44
45const fn ptr_cast_array<const N: usize, T>(ptr: *const T) -> *const [T; N] {
46    ptr.cast()
47}
48
49const fn ptr_cast_array_mut<const N: usize, T>(ptr: *mut T) -> *mut [T; N] {
50    ptr.cast()
51}
52
53/// # Safety
54///
55/// - `Src` and `Dest` **must** have the same invariants. That is, any valid
56///   `Src` must also be a valid `Dest`.
57const unsafe fn reinterpret_array_ref<const N: usize, Src, Dest>(src: &[Src; N]) -> &[Dest; N] {
58    #[expect(clippy::manual_assert)]
59    if size_of::<Src>() != size_of::<Dest>() {
60        panic!("Src and Dest have different sizes");
61    }
62
63    let src_ptr: *const Src = src.as_ptr();
64    let dest_ptr: *const Dest = src_ptr.cast();
65    let dest_array_ptr: *const [Dest; N] = ptr_cast_array(dest_ptr);
66
67    // SAFETY: This is always non-null because it's `src`, but with the reference
68    // cast. While Src and Dest might not have the same invariants, they are the
69    // same size, so there can't be any out-of-bounds accesses.
70    unsafe { dest_array_ptr.as_ref_unchecked() }
71}
72
73/// # Safety
74///
75/// - `Src` and `Dest` **must** have the same invariants. That is, any valid
76///   `Src` must also be a valid `Dest`.
77const unsafe fn reinterpret_array_mut<const N: usize, Src, Dest>(
78    src: &mut [Src; N],
79) -> &mut [Dest; N] {
80    #[expect(clippy::manual_assert)]
81    if size_of::<Src>() != size_of::<Dest>() {
82        panic!("Src and Dest have different sizes");
83    }
84
85    let src_ptr: *mut Src = src.as_mut_ptr();
86    let dest_ptr: *mut Dest = src_ptr.cast();
87    let dest_array_ptr: *mut [Dest; N] = ptr_cast_array_mut(dest_ptr);
88
89    // SAFETY: This is always non-null because it's `src`, but with the reference
90    // cast. While Src and Dest might not have the same invariants, they are the
91    // same size, so there can't be any out-of-bounds accesses.
92    unsafe { dest_array_ptr.as_mut_unchecked() }
93}
94
95// NOTE: This is the stalib's implementation
96const fn slice_shift_right<const N: usize, T>(slice: &mut [T], inserted: [T; N]) -> [T; N] {
97    if let Some(shift) = slice.len().checked_sub(N) {
98        // SAFETY: Having just checked that the inserted/returned arrays are
99        // shorter than (or the same length as) the slice:
100        // 1. The read for the items to return is in-bounds
101        // 2. We can `memmove` the slice over to cover the items we're returning to
102        //    ensure those aren't double-dropped
103        // 3. Then we write (in-bounds for the same reason as the read) the inserted
104        //    items atop the items of the slice that we just duplicated
105        //
106        // And none of this can panic, so there's no risk of intermediate unwinds.
107        unsafe {
108            let ptr = slice.as_mut_ptr();
109            let returned = ptr_cast_array_mut::<N, _>(ptr.add(shift)).read();
110            ptr.add(N).copy_from(ptr, shift);
111            ptr_cast_array_mut::<N, _>(ptr).write(inserted);
112            returned
113        }
114    } else {
115        // SAFETY: Having checked that the slice is strictly shorter than the
116        // inserted/returned arrays, it means we'll be copying the whole slice
117        // into the returned array, but that's not enough on its own.  We also
118        // need to copy some of the inserted array into the returned array,
119        // with the rest going into the slice.  Because `&mut` is exclusive
120        // and we own both `inserted` and `returned`, they're all disjoint
121        // allocations from each other as we can use `nonoverlapping` copies.
122        //
123        // We avoid double-frees by `ManuallyDrop`ing the inserted items,
124        // since we always copy them to other locations that will drop them
125        // instead.  Plus nothing in here can panic -- it's just memcpy three
126        // times -- so there's no intermediate unwinds to worry about.
127        unsafe {
128            let len = slice.len();
129            let slice = slice.as_mut_ptr();
130            let inserted = mem::ManuallyDrop::new(inserted);
131            let inserted = (&raw const inserted).cast::<T>();
132
133            let mut returned = MaybeUninit::<[T; N]>::uninit();
134            let ptr = returned.as_mut_ptr().cast::<T>();
135            ptr.add(N.wrapping_sub(len))
136                .copy_from_nonoverlapping(slice, len);
137            ptr.copy_from_nonoverlapping(inserted.add(len), N.wrapping_sub(len));
138            slice.copy_from_nonoverlapping(inserted, len);
139            returned.assume_init()
140        }
141    }
142}
143
144#[must_use]
145pub struct ArrayVec<const C: usize, T> {
146    array: [MaybeUninit<T>; C],
147    len:   usize,
148}
149
150// NOTE: `BoundedVec` must implement `Drop` because "...dropping a
151// `MaybeUninit<T>` will never call `T`’s drop code. It is your responsibility
152// to make sure `T` gets dropped if it got initialized."
153// See <https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.new>
154impl<const C: usize, T> Drop for ArrayVec<C, T> {
155    #[inline]
156    fn drop(&mut self) {
157        for i in 0..self.len {
158            // SAFETY: This is okay because `self.len` tracks the number of initialized
159            // values
160            unsafe { self.array[i].assume_init_drop() };
161        }
162    }
163}
164
165impl<const C: usize, T: Clone> Clone for ArrayVec<C, T> {
166    #[inline]
167    fn clone(&self) -> Self {
168        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<T, C>::V;
169        array[..self.len()].write_clone_of_slice(self.as_slice());
170
171        Self {
172            array,
173            len: self.len,
174        }
175    }
176}
177
178impl<const C: usize, T: core::fmt::Debug> core::fmt::Debug for ArrayVec<C, T> {
179    #[inline]
180    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181        f.debug_list().entries(self.ref_vec().as_slice()).finish()
182    }
183}
184
185impl<const C: usize, T> ArrayVec<C, T> {
186    pub const CAPACITY: usize = C;
187
188    #[inline]
189    pub const fn new() -> Self {
190        Self {
191            array: konst::array::from_fn!(|_| MaybeUninit::uninit()),
192            len:   0,
193        }
194    }
195
196    #[inline]
197    pub const fn len(&self) -> usize {
198        self.len
199    }
200
201    #[inline]
202    pub const fn is_empty(&self) -> bool {
203        self.len() == 0
204    }
205
206    #[inline]
207    pub const fn is_full(&self) -> bool {
208        self.len() == C
209    }
210
211    #[inline]
212    pub fn fill_rest(&mut self, item: &T)
213    where
214        T: Clone, {
215        konst::for_range! { _ in  self.len..C => {
216            self.push(item.clone());
217        }}
218    }
219
220    #[inline]
221    pub const fn as_slice(&self) -> &[T] {
222        // SAFETY: every item 0..self.len is initialized.
223        unsafe { konst::slice::slice_up_to(&self.array, self.len).assume_init_ref() }
224    }
225
226    #[inline]
227    pub const fn as_slice_mut(&mut self) -> &mut [T] {
228        // SAFETY: every item 0..self.len is initialized.
229        unsafe { konst::slice::slice_up_to_mut(&mut self.array, self.len).assume_init_mut() }
230    }
231
232    #[inline]
233    pub const fn from_array(array: [T; C]) -> Self {
234        let array = konst::array::map!(array, MaybeUninit::new);
235        Self { array, len: C }
236    }
237
238    #[inline]
239    pub const fn as_array(&self) -> Option<&[T; C]> {
240        if self.is_full() {
241            // SAFETY: The array is full (len == capacity); therefore, all the values are
242            // initialized and valid.
243            Some(unsafe { reinterpret_array_ref(&self.array) })
244        } else {
245            None
246        }
247    }
248
249    #[inline]
250    pub const fn as_array_mut(&mut self) -> Option<&mut [T; C]> {
251        if self.is_full() {
252            // SAFETY: The array is full (len == capacity); therefore, all the values are
253            // initialized and valid.
254            Some(unsafe { reinterpret_array_mut(&mut self.array) })
255        } else {
256            None
257        }
258    }
259
260    /// Copy all elements from `slice` into a new [`ArrayVec`].
261    ///
262    /// Returns [`None`] if `slice` is larger than the capacity.
263    #[inline]
264    pub fn from_slice(slice: &[T]) -> Option<Self>
265    where
266        T: Clone, {
267        if slice.len() > C {
268            return None;
269        }
270
271        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<T, C>::V;
272        array[..slice.len()].write_clone_of_slice(slice);
273
274        Some(Self {
275            array,
276            len: slice.len(),
277        })
278    }
279
280    /// Create a new [`ArrayVec`] containing references to all the values in
281    /// this one.
282    #[inline]
283    pub const fn ref_vec(&self) -> ArrayVec<C, &T> {
284        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<&T, C>::V;
285        konst::iter::for_each! { (i, elem) in konst::slice::iter(self.as_slice()),enumerate() =>
286        // pub const fn iter(&self) -> ArrayVecIter<C, &T> {
287
288        // }
289
290                array[i].write(elem);
291            }
292
293        ArrayVec {
294            array,
295            len: self.len,
296        }
297    }
298
299    /// Create a new [`ArrayVec`] containing mutable references to all the
300    /// values in this one.
301    #[inline]
302    pub const fn mut_vec(&mut self) -> ArrayVec<C, &mut T> {
303        let len = self.len;
304        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<&mut T, C>::V;
305        konst::iter::for_each! { (i, elem) in konst::slice::iter_mut(self.as_slice_mut()),enumerate() =>
306            array[i].write(elem);
307        }
308        ArrayVec { array, len }
309    }
310
311    /// Remove an the final element from the the vector.
312    ///
313    /// `None` is returned when the vector is empty.
314    #[inline]
315    pub const fn pop(&mut self) -> Option<T> {
316        if self.len == 0 {
317            return None;
318        }
319
320        self.len = self.len.strict_sub(1);
321
322        // SAFETY:
323        // - `self.len > 0`; therefore `self.len - 1` is a valid index.
324        // - `0..self.len` is initialized
325        // - `self.len` is decremented to prevent any reads of the duplicated element.
326        let item = unsafe { self.array[self.len].assume_init_read() };
327        Some(item)
328    }
329
330    /// Add an item to the back of the vector.
331    ///
332    /// # Panics
333    ///
334    /// This function panics when:
335    ///
336    /// 1. The array is full.
337    #[inline]
338    pub const fn push(&mut self, item: T) {
339        assert!(
340            self.len < C,
341            "Tried to push to a vector without enough capacity."
342        );
343
344        // SAFETY:
345        // - `self.len < C`; therefore, `self.len` is a valid index.
346        // - `0..self.len` are valid elements; therefore, writing to `self.len` doesn't
347        //   overwrite any valid and non-dropped elements.
348        // - `self.len` is incremented afterwards to prevent double-invocations that
349        //   cause missed `Drop`s.
350        self.array[self.len].write(item);
351        self.len = self.len.strict_add(1);
352    }
353
354    /// Add an item to the back of the vector.
355    ///
356    /// # Returns
357    ///
358    /// This function returns the provided item as the error variant when:
359    ///
360    /// - `index` is out of bounds.
361    #[inline]
362    pub const fn try_push(&mut self, item: T) -> Result<(), T> {
363        if self.len >= C {
364            return Err(item);
365        }
366
367        self.push(item);
368        Ok(())
369    }
370
371    /// Insert `item` at `index` shifting all the elements on the right by one,
372    /// and extend the length to acommodate.
373    ///
374    /// # Panics
375    ///
376    /// This function panics when:
377    ///
378    /// - The array is at it's maximum length.
379    #[inline]
380    pub const fn insert(&mut self, item: T, index: usize) {
381        assert!(self.len < C, "Tried to insert to a full vector.");
382        assert!(index <= self.len, "Index out of bounds.");
383
384        // NOTE: it's okay to ignore the result of this because we checked above that
385        // there is at least one invalid (thus removable) element at the end
386        // (`self.len < C`).
387        let _ = slice_shift_right(
388            konst::slice::slice_from_mut(&mut self.array, index),
389            [MaybeUninit::new(item)],
390        );
391        self.len = self.len.strict_add(1);
392    }
393
394    /// Attempt to insert `item` at `index` shifting all the elements on the
395    /// right by one, and extend the length to acommodate.
396    ///
397    /// # Returns
398    ///
399    /// This function returns the provided item as the error variant when:
400    ///
401    /// - The array is full.
402    /// - `index` is out of bounds.
403    #[inline]
404    pub const fn try_insert(&mut self, item: T, index: usize) -> Result<(), T> {
405        if self.len >= C || index > self.len {
406            return Err(item);
407        }
408        self.insert(item, index);
409        Ok(())
410    }
411
412    #[inline]
413    pub fn truncate(&mut self, len: usize) {
414        if len >= self.len {
415            return;
416        }
417
418        // SAFETY: These elements can be dropped because everything from `0..self.len`
419        // is initialized. The dropped elements will not be accessed again because
420        // `self.len` is set to `len`
421        unsafe { self.array[len..self.len].assume_init_drop() };
422        self.len = len;
423    }
424
425    /// Resize so that `len` is equal to `new_len`.
426    ///
427    /// If `new_len` is greater than `len`, the vec is extended by the
428    /// difference with each additional slot filled with `value`. If `new_len`
429    /// is less than `len`, the vec is truncated.
430    ///
431    /// # Panics
432    ///
433    /// This function panics when:
434    ///
435    /// 1. `new_len > C`
436    #[inline]
437    pub fn resize(&mut self, new_len: usize, value: T)
438    where
439        T: Clone, {
440        assert!(new_len <= C, "Tried to resize beyond capacity.");
441
442        if new_len < self.len {
443            self.truncate(new_len);
444        } else if new_len > self.len {
445            write_filled(&mut self.array[self.len..new_len], value);
446            self.len = new_len;
447        }
448    }
449}
450#[cfg(test)]
451#[cfg_attr(coverage_nightly, coverage(off))]
452mod tests {
453    use super::*;
454    use proptest::prelude::*;
455
456    fn proptest_config() -> ProptestConfig {
457        ProptestConfig {
458            #[cfg(miri)]
459            failure_persistence: None,
460            #[cfg(miri)]
461            cases: 32,
462            ..ProptestConfig::default()
463        }
464    }
465
466    #[test]
467    #[expect(clippy::undocumented_unsafe_blocks)]
468    fn ptr_cast_array_eq() {
469        let x = &[0u8; 4];
470        let x_ptr: *const u8 = x.as_ptr();
471
472        let y_ptr: *const [u8; 4] = ptr_cast_array(x_ptr);
473        let y = unsafe { y_ptr.as_ref().unwrap() };
474        assert_eq!(x, y);
475    }
476
477    #[test]
478    fn test_ptr_cast_array_mut() {
479        let x = &mut [0u8; 4];
480        let y_ptr: *mut [u8; 4] = ptr_cast_array_mut(x.as_mut_ptr());
481
482        assert_eq!(x.as_mut_ptr() as usize, y_ptr as usize);
483    }
484
485    #[test]
486    #[expect(clippy::undocumented_unsafe_blocks)]
487    fn test_reinterpret_array_ref() {
488        let x = &[0i32];
489        let y: &[u32; 1] = unsafe { reinterpret_array_ref(x) };
490        assert_eq!(x[0] as u32, y[0]);
491    }
492
493    #[test]
494    #[should_panic]
495    #[expect(clippy::undocumented_unsafe_blocks)]
496    fn test_reinterpret_array_ref_unequal_sizes() {
497        let x = &[0i32];
498        let _y: &[u128; 1] = unsafe { reinterpret_array_ref(x) };
499    }
500
501    #[test]
502    #[expect(clippy::undocumented_unsafe_blocks)]
503    fn test_reinterpret_array_mut() {
504        let mut x = [0x1i32];
505        let y: &mut [u32; 1] = unsafe { reinterpret_array_mut(&mut x) };
506        assert_eq!(0x1, y[0]);
507    }
508
509    #[test]
510    #[should_panic]
511    #[expect(clippy::undocumented_unsafe_blocks)]
512    fn test_reinterpret_array_mut_unequal_sizes() {
513        let mut x = [0x1i32];
514        let _y: &mut [u8; 1] = unsafe { reinterpret_array_mut(&mut x) };
515    }
516
517    #[test]
518    fn test_write_filled_empty() {
519        let mut vec: ArrayVec<0, ()> = ArrayVec::default();
520        write_filled(&mut vec.array, ());
521        assert!(vec.is_empty());
522    }
523
524    #[test]
525    fn default() {
526        let vec: ArrayVec<4, ()> = ArrayVec::default();
527        assert!(vec.is_empty());
528    }
529
530    #[test]
531    fn drop_empy() {
532        let x: ArrayVec<0, ()> = ArrayVec::new();
533        core::mem::drop(x);
534    }
535
536    #[test]
537    fn drop_heap_types() {
538        let x = ArrayVec::from_array([Box::new(0)]);
539        core::mem::drop(x);
540        let x = ArrayVec::from_array([String::from("I ♥ cum")]);
541        core::mem::drop(x);
542        let x = ArrayVec::from_array([vec![String::from("I ♥ you")]]);
543        core::mem::drop(x);
544    }
545
546    #[test]
547    fn clone() {
548        let vec = ArrayVec::from_array([1, 2, 3, 4]);
549        let mut vec2 = vec.clone();
550        assert_eq!(vec.as_slice(), vec2.as_slice());
551
552        vec2[1] = 69;
553        assert_eq!(vec[1], 2);
554    }
555
556    #[test]
557    fn len() {
558        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
559        let vec = ArrayVec::from_array(EXPECTED);
560        assert_eq!(vec.len(), EXPECTED.len());
561    }
562
563    #[test]
564    fn is_empty() {
565        let vec: ArrayVec<4, u8> = ArrayVec::new();
566        assert!(vec.is_empty());
567    }
568
569    #[test]
570    fn is_full() {
571        let vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
572        assert!(vec.is_full());
573    }
574
575    #[test]
576    fn from_array() {
577        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
578        let vec = ArrayVec::from_array(EXPECTED);
579        assert_eq!(vec.as_slice(), EXPECTED);
580    }
581
582    #[test]
583    fn deref() {
584        let vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
585        assert_eq!(&*vec, [0; 4]);
586    }
587
588    #[test]
589    fn deref_mut() {
590        let mut vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
591        assert_eq!(&*vec, [0; 4]);
592
593        for item in &mut *vec {
594            *item = 10;
595        }
596        assert_eq!(&*vec, [10; 4]);
597    }
598
599    #[test]
600    fn from_slice() {
601        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
602        let vec = ArrayVec::<4, _>::from_slice(&EXPECTED).unwrap();
603        assert_eq!(vec.as_slice(), EXPECTED);
604    }
605
606    #[test]
607    #[should_panic]
608    fn from_slice_too_large() {
609        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
610        let _ = ArrayVec::<1, _>::from_slice(&EXPECTED).unwrap();
611    }
612
613    #[test]
614    fn as_array() {
615        let vec: ArrayVec<4, u8> = ArrayVec::from_array([69; 4]);
616        assert_eq!(&*vec, vec.as_array().unwrap());
617    }
618
619    #[test]
620    fn as_array_mut() {
621        let mut vec: ArrayVec<4, u8> = ArrayVec::from_array([69; 4]);
622        vec.as_array_mut().unwrap()[2] = 3;
623        assert_eq!(&*vec, [69, 69, 3, 69]);
624    }
625
626    #[test]
627    fn as_array_not_full() {
628        let vec: ArrayVec<4, u8> = ArrayVec::new();
629        assert_eq!(vec.as_array(), None);
630    }
631
632    #[test]
633    fn as_array_mut_not_full() {
634        let mut vec: ArrayVec<4, u8> = ArrayVec::new();
635        assert_eq!(vec.as_array_mut(), None);
636    }
637
638    #[test]
639    fn push() {
640        let mut vec: ArrayVec<5, u8> = ArrayVec::new();
641        vec.push(230);
642        assert_eq!(vec.as_slice(), &[230]);
643        vec.push(69);
644        assert_eq!(vec.as_slice(), &[230, 69]);
645        vec.push(101);
646        assert_eq!(vec.as_slice(), &[230, 69, 101]);
647    }
648
649    #[test]
650    #[should_panic]
651    fn push_beyond_capacity() {
652        let mut vec: ArrayVec<0, u8> = ArrayVec::new();
653        vec.push(69);
654    }
655
656    #[test]
657    fn pop_removes_values() {
658        let mut vec = ArrayVec::from_array([2, 3, 4]);
659        assert_eq!(vec.pop(), Some(4));
660        assert_eq!(&*vec, &[2, 3]);
661
662        assert_eq!(vec.pop(), Some(3));
663        assert_eq!(&*vec, &[2]);
664
665        assert_eq!(vec.pop(), Some(2));
666        assert_eq!(&*vec, &[]);
667
668        assert_eq!(vec.pop(), None);
669        assert_eq!(&*vec, &[]);
670    }
671
672    #[test]
673    fn pop_heap_types() {
674        let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
675        assert_eq!(vec.pop(), Some(String::from("boy")));
676        core::mem::drop(vec);
677    }
678
679    #[test]
680    fn push_pop() {
681        let mut vec = ArrayVec::<2, u8>::new();
682
683        vec.push(1);
684        assert_eq!(vec.pop(), Some(1));
685        assert_eq!(&*vec, &[]);
686
687        vec.push(8);
688        assert_eq!(vec.pop(), Some(8));
689        assert_eq!(&*vec, &[]);
690    }
691
692    #[test]
693    fn try_push_ok() {
694        let mut vec: ArrayVec<2, u8> = ArrayVec::new();
695        assert_eq!(vec.try_push(1), Ok(()));
696        assert_eq!(vec.try_push(2), Ok(()));
697    }
698
699    #[test]
700    fn try_push_full() {
701        let mut vec: ArrayVec<1, u8> = ArrayVec::new();
702        vec.push(1);
703        assert_eq!(vec.try_push(99), Err(99));
704        assert_eq!(vec.as_slice(), &[1]);
705    }
706
707    #[test]
708    fn try_insert() {
709        let mut vec: ArrayVec<4, u8> = ArrayVec::from_slice(&[1, 3]).unwrap();
710        assert_eq!(vec.try_insert(2, 1), Ok(()));
711        assert_eq!(vec.as_slice(), &[1, 2, 3]);
712    }
713
714    #[test]
715    fn try_insert_out_of_bounds() {
716        let mut vec: ArrayVec<4, u8> = ArrayVec::new();
717        assert!(vec.try_insert(0, 1).is_err());
718    }
719
720    #[test]
721    fn truncate() {
722        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
723
724        vec.truncate(2);
725        assert_eq!(vec.as_slice(), [1, 2]);
726        vec.push(0);
727        assert_eq!(vec.as_slice(), [1, 2, 0]);
728        vec.truncate(0);
729        assert_eq!(vec.as_slice(), []);
730        vec.truncate(0xcafebabe);
731        assert!(vec.is_empty());
732    }
733
734    #[test]
735    fn truncate_heap_types() {
736        let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
737
738        vec.truncate(1);
739        assert_eq!(vec.as_slice(), [String::from("hey")]);
740        core::mem::drop(vec);
741    }
742
743    #[test]
744    fn truncate_noop() {
745        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
746
747        // Anything >= len is a no-op
748        vec.truncate(4);
749        assert_eq!(vec.len(), 4);
750        vec.truncate(10);
751        assert_eq!(vec.len(), 4);
752    }
753
754    #[test]
755    fn resize_truncate() {
756        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
757
758        vec.resize(2, 0);
759        assert_eq!(vec.len(), 2);
760    }
761
762    #[test]
763    #[should_panic]
764    fn resize_beyond_capacity() {
765        let mut vec = ArrayVec::<1, _>::from_slice(&[1]).unwrap();
766
767        vec.resize(2, 0);
768    }
769
770    #[test]
771    fn resize_extend_heap_types() {
772        let mut vec = ArrayVec::<1, _>::from_slice(&[]).unwrap();
773
774        vec.resize(1, String::from("girls rule"));
775        assert_eq!(vec.len(), 1);
776        assert_eq!(vec.as_slice(), [String::from("girls rule")]);
777    }
778
779    #[test]
780    fn insert() {
781        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
782        let vec: ArrayVec<4, u32> = {
783            let mut vec = ArrayVec::<4, _>::from_slice(&[67, 420, 80085]).unwrap();
784            vec.insert(69, 1);
785            vec
786        };
787        assert_eq!(vec.as_slice(), EXPECTED);
788    }
789
790    #[test]
791    #[should_panic]
792    fn insert_full() {
793        let mut vec = ArrayVec::<0, u64>::from_array([]);
794        vec.insert(0xcafebabe, 0);
795    }
796
797    proptest! {
798        #![proptest_config(proptest_config())]
799        #[test]
800        fn resize_extend(
801            initial in prop::collection::vec(0u8..=255, 0..4usize),
802            fill: u8,
803            extra in 0..5usize,
804        ) {
805            let new_len = initial.len() + extra;
806            let mut vec = ArrayVec::<8, u8>::from_slice(&initial).unwrap();
807            vec.resize(new_len, fill);
808
809            assert_eq!(&vec.as_slice()[..initial.len()], initial.as_slice());
810            assert!(vec.as_slice()[initial.len()..].iter().all(|&x| x == fill));
811            assert_eq!(vec.len(), new_len);
812        }
813    }
814
815    #[test]
816    fn ref_vec() {
817        let vec = ArrayVec::from_array([7; 4]);
818        let slice: ArrayVec<4, &i32> = vec.ref_vec();
819        assert!(vec.iter().zip(slice.iter().copied()).all(|(&l, r)| l.eq(r)));
820    }
821
822    #[test]
823    fn mut_vec() {
824        let mut vec = ArrayVec::from_array([7; 4]);
825        let slice: ArrayVec<4, &mut i32> = vec.mut_vec();
826
827        for x in slice {
828            *x = 69; // I'm so horny
829        }
830
831        assert_eq!(&*vec, [69; 4]);
832    }
833
834    #[test]
835    fn debug_noop() {
836        let vec = ArrayVec::from_array([1u8, 2, 3, 4]);
837        eprintln!("{vec:?}");
838    }
839
840    #[test]
841    fn partial_eq() {
842        let a = ArrayVec::from_array([1u8, 2, 3]);
843        let b = ArrayVec::from_array([1u8, 2, 3]);
844        let c = ArrayVec::from_array([1u8, 2, 4]);
845        assert_eq!(a, b);
846        assert_ne!(a, c);
847    }
848
849    #[test]
850    fn ord() {
851        let a = ArrayVec::from_array([1u8, 2, 3]);
852        let b = ArrayVec::from_array([1u8, 2, 4]);
853        assert!(a < b);
854    }
855
856    proptest! {
857        #![proptest_config(proptest_config())]
858        #[test]
859        fn shift_right_semantics(
860            original in prop::collection::vec(0u8..=255, 0..16),
861            item: u8,
862        ) {
863            // Build conceptual [item, original...], then split
864            let mut expected_slice = vec![item];
865            expected_slice.extend_from_slice(&original);
866            expected_slice.truncate(original.len()); // first `len` stay
867            let expected_returned = {
868                let mut full = vec![item];
869                full.extend_from_slice(&original);
870                full[original.len()..].to_vec()        // last 1 is returned
871            };
872
873            let mut buf = original.clone();
874            let returned = slice_shift_right(&mut buf, [item]);
875
876            assert_eq!(buf, expected_slice);
877            assert_eq!(returned, expected_returned.as_slice());
878        }
879    }
880
881    #[derive(Debug, Clone)]
882    enum Op {
883        Push(u8),
884        TryPush(u8),
885        Pop,
886        Insert(u8, usize),
887        TryInsert(u8, usize),
888        Truncate(usize),
889        Resize(usize, u8),
890    }
891
892    fn arbatrary_op() -> impl Strategy<Value = Op> {
893        prop_oneof![
894            any::<u8>().prop_map(Op::Push),
895            any::<u8>().prop_map(Op::TryPush),
896            Just(Op::Pop),
897            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Insert(v, i)),
898            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::TryInsert(v, i)),
899            any::<usize>().prop_map(Op::Truncate),
900            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Resize(i, v)),
901        ]
902    }
903
904    fn model_try_push(v: &mut Vec<u8>, value: u8) -> Result<(), u8> {
905        if v.len() >= v.capacity() {
906            return Err(value);
907        }
908
909        v.push(value);
910        Ok(())
911    }
912
913    fn model_try_insert(v: &mut Vec<u8>, value: u8, idx: usize) -> Result<(), u8> {
914        if v.len() >= v.capacity() || idx > v.len() {
915            return Err(value);
916        }
917
918        v.insert(idx, value);
919        Ok(())
920    }
921
922    proptest! {
923        #![proptest_config(proptest_config())]
924        #[test]
925        fn model_based(ops in prop::collection::vec(arbatrary_op(), 0..50)) {
926            const C: usize = 8;
927            let mut vec: ArrayVec<C, u8> = ArrayVec::new();
928            let mut model: Vec<u8> = Vec::with_capacity(C);
929
930            for op in ops {
931                match op {
932                    Op::Push(v) => {
933                        if model.len() < C {
934                            vec.push(v);
935                            model.push(v);
936                        }
937                    }
938                    Op::TryPush(x) => {
939                        assert_eq!(vec.try_push(x), model_try_push(&mut model, x));
940                    }
941                    Op::Pop => {
942                        assert_eq!(vec.pop(), model.pop());
943                    }
944                    Op::Insert(v, i) => {
945                        if model.len() < C {
946                            let idx = i % (model.len() + 1);
947                            vec.insert(v, idx);
948                            model.insert(idx, v);
949                        }
950                    }
951                    Op::TryInsert(val, idx) => {
952                        assert_eq!(
953                            vec.try_insert(val, idx),
954                            model_try_insert(&mut model, val, idx)
955                        );
956                    }
957                    Op::Truncate(n) => {
958                        let n = n % (C + 1);
959                        vec.truncate(n);
960                        model.truncate(n);
961                    }
962                    Op::Resize(n, x) => {
963                        let n = n % (C + 1);
964                        vec.resize(n, x);
965                        model.resize(n,x);
966                    }
967                }
968                assert_eq!(vec.as_slice(), model.as_slice());
969                assert!(vec.len() <= C);
970            }
971        }
972    }
973}