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