Skip to main content

sharky_arrayvec/
lib.rs

1#![cfg_attr(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 = "nightly")]
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 const fn as_slice(&self) -> &[T] {
213        // SAFETY: every item 0..self.len is initialized.
214        unsafe { konst::slice::slice_up_to(&self.array, self.len).assume_init_ref() }
215    }
216
217    #[inline]
218    pub const fn as_slice_mut(&mut self) -> &mut [T] {
219        // SAFETY: every item 0..self.len is initialized.
220        unsafe { konst::slice::slice_up_to_mut(&mut self.array, self.len).assume_init_mut() }
221    }
222
223    #[inline]
224    pub const fn from_array(array: [T; C]) -> Self {
225        let array = konst::array::map!(array, MaybeUninit::new);
226        Self { array, len: C }
227    }
228
229    #[inline]
230    pub const fn as_array(&self) -> Option<&[T; C]> {
231        if self.is_full() {
232            // SAFETY: The array is full (len == capacity); therefore, all the values are
233            // initialized and valid.
234            Some(unsafe { reinterpret_array_ref(&self.array) })
235        } else {
236            None
237        }
238    }
239
240    #[inline]
241    pub const fn as_array_mut(&mut self) -> Option<&mut [T; C]> {
242        if self.is_full() {
243            // SAFETY: The array is full (len == capacity); therefore, all the values are
244            // initialized and valid.
245            Some(unsafe { reinterpret_array_mut(&mut self.array) })
246        } else {
247            None
248        }
249    }
250
251    /// Copy all elements from `slice` into a new [`ArrayVec`].
252    ///
253    /// Returns [`None`] if `slice` is larger than the capacity.
254    #[inline]
255    pub fn from_slice(slice: &[T]) -> Option<Self>
256    where
257        T: Clone, {
258        if slice.len() > C {
259            return None;
260        }
261
262        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<T, C>::V;
263        array[..slice.len()].write_clone_of_slice(slice);
264
265        Some(Self {
266            array,
267            len: slice.len(),
268        })
269    }
270
271    /// Create a new [`ArrayVec`] containing references to all the values in
272    /// this one.
273    #[inline]
274    pub const fn ref_vec(&self) -> ArrayVec<C, &T> {
275        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<&T, C>::V;
276        konst::iter::for_each! { (i, elem) in konst::slice::iter(self.as_slice()),enumerate() =>
277        // pub const fn iter(&self) -> ArrayVecIter<C, &T> {
278
279        // }
280
281                array[i].write(elem);
282            }
283
284        ArrayVec {
285            array,
286            len: self.len,
287        }
288    }
289
290    /// Create a new [`ArrayVec`] containing mutable references to all the
291    /// values in this one.
292    #[inline]
293    pub const fn mut_vec(&mut self) -> ArrayVec<C, &mut T> {
294        let len = self.len;
295        let mut array = konst::maybe_uninit::UNINIT_ARRAY::<&mut T, C>::V;
296        konst::iter::for_each! { (i, elem) in konst::slice::iter_mut(self.as_slice_mut()),enumerate() =>
297            array[i].write(elem);
298        }
299        ArrayVec { array, len }
300    }
301
302    /// Remove an the final element from the the vector.
303    ///
304    /// `None` is returned when the vector is empty.
305    #[inline]
306    pub const fn pop(&mut self) -> Option<T> {
307        if self.len == 0 {
308            return None;
309        }
310
311        self.len = self.len.strict_sub(1);
312
313        // SAFETY:
314        // - `self.len > 0`; therefore `self.len - 1` is a valid index.
315        // - `0..self.len` is initialized
316        // - `self.len` is decremented to prevent any reads of the duplicated element.
317        let item = unsafe { self.array[self.len].assume_init_read() };
318        Some(item)
319    }
320
321    /// Add an item to the back of the vector.
322    ///
323    /// # Panics
324    ///
325    /// This function panics when:
326    ///
327    /// 1. The array is full.
328    #[inline]
329    pub const fn push(&mut self, item: T) {
330        assert!(
331            self.len < C,
332            "Tried to push to a vector without enough capacity."
333        );
334
335        // SAFETY:
336        // - `self.len < C`; therefore, `self.len` is a valid index.
337        // - `0..self.len` are valid elements; therefore, writing to `self.len` doesn't
338        //   overwrite any valid and non-dropped elements.
339        // - `self.len` is incremented afterwards to prevent double-invocations that
340        //   cause missed `Drop`s.
341        self.array[self.len].write(item);
342        self.len = self.len.strict_add(1);
343    }
344
345    /// Add an item to the back of the vector.
346    ///
347    /// # Returns
348    ///
349    /// This function returns the provided item as the error variant when:
350    ///
351    /// - `index` is out of bounds.
352    #[inline]
353    pub const fn try_push(&mut self, item: T) -> Result<(), T> {
354        if self.len >= C {
355            return Err(item);
356        }
357
358        self.push(item);
359        Ok(())
360    }
361
362    /// Insert `item` at `index` shifting all the elements on the right by one,
363    /// and extend the length to acommodate.
364    ///
365    /// # Panics
366    ///
367    /// This function panics when:
368    ///
369    /// - The array is at it's maximum length.
370    #[inline]
371    pub const fn insert(&mut self, item: T, index: usize) {
372        assert!(self.len < C, "Tried to insert to a full vector.");
373        assert!(index <= self.len, "Index out of bounds.");
374
375        // NOTE: it's okay to ignore the result of this because we checked above that
376        // there is at least one invalid (thus removable) element at the end
377        // (`self.len < C`).
378        let _ = slice_shift_right(
379            konst::slice::slice_from_mut(&mut self.array, index),
380            [MaybeUninit::new(item)],
381        );
382        self.len = self.len.strict_add(1);
383    }
384
385    /// Attempt to insert `item` at `index` shifting all the elements on the
386    /// right by one, and extend the length to acommodate.
387    ///
388    /// # Returns
389    ///
390    /// This function returns the provided item as the error variant when:
391    ///
392    /// - The array is full.
393    /// - `index` is out of bounds.
394    #[inline]
395    pub const fn try_insert(&mut self, item: T, index: usize) -> Result<(), T> {
396        if self.len >= C || index > self.len {
397            return Err(item);
398        }
399        self.insert(item, index);
400        Ok(())
401    }
402
403    #[inline]
404    pub fn truncate(&mut self, len: usize) {
405        if len >= self.len {
406            return;
407        }
408
409        // SAFETY: These elements can be dropped because everything from `0..self.len`
410        // is initialized. The dropped elements will not be accessed again because
411        // `self.len` is set to `len`
412        unsafe { self.array[len..self.len].assume_init_drop() };
413        self.len = len;
414    }
415
416    /// Resize so that `len` is equal to `new_len`.
417    ///
418    /// If `new_len` is greater than `len`, the vec is extended by the
419    /// difference with each additional slot filled with `value`. If `new_len`
420    /// is less than `len`, the vec is truncated.
421    ///
422    /// # Panics
423    ///
424    /// This function panics when:
425    ///
426    /// 1. `new_len > C`
427    #[inline]
428    pub fn resize(&mut self, new_len: usize, value: T)
429    where
430        T: Clone, {
431        assert!(new_len <= C, "Tried to resize beyond capacity.");
432
433        if new_len < self.len {
434            self.truncate(new_len);
435        } else if new_len > self.len {
436            write_filled(&mut self.array[self.len..new_len], value);
437            self.len = new_len;
438        }
439    }
440}
441#[cfg(test)]
442#[cfg_attr(coverage_nightly, coverage(off))]
443mod tests {
444    use super::*;
445    use proptest::prelude::*;
446
447    fn proptest_config() -> ProptestConfig {
448        ProptestConfig {
449            #[cfg(miri)]
450            failure_persistence: None,
451            #[cfg(miri)]
452            cases: 32,
453            ..ProptestConfig::default()
454        }
455    }
456
457    #[test]
458    #[expect(clippy::undocumented_unsafe_blocks)]
459    fn ptr_cast_array_eq() {
460        let x = &[0u8; 4];
461        let x_ptr: *const u8 = x.as_ptr();
462
463        let y_ptr: *const [u8; 4] = ptr_cast_array(x_ptr);
464        let y = unsafe { y_ptr.as_ref().unwrap() };
465        assert_eq!(x, y);
466    }
467
468    #[test]
469    fn test_ptr_cast_array_mut() {
470        let x = &mut [0u8; 4];
471        let y_ptr: *mut [u8; 4] = ptr_cast_array_mut(x.as_mut_ptr());
472
473        assert_eq!(x.as_mut_ptr() as usize, y_ptr as usize);
474    }
475
476    #[test]
477    #[expect(clippy::undocumented_unsafe_blocks)]
478    fn test_reinterpret_array_ref() {
479        let x = &[0i32];
480        let y: &[u32; 1] = unsafe { reinterpret_array_ref(x) };
481        assert_eq!(x[0] as u32, y[0]);
482    }
483
484    #[test]
485    #[should_panic]
486    #[expect(clippy::undocumented_unsafe_blocks)]
487    fn test_reinterpret_array_ref_unequal_sizes() {
488        let x = &[0i32];
489        let _y: &[u128; 1] = unsafe { reinterpret_array_ref(x) };
490    }
491
492    #[test]
493    #[expect(clippy::undocumented_unsafe_blocks)]
494    fn test_reinterpret_array_mut() {
495        let mut x = [0x1i32];
496        let y: &mut [u32; 1] = unsafe { reinterpret_array_mut(&mut x) };
497        assert_eq!(0x1, y[0]);
498    }
499
500    #[test]
501    #[should_panic]
502    #[expect(clippy::undocumented_unsafe_blocks)]
503    fn test_reinterpret_array_mut_unequal_sizes() {
504        let mut x = [0x1i32];
505        let _y: &mut [u8; 1] = unsafe { reinterpret_array_mut(&mut x) };
506    }
507
508    #[test]
509    fn test_write_filled_empty() {
510        let mut vec: ArrayVec<0, ()> = ArrayVec::default();
511        write_filled(&mut vec.array, ());
512        assert!(vec.is_empty());
513    }
514
515    #[test]
516    fn default() {
517        let vec: ArrayVec<4, ()> = ArrayVec::default();
518        assert!(vec.is_empty());
519    }
520
521    #[test]
522    fn drop_empy() {
523        let x: ArrayVec<0, ()> = ArrayVec::new();
524        core::mem::drop(x);
525    }
526
527    #[test]
528    fn drop_heap_types() {
529        let x = ArrayVec::from_array([Box::new(0)]);
530        core::mem::drop(x);
531        let x = ArrayVec::from_array([String::from("I ♥ cum")]);
532        core::mem::drop(x);
533        let x = ArrayVec::from_array([vec![String::from("I ♥ you")]]);
534        core::mem::drop(x);
535    }
536
537    #[test]
538    fn clone() {
539        let vec = ArrayVec::from_array([1, 2, 3, 4]);
540        let mut vec2 = vec.clone();
541        assert_eq!(vec.as_slice(), vec2.as_slice());
542
543        vec2[1] = 69;
544        assert_eq!(vec[1], 2);
545    }
546
547    #[test]
548    fn len() {
549        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
550        let vec = ArrayVec::from_array(EXPECTED);
551        assert_eq!(vec.len(), EXPECTED.len());
552    }
553
554    #[test]
555    fn is_empty() {
556        let vec: ArrayVec<4, u8> = ArrayVec::new();
557        assert!(vec.is_empty());
558    }
559
560    #[test]
561    fn is_full() {
562        let vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
563        assert!(vec.is_full());
564    }
565
566    #[test]
567    fn from_array() {
568        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
569        let vec = ArrayVec::from_array(EXPECTED);
570        assert_eq!(vec.as_slice(), EXPECTED);
571    }
572
573    #[test]
574    fn deref() {
575        let vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
576        assert_eq!(&*vec, [0; 4]);
577    }
578
579    #[test]
580    fn deref_mut() {
581        let mut vec: ArrayVec<4, u8> = ArrayVec::from_array([0; 4]);
582        assert_eq!(&*vec, [0; 4]);
583
584        for item in &mut *vec {
585            *item = 10;
586        }
587        assert_eq!(&*vec, [10; 4]);
588    }
589
590    #[test]
591    fn from_slice() {
592        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
593        let vec = ArrayVec::<4, _>::from_slice(&EXPECTED).unwrap();
594        assert_eq!(vec.as_slice(), EXPECTED);
595    }
596
597    #[test]
598    #[should_panic]
599    fn from_slice_too_large() {
600        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
601        let _ = ArrayVec::<1, _>::from_slice(&EXPECTED).unwrap();
602    }
603
604    #[test]
605    fn as_array() {
606        let vec: ArrayVec<4, u8> = ArrayVec::from_array([69; 4]);
607        assert_eq!(&*vec, vec.as_array().unwrap());
608    }
609
610    #[test]
611    fn as_array_mut() {
612        let mut vec: ArrayVec<4, u8> = ArrayVec::from_array([69; 4]);
613        vec.as_array_mut().unwrap()[2] = 3;
614        assert_eq!(&*vec, [69, 69, 3, 69]);
615    }
616
617    #[test]
618    fn as_array_not_full() {
619        let vec: ArrayVec<4, u8> = ArrayVec::new();
620        assert_eq!(vec.as_array(), None);
621    }
622
623    #[test]
624    fn as_array_mut_not_full() {
625        let mut vec: ArrayVec<4, u8> = ArrayVec::new();
626        assert_eq!(vec.as_array_mut(), None);
627    }
628
629    #[test]
630    fn push() {
631        let mut vec: ArrayVec<5, u8> = ArrayVec::new();
632        vec.push(230);
633        assert_eq!(vec.as_slice(), &[230]);
634        vec.push(69);
635        assert_eq!(vec.as_slice(), &[230, 69]);
636        vec.push(101);
637        assert_eq!(vec.as_slice(), &[230, 69, 101]);
638    }
639
640    #[test]
641    #[should_panic]
642    fn push_beyond_capacity() {
643        let mut vec: ArrayVec<0, u8> = ArrayVec::new();
644        vec.push(69);
645    }
646
647    #[test]
648    fn pop_removes_values() {
649        let mut vec = ArrayVec::from_array([2, 3, 4]);
650        assert_eq!(vec.pop(), Some(4));
651        assert_eq!(&*vec, &[2, 3]);
652
653        assert_eq!(vec.pop(), Some(3));
654        assert_eq!(&*vec, &[2]);
655
656        assert_eq!(vec.pop(), Some(2));
657        assert_eq!(&*vec, &[]);
658
659        assert_eq!(vec.pop(), None);
660        assert_eq!(&*vec, &[]);
661    }
662
663    #[test]
664    fn pop_heap_types() {
665        let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
666        assert_eq!(vec.pop(), Some(String::from("boy")));
667        core::mem::drop(vec);
668    }
669
670    #[test]
671    fn push_pop() {
672        let mut vec = ArrayVec::<2, u8>::new();
673
674        vec.push(1);
675        assert_eq!(vec.pop(), Some(1));
676        assert_eq!(&*vec, &[]);
677
678        vec.push(8);
679        assert_eq!(vec.pop(), Some(8));
680        assert_eq!(&*vec, &[]);
681    }
682
683    #[test]
684    fn try_push_ok() {
685        let mut vec: ArrayVec<2, u8> = ArrayVec::new();
686        assert_eq!(vec.try_push(1), Ok(()));
687        assert_eq!(vec.try_push(2), Ok(()));
688    }
689
690    #[test]
691    fn try_push_full() {
692        let mut vec: ArrayVec<1, u8> = ArrayVec::new();
693        vec.push(1);
694        assert_eq!(vec.try_push(99), Err(99));
695        assert_eq!(vec.as_slice(), &[1]);
696    }
697
698    #[test]
699    fn try_insert() {
700        let mut vec: ArrayVec<4, u8> = ArrayVec::from_slice(&[1, 3]).unwrap();
701        assert_eq!(vec.try_insert(2, 1), Ok(()));
702        assert_eq!(vec.as_slice(), &[1, 2, 3]);
703    }
704
705    #[test]
706    fn try_insert_out_of_bounds() {
707        let mut vec: ArrayVec<4, u8> = ArrayVec::new();
708        assert!(vec.try_insert(0, 1).is_err());
709    }
710
711    #[test]
712    fn truncate() {
713        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
714
715        vec.truncate(2);
716        assert_eq!(vec.as_slice(), [1, 2]);
717        vec.push(0);
718        assert_eq!(vec.as_slice(), [1, 2, 0]);
719        vec.truncate(0);
720        assert_eq!(vec.as_slice(), []);
721        vec.truncate(0xcafebabe);
722        assert!(vec.is_empty());
723    }
724
725    #[test]
726    fn truncate_heap_types() {
727        let mut vec = ArrayVec::from_array([String::from("hey"), String::from("boy")]);
728
729        vec.truncate(1);
730        assert_eq!(vec.as_slice(), [String::from("hey")]);
731        core::mem::drop(vec);
732    }
733
734    #[test]
735    fn truncate_noop() {
736        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
737
738        // Anything >= len is a no-op
739        vec.truncate(4);
740        assert_eq!(vec.len(), 4);
741        vec.truncate(10);
742        assert_eq!(vec.len(), 4);
743    }
744
745    #[test]
746    fn resize_truncate() {
747        let mut vec = ArrayVec::from_array([1, 2, 3, 4]);
748
749        vec.resize(2, 0);
750        assert_eq!(vec.len(), 2);
751    }
752
753    #[test]
754    #[should_panic]
755    fn resize_beyond_capacity() {
756        let mut vec = ArrayVec::<1, _>::from_slice(&[1]).unwrap();
757
758        vec.resize(2, 0);
759    }
760
761    #[test]
762    fn resize_extend_heap_types() {
763        let mut vec = ArrayVec::<1, _>::from_slice(&[]).unwrap();
764
765        vec.resize(1, String::from("girls rule"));
766        assert_eq!(vec.len(), 1);
767        assert_eq!(vec.as_slice(), [String::from("girls rule")]);
768    }
769
770    #[test]
771    fn insert() {
772        const EXPECTED: [u32; 4] = [67, 69, 420, 80085];
773        let vec: ArrayVec<4, u32> = {
774            let mut vec = ArrayVec::<4, _>::from_slice(&[67, 420, 80085]).unwrap();
775            vec.insert(69, 1);
776            vec
777        };
778        assert_eq!(vec.as_slice(), EXPECTED);
779    }
780
781    #[test]
782    #[should_panic]
783    fn insert_full() {
784        let mut vec = ArrayVec::<0, u64>::from_array([]);
785        vec.insert(0xcafebabe, 0);
786    }
787
788    proptest! {
789        #![proptest_config(proptest_config())]
790        #[test]
791        fn resize_extend(
792            initial in prop::collection::vec(0u8..=255, 0..4usize),
793            fill: u8,
794            extra in 0..5usize,
795        ) {
796            let new_len = initial.len() + extra;
797            let mut vec = ArrayVec::<8, u8>::from_slice(&initial).unwrap();
798            vec.resize(new_len, fill);
799
800            assert_eq!(&vec.as_slice()[..initial.len()], initial.as_slice());
801            assert!(vec.as_slice()[initial.len()..].iter().all(|&x| x == fill));
802            assert_eq!(vec.len(), new_len);
803        }
804    }
805
806    #[test]
807    fn ref_vec() {
808        let vec = ArrayVec::from_array([7; 4]);
809        let slice: ArrayVec<4, &i32> = vec.ref_vec();
810        assert!(vec.iter().zip(slice.iter().copied()).all(|(&l, r)| l.eq(r)));
811    }
812
813    #[test]
814    fn mut_vec() {
815        let mut vec = ArrayVec::from_array([7; 4]);
816        let slice: ArrayVec<4, &mut i32> = vec.mut_vec();
817
818        for x in slice {
819            *x = 69; // I'm so horny
820        }
821
822        assert_eq!(&*vec, [69; 4]);
823    }
824
825    #[test]
826    fn debug_noop() {
827        let vec = ArrayVec::from_array([1u8, 2, 3, 4]);
828        eprintln!("{vec:?}");
829    }
830
831    #[test]
832    fn partial_eq() {
833        let a = ArrayVec::from_array([1u8, 2, 3]);
834        let b = ArrayVec::from_array([1u8, 2, 3]);
835        let c = ArrayVec::from_array([1u8, 2, 4]);
836        assert_eq!(a, b);
837        assert_ne!(a, c);
838    }
839
840    #[test]
841    fn ord() {
842        let a = ArrayVec::from_array([1u8, 2, 3]);
843        let b = ArrayVec::from_array([1u8, 2, 4]);
844        assert!(a < b);
845    }
846
847    proptest! {
848        #![proptest_config(proptest_config())]
849        #[test]
850        fn shift_right_semantics(
851            original in prop::collection::vec(0u8..=255, 0..16),
852            item: u8,
853        ) {
854            // Build conceptual [item, original...], then split
855            let mut expected_slice = vec![item];
856            expected_slice.extend_from_slice(&original);
857            expected_slice.truncate(original.len()); // first `len` stay
858            let expected_returned = {
859                let mut full = vec![item];
860                full.extend_from_slice(&original);
861                full[original.len()..].to_vec()        // last 1 is returned
862            };
863
864            let mut buf = original.clone();
865            let returned = slice_shift_right(&mut buf, [item]);
866
867            assert_eq!(buf, expected_slice);
868            assert_eq!(returned, expected_returned.as_slice());
869        }
870    }
871
872    #[derive(Debug, Clone)]
873    enum Op {
874        Push(u8),
875        TryPush(u8),
876        Pop,
877        Insert(u8, usize),
878        TryInsert(u8, usize),
879        Truncate(usize),
880        Resize(usize, u8),
881    }
882
883    fn arbatrary_op() -> impl Strategy<Value = Op> {
884        prop_oneof![
885            any::<u8>().prop_map(Op::Push),
886            any::<u8>().prop_map(Op::TryPush),
887            Just(Op::Pop),
888            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Insert(v, i)),
889            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::TryInsert(v, i)),
890            any::<usize>().prop_map(Op::Truncate),
891            (any::<u8>(), any::<usize>()).prop_map(|(v, i)| Op::Resize(i, v)),
892        ]
893    }
894
895    fn model_try_push(v: &mut Vec<u8>, value: u8) -> Result<(), u8> {
896        if v.len() >= v.capacity() {
897            return Err(value);
898        }
899
900        v.push(value);
901        Ok(())
902    }
903
904    fn model_try_insert(v: &mut Vec<u8>, value: u8, idx: usize) -> Result<(), u8> {
905        if v.len() >= v.capacity() || idx > v.len() {
906            return Err(value);
907        }
908
909        v.insert(idx, value);
910        Ok(())
911    }
912
913    proptest! {
914        #![proptest_config(proptest_config())]
915        #[test]
916        fn model_based(ops in prop::collection::vec(arbatrary_op(), 0..50)) {
917            const C: usize = 8;
918            let mut vec: ArrayVec<C, u8> = ArrayVec::new();
919            let mut model: Vec<u8> = Vec::with_capacity(C);
920
921            for op in ops {
922                match op {
923                    Op::Push(v) => {
924                        if model.len() < C {
925                            vec.push(v);
926                            model.push(v);
927                        }
928                    }
929                    Op::TryPush(x) => {
930                        assert_eq!(vec.try_push(x), model_try_push(&mut model, x));
931                    }
932                    Op::Pop => {
933                        assert_eq!(vec.pop(), model.pop());
934                    }
935                    Op::Insert(v, i) => {
936                        if model.len() < C {
937                            let idx = i % (model.len() + 1);
938                            vec.insert(v, idx);
939                            model.insert(idx, v);
940                        }
941                    }
942                    Op::TryInsert(val, idx) => {
943                        assert_eq!(
944                            vec.try_insert(val, idx),
945                            model_try_insert(&mut model, val, idx)
946                        );
947                    }
948                    Op::Truncate(n) => {
949                        let n = n % (C + 1);
950                        vec.truncate(n);
951                        model.truncate(n);
952                    }
953                    Op::Resize(n, x) => {
954                        let n = n % (C + 1);
955                        vec.resize(n, x);
956                        model.resize(n,x);
957                    }
958                }
959                assert_eq!(vec.as_slice(), model.as_slice());
960                assert!(vec.len() <= C);
961            }
962        }
963    }
964}