copy_stack_vec/
vec.rs

1// This file is part of copy-stack-vec.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! The `CopyStackVec` type and its inherent API.
5//!
6//! `CopyStackVec<T, N>` is a fixed-capacity vector specialized for `Copy` types.
7//! It stores elements inline in a fixed-size backing buffer and tracks a logical length.
8//! Methods generally mirror slice/vector semantics, with explicit capacity checks and
9//! fallible variants where appropriate.
10//!
11//! No heap allocations are performed.
12
13#[cfg(not(feature = "unsafe-maybe-uninit"))]
14mod array;
15#[cfg(feature = "unsafe-maybe-uninit")]
16mod maybe_uninit;
17
18// Crate imports
19use crate::{error::Error, iter::IntoIter};
20
21// Core imports
22use core::{
23    borrow::{Borrow, BorrowMut},
24    fmt,
25    hash::{Hash, Hasher},
26    ops::{Deref, DerefMut},
27};
28
29/// A fixed-capacity, stack-allocated vector for `Copy` types.
30///
31/// `CopyStackVec<T, N>` stores its elements inline in a buffer of capacity `N`
32/// and tracks a logical length `len ∈ 0..=N`. Conceptually, it is a slice-like
33/// view into a fixed-capacity backing array:
34///
35/// - capacity is known at compile time (`N`);
36/// - the buffer is stored inline (typically on the stack);
37/// - `T: Copy` is required, and the vector itself is `Copy`;
38/// - many methods mirror `Vec`/slice semantics where they make sense;
39/// - no heap allocations are performed.
40///
41/// This type is intended for **small capacities** (e.g. `N <= 256`) and small
42/// `Copy` element types, used mostly as a local scratch buffer passed by
43/// reference (`&CopyStackVec` / `&mut CopyStackVec`).
44///
45/// # Layout and invariants
46///
47/// Internally, `CopyStackVec<T, N>` maintains:
48///
49/// - a backing buffer of capacity `N` (either `[T; N]` or `[MaybeUninit<T>; N]`,
50///   depending on the backend); and
51/// - a logical length `len` with `0 <= len <= N`.
52///
53/// Only the prefix `buf[..len]` is considered initialized and visible through
54/// safe APIs. Methods such as [`as_slice`], [`as_mut_slice`], indexing, and
55/// iteration are all restricted to this prefix.
56///
57/// # Complexity characteristics
58///
59/// - The type size is roughly `N * size_of::<T>() + O(1)`.
60/// - Moving or copying a `CopyStackVec<T, N>` copies the entire backing buffer,
61///   not just the initialized prefix. This is `O(N)` in the capacity, *not* in
62///   `len`, so you generally want to pass it by reference in hot code.
63/// - In the default backend:
64///   - [`Default::default`] / [`CopyStackVec::new`] initialize all `N` elements
65///     with `T::default()`, which is `O(N)` and requires `T: Default`.
66/// - With the `unsafe-maybe-uninit` backend enabled:
67///   - [`Default::default`] / [`new`] no longer require `T: Default` and avoid
68///     constructing `N` copies of `T`. The backing buffer is
69///     `[MaybeUninit<T>; N]`, which is typically cheap to initialize, but still
70///     conceptually `O(N)` in `N`.
71/// - Most mutating operations (`push`, `pop`, `insert`, `remove`,
72///   `swap_remove`, `retain`, `truncate`, `resize`) are `O(1)` or `O(len)`,
73///   as you would expect from a small Vec-like container.
74///
75/// # Fallible vs truncating operations
76///
77/// Capacity-sensitive operations come in two styles:
78///
79/// - **Fallible** (error on overflow, no changes on error):
80///
81///   - [`push`](CopyStackVec::push)
82///   - [`extend_from_slice`](CopyStackVec::extend_from_slice)
83///   - [`resize`](CopyStackVec::resize)
84///   - [`TryFrom<&[T]>`](TryFrom)
85///   - [`try_from_iter`](CopyStackVec::try_from_iter)
86///   - [`try_extend_from_iter`](CopyStackVec::try_extend_from_iter)
87///   - [`insert`](CopyStackVec::insert)
88///   - [`try_remove`](CopyStackVec::try_remove)
89///   - [`try_swap_remove`](CopyStackVec::try_swap_remove)
90///
91///   These return [`crate::Error::Full`] when the operation would exceed
92///   capacity and leave the vector unchanged.
93///
94/// - **Truncating** (silently drop extra elements):
95///
96///   - [`push_truncated`](CopyStackVec::push_truncated)
97///   - [`extend_from_slice_truncated`](CopyStackVec::extend_from_slice_truncated)
98///   - [`from_slice_truncated`](CopyStackVec::from_slice_truncated)
99///   - [`from_array_truncated`](CopyStackVec::from_array_truncated)
100///   - [`Extend<T>`](core::iter::Extend) and
101///     [`FromIterator<T>`](core::iter::FromIterator):
102///     collecting into `CopyStackVec<T, N>` takes the first `N` elements and
103///     ignores the rest.
104///
105/// Choose the variant that matches your error-handling strategy: fail-fast with
106/// an explicit `Error::Full`, or truncate when you only care about the prefix.
107///
108/// # Element and trait bounds
109///
110/// - `CopyStackVec<T, N>` is only defined for `T: Copy`.
111/// - In the **default backend**, constructors and helpers that create a fresh buffer
112///   (`Default` / `new`, `from_slice_truncated`, `FromIterator<T>`, `try_from_iter`,
113///   and `drain`) additionally require `T: Default`.
114/// - With the `unsafe-maybe-uninit` backend enabled, [`Default`] / [`new`]
115///   only require `T: Copy`.
116/// - The type implements `Copy`, `Clone`, `Deref<Target = [T]>`, `Borrow<[T]>`,
117///   `AsRef<[T]>`, and `AsMut<[T]>`, so it can be used wherever a slice is
118///   expected.
119///
120/// For `T: Copy` but not `Default`, you can still construct an empty vector
121/// with a pre-filled backing buffer using [`CopyStackVec::new_with`]:
122///
123/// # Examples
124///
125/// ```rust
126/// use copy_stack_vec::CopyStackVec;
127///
128/// let mut v: CopyStackVec<u8, 4> = CopyStackVec::default();
129/// v.push(1).unwrap();
130/// v.extend_from_slice(&[2, 3]).unwrap();
131/// assert_eq!(v.as_slice(), &[1, 2, 3]);
132///
133/// #[cfg(feature = "unsafe-maybe-uninit")]
134/// {
135/// use copy_stack_vec::CopyStackVec;
136///
137/// #[derive(Copy, Clone)]
138/// struct NoDefault(u8);
139///
140/// let mut v: CopyStackVec<NoDefault, 4> = CopyStackVec::new_with(NoDefault(0));
141/// assert!(v.is_empty());
142/// v.push(NoDefault(1)).unwrap();
143/// v.push(NoDefault(2)).unwrap();
144/// assert_eq!(v.len(), 2);
145/// }
146/// ```
147///
148/// # Limitations and trade-offs
149///
150/// - Moving or copying a `CopyStackVec` is `O(N)` in the capacity, not in the
151///   current length.
152/// - Elements must be `Copy`; this type is not suitable for non-`Copy` data
153///   that needs drop semantics.
154/// - Capacity is compile-time fixed. If you need dynamic growth, prefer `Vec`
155///   (in `std`) or another growable container.
156/// - In the default backend, some constructors require `T: Default` to be able
157///   to eagerly initialize the backing buffer.
158///
159/// For a higher-level overview and feature discussion, see the crate-level
160/// documentation in [`lib`](crate).
161#[cfg(not(feature = "unsafe-maybe-uninit"))]
162pub struct CopyStackVec<T: Copy, const N: usize> {
163    pub(crate) buf: [T; N],
164    pub(crate) len: usize,
165}
166#[cfg(feature = "unsafe-maybe-uninit")]
167pub struct CopyStackVec<T: Copy, const N: usize> {
168    pub(crate) buf: [core::mem::MaybeUninit<T>; N],
169    pub(crate) len: usize,
170}
171
172impl<T: Copy, const N: usize> CopyStackVec<T, N> {
173    /// The fixed capacity of this vector.
174    pub const CAPACITY: usize = N;
175
176    /// Returns the capacity of this vector (always `N`).
177    #[inline]
178    pub const fn capacity(&self) -> usize {
179        N
180    }
181
182    /// Returns the current logical length (`0..=N`).
183    #[inline]
184    pub const fn len(&self) -> usize {
185        self.len
186    }
187
188    /// Returns `true` if `len == 0`.
189    #[inline]
190    pub const fn is_empty(&self) -> bool {
191        self.len == 0
192    }
193
194    /// Returns `true` if `len == N`.
195    #[inline]
196    pub const fn is_full(&self) -> bool {
197        self.len == N
198    }
199
200    /// Returns `N - len`, the number of additional elements that can be pushed.
201    #[inline]
202    pub const fn spare_capacity(&self) -> usize {
203        N - self.len
204    }
205
206    /// Returns `Some(&T)` if `i < len`, otherwise `None`.
207    #[inline]
208    pub fn get(&self, i: usize) -> Option<&T> {
209        (i < self.len).then(|| &self.as_slice()[i])
210    }
211
212    /// Returns `Some(&mut T)` if `i < len`, otherwise `None`.
213    #[inline]
214    pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
215        (i < self.len).then(|| &mut self.as_mut_slice()[i])
216    }
217
218    // iterators
219    /// Shorthand for `self.as_slice().iter()`.
220    #[inline]
221    pub fn iter(&self) -> core::slice::Iter<'_, T> {
222        self.as_slice().iter()
223    }
224
225    /// Shorthand for `self.as_mut_slice().iter_mut()`.
226    #[inline]
227    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
228        self.as_mut_slice().iter_mut()
229    }
230
231    /// Returns the first element, if any.
232    #[inline]
233    pub fn first(&self) -> Option<&T> {
234        self.as_slice().first()
235    }
236
237    /// Returns the last element, if any.
238    #[inline]
239    pub fn last(&self) -> Option<&T> {
240        self.as_slice().last()
241    }
242
243    /// Returns the first element mutably, if any.
244    #[inline]
245    pub fn first_mut(&mut self) -> Option<&mut T> {
246        self.as_mut_slice().first_mut()
247    }
248
249    /// Returns the last element mutably, if any.
250    #[inline]
251    pub fn last_mut(&mut self) -> Option<&mut T> {
252        self.as_mut_slice().last_mut()
253    }
254}
255
256impl<T: Copy + fmt::Debug, const N: usize> fmt::Debug for CopyStackVec<T, N> {
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        f.debug_struct("CopyStackVec")
259            .field("len", &self.len)
260            .field("elements", &self.as_slice())
261            .finish()
262    }
263}
264
265impl<T: Copy + PartialEq, const N: usize> PartialEq for CopyStackVec<T, N> {
266    fn eq(&self, other: &Self) -> bool {
267        self.as_slice() == other.as_slice()
268    }
269}
270impl<T: Copy + Eq, const N: usize> Eq for CopyStackVec<T, N> {}
271impl<T: Copy + Ord, const N: usize> Ord for CopyStackVec<T, N> {
272    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
273        self.as_slice().cmp(other.as_slice())
274    }
275}
276impl<T: Copy + PartialOrd, const N: usize> PartialOrd for CopyStackVec<T, N> {
277    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
278        self.as_slice().partial_cmp(other.as_slice())
279    }
280}
281impl<T: Copy + Hash, const N: usize> Hash for CopyStackVec<T, N> {
282    fn hash<H: Hasher>(&self, state: &mut H) {
283        self.as_slice().hash(state)
284    }
285}
286
287impl<T: Copy, const N: usize> Copy for CopyStackVec<T, N> {}
288impl<T: Copy, const N: usize> Clone for CopyStackVec<T, N> {
289    fn clone(&self) -> Self {
290        *self
291    }
292}
293
294impl<T: Copy, const N: usize> CopyStackVec<T, N> {
295    /// Sets `len = 0` without altering the underlying values.
296    #[inline]
297    pub fn clear(&mut self) {
298        self.len = 0;
299    }
300
301    /// Overwrites the initialized prefix with `value` and then clears the vector (`len = 0`).
302    #[inline]
303    pub fn clear_to(&mut self, value: T) {
304        for x in self.as_mut_slice() {
305            *x = value;
306        }
307        self.len = 0;
308    }
309
310    /// Shrinks to `new_len` if `new_len < len`; otherwise a no-op.
311    #[inline]
312    pub fn truncate(&mut self, new_len: usize) {
313        if new_len < self.len {
314            self.len = new_len;
315        }
316    }
317
318    /// Resizes to `new_len`, filling with `value` when growing.
319    ///
320    /// Returns [`Error::Full`] if `new_len > N`.
321    #[inline]
322    pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), Error> {
323        if new_len <= self.len {
324            self.len = new_len;
325            return Ok(());
326        }
327        if new_len > N {
328            return Err(Error::Full);
329        }
330        while self.len < new_len {
331            // This cannot fail because we already checked new_len <= N.
332            self.push(value)?;
333        }
334        Ok(())
335    }
336
337    /// Fallible variant of [`remove`], returning [`Error::OutOfBounds`] when `index >= len`.
338    #[inline]
339    pub fn try_remove(&mut self, index: usize) -> Result<T, Error> {
340        self.remove(index).ok_or(Error::OutOfBounds)
341    }
342
343    /// Fallible variant of [`swap_remove`], returning [`Error::OutOfBounds`] when `index >= len`.
344    #[inline]
345    pub fn try_swap_remove(&mut self, index: usize) -> Result<T, Error> {
346        self.swap_remove(index).ok_or(Error::OutOfBounds)
347    }
348
349    /// Returns `true` if the vector contains `x` (linear search on the initialized prefix).
350    #[inline]
351    pub fn contains(&self, x: &T) -> bool
352    where
353        T: PartialEq,
354    {
355        self.as_slice().contains(x)
356    }
357}
358
359impl<T: Copy, const N: usize> Deref for CopyStackVec<T, N> {
360    type Target = [T];
361    fn deref(&self) -> &Self::Target {
362        self.as_slice()
363    }
364}
365impl<T: Copy, const N: usize> DerefMut for CopyStackVec<T, N> {
366    fn deref_mut(&mut self) -> &mut Self::Target {
367        self.as_mut_slice()
368    }
369}
370
371impl<T: Copy, const N: usize> CopyStackVec<T, N> {
372    /// Returns an iterator over the current contents **and clears `self`**.
373    ///
374    /// - Items are yielded in order from front to back.
375    /// - O(N) in the capacity to create (copies the backing buffer);
376    ///   overall O(len) to iterate.
377    /// - After calling, `self.len() == 0`.
378    #[inline]
379    pub fn drain_all(&mut self) -> IntoIter<T, N> {
380        let len = self.len;
381        let v = *self;
382
383        // Logically clear self (we ignore what is left in buf)
384        self.len = 0;
385
386        IntoIter {
387            v,
388            front: 0,
389            back: len,
390        }
391    }
392}
393
394impl<T: Copy, const N: usize> AsRef<[T]> for CopyStackVec<T, N> {
395    fn as_ref(&self) -> &[T] {
396        self.as_slice()
397    }
398}
399impl<T: Copy, const N: usize> AsMut<[T]> for CopyStackVec<T, N> {
400    fn as_mut(&mut self) -> &mut [T] {
401        self.as_mut_slice()
402    }
403}
404
405// Borrow ergonomics (treat as a slice)
406impl<T: Copy, const N: usize> Borrow<[T]> for CopyStackVec<T, N> {
407    fn borrow(&self) -> &[T] {
408        self.as_slice()
409    }
410}
411impl<T: Copy, const N: usize> BorrowMut<[T]> for CopyStackVec<T, N> {
412    fn borrow_mut(&mut self) -> &mut [T] {
413        self.as_mut_slice()
414    }
415}
416
417#[cfg(test)]
418mod tests {
419    // Imports
420    use super::CopyStackVec;
421
422    #[test]
423    fn test_push_pop() {
424        let mut v: CopyStackVec<u8, 2> = CopyStackVec::default();
425        v.push(1).unwrap();
426        v.push(2).unwrap();
427        assert!(v.push(9).is_err());
428        assert_eq!(v.pop(), Some(2));
429        assert_eq!(v.pop(), Some(1));
430        assert_eq!(v.pop(), None);
431    }
432
433    #[test]
434    fn test_default_and_capacity_full_suite() {
435        let v: CopyStackVec<i32, 4> = CopyStackVec::default();
436        assert_eq!(v.len(), 0);
437        assert_eq!(v.capacity(), 4);
438        assert!(v.is_empty());
439        assert_eq!(v.spare_capacity(), 4);
440
441        let v2: CopyStackVec<i32, 4> = CopyStackVec::new();
442        assert_eq!(v2.len(), 0);
443        assert_eq!(CopyStackVec::<i32, 4>::CAPACITY, 4);
444    }
445
446    #[test]
447    fn test_new_with_and_clear_variants() {
448        let mut v: CopyStackVec<u8, 3> = CopyStackVec::new_with(7);
449        assert_eq!(v.len(), 0);
450        v.push(1).unwrap();
451        v.push(2).unwrap();
452        v.push(3).unwrap();
453        assert_eq!(v.as_slice(), &[1, 2, 3]);
454
455        v.clear_to(9);
456        assert_eq!(v.len(), 0);
457        v.push(4).unwrap();
458        assert_eq!(v.as_slice(), &[4]);
459
460        v.clear();
461        assert!(v.is_empty());
462        assert_eq!(v.spare_capacity(), 3);
463    }
464
465    #[test]
466    fn test_push_pop_and_full_error_full_suite() {
467        let mut v: CopyStackVec<i32, 2> = CopyStackVec::default();
468        assert_eq!(v.push(10), Ok(()));
469        assert_eq!(v.push(20), Ok(()));
470        assert_eq!(v.push(30), Err(crate::Error::Full));
471        assert!(v.is_full());
472        assert_eq!(v.pop(), Some(20));
473        assert_eq!(v.pop(), Some(10));
474        assert_eq!(v.pop(), None);
475        assert!(v.is_empty());
476        assert_eq!(v.spare_capacity(), 2);
477    }
478
479    #[test]
480    fn test_push_truncated() {
481        let mut v: CopyStackVec<i32, 2> = CopyStackVec::default();
482        assert!(v.push_truncated(1));
483        assert!(v.push_truncated(2));
484        assert!(!v.push_truncated(3));
485        assert_eq!(v.as_slice(), &[1, 2]);
486    }
487
488    #[test]
489    fn test_extend_from_slice_and_truncated() {
490        let mut v: CopyStackVec<u8, 5> = CopyStackVec::default();
491        assert_eq!(v.extend_from_slice(&[1, 2, 3]), Ok(()));
492        assert_eq!(v.as_slice(), &[1, 2, 3]);
493        assert_eq!(v.extend_from_slice(&[4, 5, 6]), Err(crate::Error::Full));
494        let pushed = v.extend_from_slice_truncated(&[4, 5, 6]);
495        assert_eq!(pushed, 2);
496        assert_eq!(v.as_slice(), &[1, 2, 3, 4, 5]);
497        assert!(v.is_full());
498    }
499
500    #[test]
501    fn test_extend_from_slice_err_is_noop() {
502        let mut v: CopyStackVec<i32, 3> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
503        let before = v.as_slice().to_vec();
504        let res = v.extend_from_slice(&[3, 4]); // needs 2, spare 1 -> Err
505        assert_eq!(res, Err(crate::Error::Full));
506        assert_eq!(v.as_slice(), &before[..]); // unchanged
507    }
508
509    #[test]
510    fn test_truncate_and_resize() {
511        let mut v: CopyStackVec<i32, 5> = CopyStackVec::default();
512        v.extend_from_slice(&[1, 2, 3, 4]).unwrap();
513        v.truncate(2);
514        assert_eq!(v.as_slice(), &[1, 2]);
515        v.resize(5, 9).unwrap();
516        assert_eq!(v.as_slice(), &[1, 2, 9, 9, 9]);
517        v.resize(3, 0).unwrap();
518        assert_eq!(v.as_slice(), &[1, 2, 9]);
519        let mut w: CopyStackVec<i32, 3> = CopyStackVec::default();
520        assert_eq!(w.resize(4, 7), Err(crate::Error::Full));
521    }
522
523    #[test]
524    fn test_retain_is_stable() {
525        let mut v: CopyStackVec<i32, 10> = CopyStackVec::default();
526        v.extend_from_slice(&[1, 2, 3, 4, 5, 6]).unwrap();
527        v.retain(|x| x % 2 == 0);
528        assert_eq!(v.as_slice(), &[2, 4, 6]);
529    }
530
531    #[test]
532    fn test_insert_remove_and_swap_remove() {
533        let mut v: CopyStackVec<i32, 5> = CopyStackVec::default();
534        v.extend_from_slice(&[10, 20, 30]).unwrap();
535        v.insert(1, 15).unwrap();
536        assert_eq!(v.as_slice(), &[10, 15, 20, 30]);
537        v.insert(4, 35).unwrap();
538        assert_eq!(v.as_slice(), &[10, 15, 20, 30, 35]);
539        assert_eq!(v.insert(0, 0), Err(crate::Error::Full));
540
541        let mut w: CopyStackVec<i32, 3> = CopyStackVec::default();
542        w.extend_from_slice(&[1, 2]).unwrap();
543        assert_eq!(w.insert(3, 9), Err(crate::Error::OutOfBounds));
544
545        let mut r: CopyStackVec<i32, 5> = CopyStackVec::from([1, 2, 3, 4, 5]);
546        assert_eq!(r.remove(2), Some(3));
547        assert_eq!(r.as_slice(), &[1, 2, 4, 5]);
548        assert_eq!(r.try_remove(8), Err(crate::Error::OutOfBounds));
549
550        let mut s: CopyStackVec<i32, 5> = CopyStackVec::from([1, 2, 3, 4, 5]);
551        assert_eq!(s.swap_remove(1), Some(2));
552        assert_eq!(s.as_slice(), &[1, 5, 3, 4]);
553        assert_eq!(s.try_swap_remove(10), Err(crate::Error::OutOfBounds));
554    }
555
556    #[test]
557    fn test_insert_err_is_noop() {
558        let mut v: CopyStackVec<i32, 2> = CopyStackVec::try_from(&[10, 20][..]).unwrap();
559        let before = v.as_slice().to_vec();
560        assert_eq!(v.insert(3, 99), Err(crate::Error::OutOfBounds));
561        assert_eq!(v.as_slice(), &before[..]);
562        assert_eq!(v.insert(0, 1), Err(crate::Error::Full));
563        assert_eq!(v.as_slice(), &before[..]);
564    }
565
566    #[test]
567    fn test_contains_and_getters() {
568        let mut v: CopyStackVec<i32, 4> = CopyStackVec::default();
569        v.extend_from_slice(&[7, 8, 9]).unwrap();
570        assert!(v.contains(&7));
571        assert!(!v.contains(&10));
572        assert_eq!(v.first(), Some(&7));
573        assert_eq!(v.last(), Some(&9));
574        assert_eq!(v.get(1), Some(&8));
575        assert_eq!(v.get(3), None);
576        *v.get_mut(1).unwrap() = 80;
577        assert_eq!(v.as_slice(), &[7, 80, 9]);
578        let len = v.len();
579        assert_eq!(v.get(len), None);
580        assert!(v.get_mut(len - 1).is_some());
581    }
582
583    #[test]
584    fn test_deref_and_as_ref() {
585        let mut v: CopyStackVec<i32, 3> = CopyStackVec::default();
586        v.extend_from_slice(&[1, 2]).unwrap();
587        let s: &[i32] = &v;
588        assert_eq!(s, &[1, 2]);
589        let smut: &mut [i32] = &mut v;
590        smut[1] = 22;
591        assert_eq!(v.as_slice(), &[1, 22]);
592        let aref: &[i32] = v.as_ref();
593        assert_eq!(aref, &[1, 22]);
594        let amut: &mut [i32] = v.as_mut();
595        amut[0] = 11;
596        assert_eq!(v.as_slice(), &[11, 22]);
597    }
598
599    #[test]
600    fn test_try_into_array_and_conversions() {
601        let v_full: CopyStackVec<u8, 3> = [7, 8, 9].into();
602        let arr = v_full.try_into_array().unwrap();
603        assert_eq!(arr, [7, 8, 9]);
604
605        let v_not_full: CopyStackVec<u8, 3> = CopyStackVec::from_slice_truncated(&[1, 2]);
606        assert_eq!(v_not_full.try_into_array(), Err(crate::Error::InvalidLen));
607
608        let v2 = <CopyStackVec<u8, 4>>::try_from(&[1, 2, 3][..]).unwrap();
609        assert_eq!(v2.as_slice(), &[1, 2, 3]);
610
611        let v3 = <CopyStackVec<u8, 3>>::try_from_iter([10, 11, 12]).unwrap();
612        assert_eq!(v3.as_slice(), &[10, 11, 12]);
613
614        let err = <CopyStackVec<u8, 2>>::try_from_iter([1, 2, 3]).unwrap_err();
615        assert_eq!(err, crate::Error::Full);
616    }
617
618    #[test]
619    fn test_eq_ord_partial_ord_hash_via_slice() {
620        use core::cmp::Ordering;
621        use core::hash::{Hash, Hasher};
622        use std::collections::hash_map::DefaultHasher;
623
624        let a: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
625        let b: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
626        let c: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 4][..]).unwrap();
627
628        assert_eq!(a, b);
629        assert_ne!(a, c);
630        assert_eq!(a.cmp(&b), Ordering::Equal);
631        assert_eq!(a.partial_cmp(&c), Some(Ordering::Less));
632
633        let mut ha = DefaultHasher::new();
634        a.hash(&mut ha);
635        let mut hb = DefaultHasher::new();
636        [1, 2, 3][..].hash(&mut hb);
637        assert_eq!(ha.finish(), hb.finish());
638    }
639
640    #[test]
641    fn test_debug_structure_and_error_display() {
642        use alloc::format;
643        let v: CopyStackVec<i32, 5> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
644        let dbg = format!("{v:?}");
645        assert!(dbg.contains("CopyStackVec"));
646        assert!(dbg.contains("len"));
647        assert!(dbg.contains("elements"));
648        assert!(dbg.contains("[1, 2]"));
649        assert_eq!(crate::Error::Full.to_string(), "capacity exceeded");
650        assert_eq!(crate::Error::OutOfBounds.to_string(), "index out of bounds");
651        assert_eq!(crate::Error::InvalidLen.to_string(), "invalid length");
652    }
653
654    #[test]
655    fn test_as_ptr_and_as_mut_ptr() {
656        let mut v: CopyStackVec<u16, 4> = CopyStackVec::try_from(&[10, 20][..]).unwrap();
657        // Compare raw pointers against slice pointers (safe).
658        let p_const = v.as_ptr();
659        let p_slice = v.as_slice().as_ptr();
660        assert_eq!(p_const, p_slice);
661
662        // For mut ptr, compare addresses and also mutate via safe APIs to ensure view is live.
663        let p_mut = v.as_mut_ptr();
664        let p_mut_slice = v.as_mut_slice().as_mut_ptr();
665        assert_eq!(p_mut, p_mut_slice);
666
667        // Mutate safely through the slice and verify contents.
668        {
669            let s = v.as_mut_slice();
670            s[1] = 21;
671        }
672        assert_eq!(v.as_slice(), &[10, 21]);
673    }
674
675    #[test]
676    fn zero_capacity_vec_behaves() {
677        let mut v: CopyStackVec<u8, 0> = CopyStackVec::default();
678        assert_eq!(v.capacity(), 0);
679        assert!(v.is_empty());
680        assert!(v.is_full());
681
682        assert_eq!(v.push(1), Err(crate::Error::Full));
683        assert_eq!(v.extend_from_slice(&[1, 2]), Err(crate::Error::Full));
684        assert_eq!(v.extend_from_slice_truncated(&[1, 2, 3]), 0);
685
686        assert_eq!(v.resize(0, 9), Ok(()));
687        assert_eq!(v.resize(1, 9), Err(crate::Error::Full));
688        assert_eq!(v.pop(), None);
689
690        // try_into_array must succeed for N=0 when len==0
691        let arr = v.try_into_array().unwrap();
692        assert_eq!(arr.len(), 0);
693    }
694
695    #[test]
696    fn test_zero_sized_type_supports_capacity() {
697        // ZST like () should work; capacity N, len arithmetic should still be correct.
698        let mut v: CopyStackVec<(), 4> = CopyStackVec::default();
699        assert_eq!(v.len(), 0);
700        v.push(()).unwrap();
701        v.push(()).unwrap();
702        assert_eq!(v.len(), 2);
703        v.truncate(1);
704        assert_eq!(v.len(), 1);
705        v.resize(4, ()).unwrap();
706        assert!(v.is_full());
707        assert_eq!(v.try_into_array().unwrap().len(), 4);
708    }
709
710    #[test]
711    fn test_insert_at_bounds_and_shift_correctly() {
712        let mut v: CopyStackVec<i32, 4> = CopyStackVec::default();
713        v.insert(0, 1).unwrap(); // insert at front into empty
714        v.insert(1, 3).unwrap(); // tail
715        v.insert(1, 2).unwrap(); // middle, shifts right
716        assert_eq!(v.as_slice(), &[1, 2, 3]);
717        v.insert(3, 4).unwrap(); // exactly at len
718        assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
719        assert_eq!(v.insert(0, 9), Err(crate::Error::Full)); // full
720    }
721
722    #[test]
723    fn test_swap_remove_last_index_is_o1() {
724        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[10, 20, 30][..]).unwrap();
725        assert_eq!(v.swap_remove(2), Some(30)); // removing last should not do a swap
726        assert_eq!(v.as_slice(), &[10, 20]);
727    }
728
729    #[test]
730    fn test_retain_all_and_retain_none() {
731        let mut v: CopyStackVec<i32, 5> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
732        v.retain(|_| true);
733        assert_eq!(v.as_slice(), &[1, 2, 3]);
734        v.retain(|_| false);
735        assert!(v.is_empty());
736    }
737
738    #[test]
739    fn test_resize_to_same_len_is_noop() {
740        let mut v: CopyStackVec<i32, 3> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
741        assert!(v.is_full());
742        v.resize(3, 9).unwrap(); // no-op
743        assert_eq!(v.as_slice(), &[1, 2, 3]);
744    }
745
746    #[test]
747    fn test_resize_err_is_noop() {
748        let mut v: CopyStackVec<i32, 2> = CopyStackVec::try_from(&[1][..]).unwrap();
749        let before = v.as_slice().to_vec();
750        assert_eq!(v.resize(3, 9), Err(crate::Error::Full));
751        assert_eq!(v.as_slice(), &before[..]);
752    }
753
754    #[test]
755    fn test_from_slice_truncated_really_truncates() {
756        let v: CopyStackVec<i32, 3> = CopyStackVec::from_slice_truncated(&[5, 6, 7, 8, 9]);
757        assert_eq!(v.as_slice(), &[5, 6, 7]);
758        assert!(v.is_full());
759    }
760
761    #[test]
762    fn test_extend_and_resize_with_empty_input_are_no_ops() {
763        let mut v: CopyStackVec<i32, 3> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
764        assert_eq!(v.extend_from_slice(&[]), Ok(()));
765        assert_eq!(v.as_slice(), &[1, 2]);
766        let before = v.len();
767        v.truncate(before); // no-op truncate path
768        assert_eq!(v.len(), before);
769    }
770
771    #[test]
772    fn test_try_from_iter_over_capacity_errors() {
773        let res = <CopyStackVec<i32, 3>>::try_from_iter([1, 2, 3, 4]);
774        assert_eq!(res.unwrap_err(), crate::Error::Full);
775    }
776
777    #[test]
778    fn test_extend_trait_truncates() {
779        let mut v: CopyStackVec<i32, 3> = CopyStackVec::default();
780        v.extend([1, 2, 3, 4, 5]);
781        assert_eq!(v.as_slice(), &[1, 2, 3]);
782        assert!(v.is_full());
783    }
784
785    #[test]
786    fn test_extend_preserves_prefix_and_truncates_tail() {
787        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
788        v.extend([3, 4, 5]);
789        assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
790    }
791
792    #[test]
793    fn test_extend_does_not_overconsume() {
794        struct ExtendTestIter {
795            remaining: usize,
796            next_calls: usize,
797        }
798
799        impl Iterator for ExtendTestIter {
800            type Item = u8;
801            fn next(&mut self) -> Option<u8> {
802                if self.remaining == 0 {
803                    return None;
804                }
805                self.remaining -= 1;
806                self.next_calls += 1;
807                Some(1)
808            }
809        }
810        let mut it = ExtendTestIter {
811            remaining: 10,
812            next_calls: 0,
813        };
814        let mut vec: CopyStackVec<u8, 4> = CopyStackVec::default();
815
816        // Note: &mut it implements IntoIterator via &mut MyIter → Iterator
817        vec.extend(&mut it);
818
819        assert_eq!(vec.len(), 4);
820        assert_eq!(it.next_calls, 4); // must not be 5
821    }
822
823    #[test]
824    fn test_drain_all_yields_all_and_clears() {
825        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[10, 20, 30][..]).unwrap();
826        let drained: alloc::vec::Vec<_> = v.drain_all().collect();
827        assert_eq!(drained, [10, 20, 30]);
828        assert!(v.is_empty());
829    }
830
831    #[test]
832    fn test_remove_and_swap_remove_oob_return_none() {
833        let mut v: CopyStackVec<i32, 2> = CopyStackVec::from_slice_truncated(&[1, 2]);
834        assert_eq!(v.remove(5), None);
835        assert_eq!(v.swap_remove(5), None);
836    }
837
838    #[test]
839    fn test_must_use_push_truncated() {
840        let mut v: CopyStackVec<i32, 1> = Default::default();
841        let _ = v.push_truncated(1);
842        // compile-fail tests would be ideal, but at least we can assert behavior
843        assert!(!v.push_truncated(2)); // returns false
844    }
845
846    #[test]
847    fn test_retain_keeps_edges() {
848        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4][..]).unwrap();
849        v.retain(|x| *x == 1 || *x == 4);
850        assert_eq!(v.as_slice(), &[1, 4]);
851    }
852
853    #[test]
854    fn test_remove_first_and_last() {
855        let mut v: CopyStackVec<i32, 5> = [1, 2, 3, 4, 5].into();
856        assert_eq!(v.remove(0), Some(1));
857        assert_eq!(v.remove(v.len() - 1), Some(5));
858        assert_eq!(v.as_slice(), &[2, 3, 4]);
859    }
860
861    #[test]
862    fn test_swap_remove_first_and_last() {
863        let mut v: CopyStackVec<i32, 4> = [10, 20, 30, 40].into();
864
865        assert_eq!(v.swap_remove(0), Some(10));
866        assert!(v.contains(&20) && v.contains(&30) && v.contains(&40));
867
868        let last = v.len() - 1;
869        let expected = v.as_slice()[last]; // capture before mutation
870        assert_eq!(v.swap_remove(last), Some(expected));
871
872        // (optional) sanity: now only two remain, and neither is the removed `expected`
873        assert_eq!(v.len(), 2);
874        assert!(!v.contains(&expected));
875    }
876
877    #[test]
878    fn test_drain_all_then_reuse() {
879        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
880        let collected: alloc::vec::Vec<_> = v.drain_all().collect();
881        assert_eq!(collected, [1, 2, 3]);
882        assert!(v.is_empty());
883        v.extend_from_slice(&[9, 9]).unwrap();
884        assert_eq!(v.as_slice(), &[9, 9]);
885    }
886
887    #[test]
888    fn test_from_iterator_truncates_at_capacity() {
889        let v: CopyStackVec<u8, 3> = [10, 20, 30, 40, 50].into_iter().collect();
890        // Should take only the first 3 items
891        assert_eq!(v.as_slice(), &[10, 20, 30]);
892        assert!(v.is_full());
893    }
894
895    #[test]
896    fn test_from_iterator_zero_capacity() {
897        let v: CopyStackVec<u8, 0> = [1, 2, 3].into_iter().collect();
898        assert_eq!(v.len(), 0);
899        assert!(v.is_full());
900    }
901
902    #[test]
903    fn test_from_iterator_zst() {
904        let v: CopyStackVec<(), 2> = core::iter::repeat_n((), 5).collect();
905        // capacity 2, but all elements are ()
906        assert_eq!(v.len(), 2);
907        let slice = v.as_slice();
908        assert_eq!(slice.len(), 2);
909    }
910
911    #[test]
912    fn test_from_array_ref_fills_full_capacity() {
913        let arr = [1, 2, 3];
914        let v: CopyStackVec<i32, 3> = (&arr).into();
915        assert_eq!(v.len(), 3);
916        assert_eq!(v.as_slice(), &[1, 2, 3]);
917        assert!(v.is_full());
918    }
919
920    #[test]
921    fn test_drain_middle_range() {
922        // Build from slice; works in both backends.
923        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
924
925        let drained: CopyStackVec<i32, 8> = v.drain(1..4).collect();
926        assert_eq!(drained.as_slice(), &[2, 3, 4]);
927        assert_eq!(v.as_slice(), &[1, 5]);
928        assert_eq!(v.len(), 2);
929    }
930
931    #[test]
932    fn test_drain_full_range() {
933        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[10, 20, 30, 40][..]).unwrap();
934
935        let drained: CopyStackVec<i32, 4> = v.drain(..).collect();
936        assert_eq!(drained.as_slice(), &[10, 20, 30, 40]);
937        assert!(v.is_empty());
938        assert_eq!(v.len(), 0);
939    }
940
941    #[test]
942    fn test_drain_empty_range_is_noop_on_data() {
943        let mut v: CopyStackVec<i32, 5> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
944        let before = v.as_slice().to_vec();
945        let len_before = v.len();
946
947        let drained: CopyStackVec<i32, 5> = v.drain(2..2).collect();
948        assert!(drained.is_empty());
949        assert_eq!(v.as_slice(), &before[..]);
950        assert_eq!(v.len(), len_before);
951    }
952
953    #[test]
954    fn test_drain_prefix_and_suffix() {
955        let mut v: CopyStackVec<i32, 6> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
956
957        // Drain prefix [1, 2]
958        let drained_prefix: CopyStackVec<i32, 6> = v.drain(..2).collect();
959        assert_eq!(drained_prefix.as_slice(), &[1, 2]);
960        assert_eq!(v.as_slice(), &[3, 4, 5]);
961
962        // Drain suffix [4, 5] from the updated vec
963        let drained_suffix: CopyStackVec<i32, 6> = v.drain(1..).collect();
964        assert_eq!(drained_suffix.as_slice(), &[4, 5]);
965        assert_eq!(v.as_slice(), &[3]);
966    }
967
968    #[test]
969    fn test_drain_double_ended_iteration() {
970        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
971        {
972            let mut it = v.drain(1..4); // should drain [2,3,4]
973
974            // Use both ends of the iterator.
975            assert_eq!(it.next_back(), Some(4));
976            assert_eq!(it.next(), Some(2));
977            assert_eq!(it.next(), Some(3));
978            assert_eq!(it.next_back(), None);
979        }
980        // Remaining vector should be [1,5].
981        assert_eq!(v.as_slice(), &[1, 5]);
982    }
983
984    #[test]
985    fn test_drain_size_hint_tracks_consumption() {
986        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
987
988        {
989            let mut it = v.drain(1..4); // draining 3 elements
990
991            assert_eq!(it.size_hint(), (3, Some(3)));
992            assert_eq!(it.next(), Some(2));
993            assert_eq!(it.size_hint(), (2, Some(2)));
994            assert_eq!(it.next_back(), Some(4));
995            assert_eq!(it.size_hint(), (1, Some(1)));
996            assert_eq!(it.next(), Some(3));
997            assert_eq!(it.size_hint(), (0, Some(0)));
998            assert_eq!(it.next(), None);
999        }
1000        // Remaining elements in vec: [1,5]
1001        assert_eq!(v.as_slice(), &[1, 5]);
1002    }
1003
1004    #[test]
1005    #[should_panic]
1006    fn test_drain_end_out_of_bounds_panics() {
1007        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3, 4][..]).unwrap();
1008        // end > len should panic
1009        let _ = v.drain(2..10);
1010    }
1011
1012    #[test]
1013    #[should_panic]
1014    #[allow(clippy::reversed_empty_ranges)]
1015    fn test_drain_start_greater_than_end_panics() {
1016        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3, 4][..]).unwrap();
1017        // inverted range should panic
1018        let _ = v.drain(3..1);
1019    }
1020
1021    #[test]
1022    fn test_drain_zero_capacity_vec() {
1023        let mut v: CopyStackVec<u8, 0> = CopyStackVec::default();
1024        assert_eq!(v.len(), 0);
1025        assert!(v.is_full());
1026
1027        {
1028            let mut it = v.drain(..);
1029            assert_eq!(it.size_hint(), (0, Some(0)));
1030            assert_eq!(it.next(), None);
1031        }
1032
1033        // Still zero-length and zero-capacity.
1034        assert_eq!(v.len(), 0);
1035        assert!(v.is_full());
1036    }
1037
1038    #[test]
1039    fn test_drain_zst() {
1040        let mut v: CopyStackVec<(), 4> = CopyStackVec::from([(), (), (), ()]);
1041
1042        let drained: CopyStackVec<(), 4> = v.drain(1..3).collect();
1043        assert_eq!(drained.len(), 2);
1044
1045        // Remaining 2 elements: positions [0] and [3] collapsed to [0] and [1]
1046        assert_eq!(v.len(), 2);
1047    }
1048
1049    #[test]
1050    fn test_first_and_last_mut() {
1051        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
1052
1053        // Mutate first via first_mut
1054        if let Some(first) = v.first_mut() {
1055            *first = 10;
1056        }
1057        // Mutate last via last_mut
1058        if let Some(last) = v.last_mut() {
1059            *last = 30;
1060        }
1061
1062        assert_eq!(v.as_slice(), &[10, 2, 30]);
1063
1064        // Empty vector: both should be None
1065        let mut empty: CopyStackVec<i32, 4> = CopyStackVec::default();
1066        assert!(empty.first_mut().is_none());
1067        assert!(empty.last_mut().is_none());
1068    }
1069
1070    #[test]
1071    fn test_iter_and_iter_mut() {
1072        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3, 4][..]).unwrap();
1073
1074        // iter() should yield all elements by shared reference in order
1075        let collected: alloc::vec::Vec<_> = v.iter().copied().collect();
1076        assert_eq!(collected, alloc::vec![1, 2, 3, 4]);
1077
1078        // iter_mut() should allow in-place mutation
1079        for x in v.iter_mut() {
1080            *x *= 2;
1081        }
1082        assert_eq!(v.as_slice(), &[2, 4, 6, 8]);
1083
1084        // After iter_mut, length and contents are still consistent
1085        assert_eq!(v.len(), 4);
1086    }
1087
1088    #[test]
1089    fn test_borrow_and_borrow_mut_behave_like_slice() {
1090        use core::borrow::{Borrow, BorrowMut};
1091
1092        let mut v: CopyStackVec<i32, 3> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
1093
1094        // Borrow<[T]> should give us the same view as as_slice()
1095        let b: &[i32] = Borrow::<[i32]>::borrow(&v);
1096        assert_eq!(b, &[1, 2, 3]);
1097        assert_eq!(b, v.as_slice());
1098
1099        // BorrowMut<[T]> should give a mutable slice into the same data
1100        {
1101            let bm: &mut [i32] = BorrowMut::<[i32]>::borrow_mut(&mut v);
1102            bm[1] = 20;
1103        }
1104
1105        // Mutations through BorrowMut are visible on the vector
1106        assert_eq!(v.as_slice(), &[1, 20, 3]);
1107    }
1108
1109    #[test]
1110    fn test_into_iter_shared_ref() {
1111        let v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
1112
1113        let mut collected = alloc::vec::Vec::new();
1114        for x in &v {
1115            // uses IntoIterator for &CopyStackVec
1116            collected.push(*x);
1117        }
1118
1119        assert_eq!(collected, alloc::vec![1, 2, 3]);
1120
1121        // original must remain unchanged
1122        assert_eq!(v.as_slice(), &[1, 2, 3]);
1123    }
1124
1125    #[test]
1126    fn test_into_iter_mutable_ref() {
1127        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
1128
1129        for x in &mut v {
1130            // uses IntoIterator for &mut CopyStackVec
1131            *x *= 10;
1132        }
1133
1134        assert_eq!(v.as_slice(), &[10, 20, 30]);
1135    }
1136
1137    #[test]
1138    fn test_into_iter_refs_empty() {
1139        let mut v: CopyStackVec<i32, 4> = CopyStackVec::default();
1140
1141        assert_eq!((&v).into_iter().count(), 0);
1142        assert_eq!((&mut v).into_iter().count(), 0);
1143    }
1144
1145    #[test]
1146    #[allow(clippy::clone_on_copy)]
1147    fn test_clone_copies_len_and_elements() {
1148        let mut v: CopyStackVec<i32, 4> = CopyStackVec::default();
1149        v.extend_from_slice(&[1, 2, 3]).unwrap();
1150
1151        let c = v.clone();
1152
1153        // Clone should have same length and contents
1154        assert_eq!(c.len(), v.len());
1155        assert_eq!(c.as_slice(), v.as_slice());
1156    }
1157
1158    #[test]
1159    #[allow(clippy::clone_on_copy)]
1160    fn test_clone_is_independent_copy() {
1161        let mut v: CopyStackVec<i32, 4> = CopyStackVec::default();
1162        v.extend_from_slice(&[1, 2, 3]).unwrap();
1163
1164        let mut c = v.clone();
1165
1166        // Mutate original
1167        v[1] = 20;
1168        // Mutate clone
1169        c[2] = 30;
1170
1171        // Changes must not leak across copies
1172        assert_eq!(v.as_slice(), &[1, 20, 3]);
1173        assert_eq!(c.as_slice(), &[1, 2, 30]);
1174    }
1175
1176    #[test]
1177    #[allow(clippy::clone_on_copy)]
1178    fn test_clone_zero_capacity_vec() {
1179        let v: CopyStackVec<u8, 0> = CopyStackVec::default();
1180        let c = v.clone();
1181
1182        assert_eq!(v.len(), 0);
1183        assert_eq!(c.len(), 0);
1184        assert!(v.is_full());
1185        assert!(c.is_full());
1186    }
1187
1188    #[test]
1189    fn test_drain_inclusive_end_uses_bound_included_branch() {
1190        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
1191
1192        // ..=2 corresponds to end Bound::Included(2) → end = 2 + 1 = 3
1193        let drained: CopyStackVec<i32, 8> = v.drain(..=2).collect();
1194
1195        // Drained indices [0, 1, 2] → [1, 2, 3]
1196        assert_eq!(drained.as_slice(), &[1, 2, 3]);
1197        // Remaining should be [4, 5]
1198        assert_eq!(v.as_slice(), &[4, 5]);
1199    }
1200
1201    #[test]
1202    fn test_drain_excluded_start_uses_bound_excluded_branch() {
1203        use core::ops::{Bound, RangeBounds};
1204        struct ExcludedStartRange {
1205            start: usize,
1206            end: usize,
1207        }
1208
1209        impl RangeBounds<usize> for ExcludedStartRange {
1210            fn start_bound(&self) -> Bound<&usize> {
1211                // This hits: Bound::Excluded(&i) => i + 1
1212                Bound::Excluded(&self.start)
1213            }
1214
1215            fn end_bound(&self) -> Bound<&usize> {
1216                // Use Included here so we also exercise the included-end path in one go.
1217                Bound::Included(&self.end)
1218            }
1219        }
1220
1221        // Indexes: 0  1  2  3  4
1222        // Values:  10 20 30 40 50
1223        let mut v: CopyStackVec<i32, 8> =
1224            CopyStackVec::try_from(&[10, 20, 30, 40, 50][..]).unwrap();
1225
1226        // start = Excluded(1) → start = 1 + 1 = 2
1227        // end   = Included(3) → end   = 3 + 1 = 4
1228        // So we drain indices [2, 3] => [30, 40].
1229        let drained: CopyStackVec<i32, 8> =
1230            v.drain(ExcludedStartRange { start: 1, end: 3 }).collect();
1231
1232        assert_eq!(drained.as_slice(), &[30, 40]);
1233        // Remaining elements should be [10, 20, 50]
1234        assert_eq!(v.as_slice(), &[10, 20, 50]);
1235    }
1236
1237    #[test]
1238    fn test_drain_nth_and_nth_back() {
1239        // Original: [1, 2, 3, 4, 5]
1240        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[1, 2, 3, 4, 5][..]).unwrap();
1241
1242        {
1243            // Drain the middle three: [2, 3, 4]
1244            let mut it = v.drain(1..4);
1245
1246            // Drain iterator contents: [2, 3, 4]
1247            // nth(1) should skip 2 and yield 3
1248            assert_eq!(it.nth(1), Some(3));
1249
1250            // Now only [4] remains in the drain iterator
1251            // nth_back(0) should yield 4
1252            assert_eq!(it.nth_back(0), Some(4));
1253
1254            // Fully consumed
1255            assert_eq!(it.next(), None);
1256        }
1257
1258        // Parent vector should now contain [1, 5]
1259        assert_eq!(v.as_slice(), &[1, 5]);
1260    }
1261
1262    #[test]
1263    fn test_drain_nth_and_nth_back_overflow() {
1264        let mut v: CopyStackVec<i32, 8> = CopyStackVec::try_from(&[10, 20, 30, 40][..]).unwrap();
1265
1266        {
1267            // Drain all 4 elements
1268            let mut it = v.drain(..);
1269
1270            // Remaining = 4; nth(4) should return None and fully exhaust
1271            assert_eq!(it.nth(4), None);
1272            assert_eq!(it.next(), None);
1273        }
1274
1275        {
1276            // Another drain on the now-empty vec still works and is empty
1277            let mut it2 = v.drain(..);
1278            assert_eq!(it2.nth_back(0), None);
1279            assert_eq!(it2.next_back(), None);
1280        }
1281
1282        // Parent vec should be empty after draining everything
1283        assert!(v.is_empty());
1284        assert_eq!(v.len(), 0);
1285    }
1286
1287    #[test]
1288    fn test_try_extend_from_iter_all_or_nothing() {
1289        // Success: everything fits
1290        let mut v: CopyStackVec<i32, 5> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
1291        v.try_extend_from_iter([3, 4]).unwrap();
1292        assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
1293
1294        // Error: iterator yields more than spare_capacity()
1295        let mut w: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[10, 20][..]).unwrap();
1296        let before = w.as_slice().to_vec();
1297
1298        let err = w.try_extend_from_iter([30, 40, 50]).unwrap_err();
1299        assert_eq!(err, crate::Error::Full);
1300
1301        // Vector unchanged on error
1302        assert_eq!(w.as_slice(), &before[..]);
1303    }
1304
1305    #[test]
1306    fn test_try_extend_from_iter_zero_spare_capacity() {
1307        let mut v: CopyStackVec<i32, 2> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
1308        assert!(v.is_full());
1309
1310        // Any element at all should cause Error::Full
1311        let err = v.try_extend_from_iter([3]).unwrap_err();
1312        assert_eq!(err, crate::Error::Full);
1313
1314        // Empty iterator is fine and leaves vector unchanged
1315        v.try_extend_from_iter(core::iter::empty()).unwrap();
1316        assert_eq!(v.as_slice(), &[1, 2]);
1317    }
1318
1319    #[test]
1320    fn test_split_off_basic() {
1321        let mut v: CopyStackVec<i32, 5> = CopyStackVec::try_from(&[10, 20, 30, 40][..]).unwrap();
1322        let tail = v.split_off(2).unwrap();
1323
1324        assert_eq!(v.as_slice(), &[10, 20]);
1325        assert_eq!(tail.as_slice(), &[30, 40]);
1326    }
1327
1328    #[test]
1329    fn test_split_off_at_len_and_empty() {
1330        // Split at len → empty tail
1331        let mut v: CopyStackVec<i32, 4> = CopyStackVec::try_from(&[1, 2, 3][..]).unwrap();
1332        let tail = v.split_off(v.len()).unwrap();
1333        assert_eq!(v.as_slice(), &[1, 2, 3]);
1334        assert!(tail.is_empty());
1335
1336        // Split an empty vec → both sides empty
1337        let mut empty: CopyStackVec<i32, 4> = CopyStackVec::default();
1338        let tail2 = empty.split_off(0).unwrap();
1339        assert!(empty.is_empty());
1340        assert!(tail2.is_empty());
1341    }
1342
1343    #[test]
1344    fn test_split_off_out_of_bounds_errors_and_is_noop() {
1345        let mut v: CopyStackVec<i32, 3> = CopyStackVec::try_from(&[1, 2][..]).unwrap();
1346        let before = v.as_slice().to_vec();
1347
1348        let err = v.split_off(3).unwrap_err();
1349        assert_eq!(err, crate::Error::OutOfBounds);
1350
1351        // Vector unchanged on error
1352        assert_eq!(v.as_slice(), &before[..]);
1353    }
1354
1355    #[test]
1356    fn test_from_array_truncated() {
1357        // M > N: should truncate
1358        let arr = [1, 2, 3, 4];
1359        let v: CopyStackVec<i32, 2> = CopyStackVec::from_array_truncated(&arr);
1360        assert_eq!(v.as_slice(), &[1, 2]);
1361        assert!(v.is_full());
1362
1363        // M == N: should take all
1364        let arr2 = [10, 20, 30];
1365        let v2: CopyStackVec<i32, 3> = CopyStackVec::from_array_truncated(&arr2);
1366        assert_eq!(v2.as_slice(), &[10, 20, 30]);
1367        assert!(v2.is_full());
1368
1369        // M < N: should just fill len = M
1370        let arr3 = [7, 8];
1371        let v3: CopyStackVec<i32, 4> = CopyStackVec::from_array_truncated(&arr3);
1372        assert_eq!(v3.as_slice(), &[7, 8]);
1373        assert_eq!(v3.len(), 2);
1374        assert!(!v3.is_full());
1375    }
1376}