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