//! A vector-like array.
use crate::{
len::{LengthType, Usize},
mem::{SpareMemoryPolicy, Uninitialized},
};
use core::{
marker::PhantomData,
mem,
ops::{Bound, RangeBounds},
ptr,
result::Result,
slice,
};
mod drain;
pub use drain::*;
pub mod errors;
use errors::*;
mod retain;
use retain::*;
/// A continuous non-growable array with vector-like API.
///
/// Written as `ArrayVec<T, C, L, SM>`, array vector has the capacity to store `C` elements of type
/// `T`.
///
/// It uses type `L` as [`length type`], and `SM` as [`spare memory policy`].
///
/// `ArrayVec` stores elements inline in the struct itself, and doesn't allocate memory on the heap.
///
/// The size of `ArrayVec` struct is not constant, as it depends on the requested capacity and
/// size of `T` (like a standard array).
///
/// `ArrayVec` may be created empty, with no elements.
/// However, once created, contrary to `Vec` which allocates memory only when elements are pushed,
/// `ArrayVec` occupies all the memory needed for the requested capacity.
///
/// The capacity of `ArrayVec` cannot be dynamically changed.
///
/// [`spare memory policy`]: SpareMemoryPolicy
/// [`length type`]: LengthType
///
///
/// # Examples
///
/// ```rust
/// # use cds::{arrayvec::ArrayVec, array_vec, len::U8};
/// let mut v = ArrayVec::<u64, 12, U8>::new();
/// assert_eq!(v.len(), 0);
/// assert_eq!(v.capacity(), 12);
/// assert_eq!(v.spare_capacity(), 12);
/// assert_eq!(v, []);
///
/// v.push(1);
/// v.push(2);
///
/// assert_eq!(v.len(), 2);
/// assert_eq!(v.capacity(), 12);
/// assert_eq!(v.spare_capacity(), 10);
/// assert_eq!(v, [1, 2]);
///
/// v[0] = 7;
/// assert_eq!(v, [7, 2]);
/// ```
///
/// The [`array_vec!`] macro is provided for convenient initialization:
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![12; u64; 1, 2, 3];
/// assert_eq!(v, [1, 2, 3]);
///
/// v.push(7);
/// assert_eq!(v, [1, 2, 3, 7]);
/// ```
///
/// [`push`] panics if there is no spare capacity:
///
/// ```should_panic
/// # use cds::array_vec;
/// let mut v = array_vec![3; 6, 7, 8];
/// assert_eq!(v.has_spare_capacity(), false);
/// v.push(9); // <-- this panics as there is no spare capacity
/// ```
///
/// Avoid a panic with [`try_push`] method, which returns [`InsufficientCapacityError`] instead:
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityError};
/// let mut v = array_vec![3; 6, 7, 8];
/// assert!(matches!(v.try_push(9), Err(e) if e == InsufficientCapacityError));
/// ```
///
/// An `ArrayVec` can be created from an iterator:
///
/// ```rust
/// # use cds::{arrayvec::ArrayVec, len::U8};
/// type A = ArrayVec<u64, 5, U8>;
/// let vec = vec![1, 2, 3, 4, 5];
/// let a = vec.iter()
/// .map(|x| x * x)
/// .filter(|x| x % 2 == 0)
/// .collect::<A>();
/// assert_eq!(a, [4, 16]);
/// ```
///
/// If the iterator yields more than [`CAPACITY`] elements, the method panics:
///
/// ```should_panic
/// # use cds::{arrayvec::ArrayVec, len::U64, mem::Uninitialized};
/// type A = ArrayVec<u64, 3, U64, Uninitialized>; // <-- the capacity is 3
/// let vec = vec![1, 2, 3, 4, 5];
/// let a = vec.iter() // <-- but the iterator yields 5 elements
/// .map(|x| x * x)
/// .collect::<A>(); // <-- this panics
/// ```
///
/// Avoid a panic with [`try_from_iter`] method, which returns [`InsufficientCapacityError`]
/// instead:
///
/// ```rust
/// # use cds::{arrayvec::{ArrayVec, errors::InsufficientCapacityError}, len::U64};
/// type A = ArrayVec<u64, 3, U64>;
/// let vec = vec![1, 2, 3, 4, 5];
/// let iter = vec.iter().map(|x| x * x);
/// assert!(matches!(A::try_from_iter(iter), Err(e) if e == InsufficientCapacityError));
/// ```
///
/// [`array_vec!`]: crate::array_vec
/// [`CAPACITY`]: ArrayVec::CAPACITY
/// [`try_from_iter`]: ArrayVec::try_from_iter
/// [`try_push`]: ArrayVec::try_push
/// [`push`]: ArrayVec::push
pub struct ArrayVec<T, const C: usize, L = Usize, SM = Uninitialized>
where
L: LengthType,
SM: SpareMemoryPolicy<T>,
{
arr: [mem::MaybeUninit<T>; C],
len: L,
phantom1: PhantomData<SM>,
}
impl<T, L, SM, const C: usize> ArrayVec<T, C, L, SM>
where
L: LengthType,
SM: SpareMemoryPolicy<T>,
{
/// The capacity of the array-vector as associated constant.
///
/// The capacity can also be obtained via the [`capacity`] method.
///
/// # Examples
/// ```rust
/// # use cds::{arrayvec::ArrayVec, len::U8, mem::Uninitialized};
/// type A = ArrayVec<u64, 8, U8, Uninitialized>;
/// let v = A::new();
/// assert_eq!(A::CAPACITY, 8);
/// assert_eq!(v.capacity(), A::CAPACITY);
/// ```
///
/// [`capacity`]: ArrayVec::capacity
pub const CAPACITY: usize = C;
/// Creates an empty `ArrayVec`.
///
/// # Safety
///
/// This method panics if requested capacity `C` exceeds the maximal value that can be stored in
/// length type `L`.
///
/// # Examples
///
/// ```rust
/// # use cds::{arrayvec::ArrayVec, len::U8, mem::Zeroed};
/// let a = ArrayVec::<u64, 8, U8, Zeroed>::new();
/// assert_eq!(a.capacity(), 8);
/// assert_eq!(a.len(), 0);
/// ```
#[inline]
pub fn new() -> Self {
assert!(C <= L::MAX);
let mut v = ArrayVec {
// it is safe to call `assume_init` to create an array of `MaybeUninit`
arr: unsafe { mem::MaybeUninit::uninit().assume_init() },
len: L::new(0),
phantom1: PhantomData,
};
unsafe { SM::init(v.as_mut_ptr(), Self::CAPACITY) };
v
}
/// Returns the number of elements in the array-vector.
///
/// # Examples
///
/// ```rust
/// # use cds::{arrayvec::ArrayVec, array_vec};
/// let mut a = array_vec![12; 3, 4];
/// assert_eq!(a.len(), 2);
/// a.pop();
/// assert_eq!(a.len(), 1);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.len.as_usize()
}
/// Returns `true` if the array-vector contains no elements.
///
/// Equivalent to `len() == 0`.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// assert_eq!(array_vec![3; u64].is_empty(), true);
/// assert_eq!(array_vec![3; u64; 1].is_empty(), false);
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Returns `true` if the array-vector is completely full.
///
/// Equivalent to `len() == capacity()`.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2];
/// assert_eq!(v.is_full(), false);
/// v.push(3);
/// assert_eq!(v.is_full(), true);
/// ```
#[inline]
pub fn is_full(&self) -> bool {
self.len == Self::CAPACITY
}
/// Returns a raw pointer to the array-vector's buffer.
///
/// The caller must ensure that the array-vector outlives the pointer this function returns.
/// Otherwise, it will end up pointing to garbage.
///
/// The caller must also ensure that the memory the pointer (non-transitively) points to is
/// never written to (except inside an `UnsafeCell`) using this pointer or any pointer derived
/// from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
///
/// [`as_mut_ptr`]: ArrayVec::as_mut_ptr
#[inline]
pub fn as_ptr(&self) -> *const T {
self.arr.as_ptr() as *const T
}
/// Returns an unsafe mutable pointer to the array-vector's buffer.
///
/// The caller must ensure that the array-vector outlives the pointer this function returns.
/// Otherwise, it will end up pointing to garbage.
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.arr.as_mut_ptr() as *mut T
}
/// Extracts a slice of the entire array-vector.
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len.as_usize()) }
}
/// Extracts a mutable slice of the entire array-vector.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len.as_usize()) }
}
/// Returns the total number of elements the array-vector can hold.
///
/// This is a convenience method. The capacity of the array-vector is known at compilation time
/// and can be also obtained via the [`CAPACITY`] associated constant.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![17; u64];
/// assert_eq!(v.capacity(), 17);
/// ```
///
/// [`CAPACITY`]: ArrayVec::CAPACITY
#[inline]
pub fn capacity(&self) -> usize {
Self::CAPACITY
}
/// Returns the number of elements the array-vector can hold in addition to already held ones.
///
/// Equivalent to `capacity() - len()`.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64];
/// assert_eq!(v.capacity(), 2);
/// assert_eq!(v.spare_capacity(), 2);
///
/// v.push(1);
/// assert_eq!(v.capacity(), 2);
/// assert_eq!(v.spare_capacity(), 1);
/// ```
#[inline]
pub fn spare_capacity(&self) -> usize {
Self::CAPACITY - self.len.as_usize()
}
/// Checks if there is spare capacity in the array-vector.
///
/// Equivalent to `len() < capacity()`, `spare_capacity() != 0` and `!is_full()`.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64];
/// assert_eq!(v.capacity(), 2);
/// assert_eq!(v.has_spare_capacity(), true);
///
/// v.push(1);
/// v.push(2);
/// assert_eq!(v.has_spare_capacity(), false);
/// ```
#[inline]
pub fn has_spare_capacity(&self) -> bool {
self.len < Self::CAPACITY
}
/// Forces the length of the array-vector to `new_len`.
///
/// Note that this method doesn't [`drop`] elements, which may lead to a resource leak if
/// `new_len < len()` and `T` has a custom [`Drop`] implementation. See [`truncate`] for a
/// method that handles array-vector truncation properly.
///
/// # Safety
///
/// - `new_len` must be less than or equal to the array-vector's [`CAPACITY`]
/// - the elements at `old_len..new_len` must be initialized
///
/// [`CAPACITY`]: ArrayVec::CAPACITY
///
/// # Panics
///
/// This method uses debug assertions to verify that `new_len` is in bounds.
///
/// [`drop`]: core::mem::drop
/// [`Drop`]: core::ops::Drop
/// [`truncate`]: ArrayVec::truncate
#[inline]
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(new_len <= Self::CAPACITY);
self.len.set(new_len);
}
/// Appends an element to the back of the array-vector.
///
/// # Panics
///
/// This method panics if there is no spare capacity to accommodate the new element.
/// See [`try_push`] for a method that returns an error instead.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64];
/// v.push(1);
/// v.push(2);
/// ```
///
/// [`push`] panics if there is no spare capacity:
///
/// ```should_panic
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64];
/// v.push(1);
/// v.push(2);
/// v.push(3); // <-- this panics
/// ```
///
/// [`try_push`]: ArrayVec::try_push
/// [`push`]: ArrayVec::push
#[inline]
pub fn push(&mut self, e: T) {
if self.len >= Self::CAPACITY {
panic!("insufficient capacity");
}
unsafe { self.push_unchecked(e) };
}
/// Tries to append an element to the back of the array-vector.
///
/// Returns [`InsufficientCapacityError`] if there is no spare capacity to accommodate a new
/// element.
///
/// This is a non-panic version of [`push`].
///
/// # Examples
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityError};
/// let mut v = array_vec![2; u64];
/// assert!(v.try_push(1).is_ok());
/// assert!(v.try_push(2).is_ok());
/// assert!(matches!(v.try_push(3), Err(e) if e == InsufficientCapacityError));
/// assert_eq!(v, [1, 2]);
/// ```
///
/// [`push`]: ArrayVec::push
#[inline]
pub fn try_push(&mut self, e: T) -> Result<(), InsufficientCapacityError> {
if self.len < Self::CAPACITY {
unsafe { self.push_unchecked(e) };
Ok(())
} else {
Err(InsufficientCapacityError {})
}
}
/// Tries to append an element to the back of the array-vector.
///
/// Returns [`InsufficientCapacityErrorVal`] if there is no spare capacity to accommodate a new
/// element.
///
/// The difference between this method and [`try_push`] is that in case of an error
/// [`try_push_val`] returns the element back to the caller.
///
/// This is a non-panic version of [`push`].
///
/// # Examples
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityErrorVal};
/// let mut v = array_vec![2; u64];
/// assert_eq!(v, []);
///
/// assert!(v.try_push_val(1).is_ok());
/// assert!(v.try_push_val(2).is_ok());
/// assert_eq!(v, [1, 2]);
///
/// assert!(matches!(v.try_push_val(3), Err(InsufficientCapacityErrorVal(e)) if e == 3));
/// assert_eq!(v, [1, 2]);
/// ```
///
/// [`try_push_val`]: ArrayVec::try_push_val
/// [`try_push`]: ArrayVec::try_push
/// [`push`]: ArrayVec::push
#[inline]
pub fn try_push_val(&mut self, value: T) -> Result<(), InsufficientCapacityErrorVal<T>> {
if self.len < Self::CAPACITY {
unsafe { self.push_unchecked(value) };
Ok(())
} else {
Err(InsufficientCapacityErrorVal(value))
}
}
/// Appends an element to the back of the array-vector without spare capacity check.
///
/// This method is useful when spare capacity check is already done by the caller.
///
/// # Safety
///
/// The caller must ensure that the array-vector has spare capacity to accommodate a new
/// element.
///
/// # Example
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![3; usize; 1];
/// while a.has_spare_capacity() {
/// unsafe { a.push_unchecked(0); }
/// }
/// assert_eq!(a, [1, 0, 0]);
/// ```
#[inline]
pub unsafe fn push_unchecked(&mut self, value: T) {
let len = self.len();
self.as_mut_ptr().add(len).write(value);
self.set_len(len + 1);
}
/// Removes the last element from an array-vector and returns it, or [`None`] if it is empty.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![3; 10];
/// assert_eq!(a.pop(), Some(10));
/// assert_eq!(a.pop(), None);
/// ```
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.len > 0 {
unsafe { Some(self.pop_unchecked()) }
} else {
None
}
}
/// Removes the last element from array-vector and returns it without checking the length.
///
/// # Safety
///
/// The caller must ensure that the array-vector is not empty.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![3; 11, 12];
/// if !a.is_empty() {
/// unsafe {
/// assert_eq!(a.pop_unchecked(), 12);
/// }
/// }
/// ```
#[inline]
pub unsafe fn pop_unchecked(&mut self) -> T {
self.len -= 1;
let p = self.as_mut_ptr().add(self.len.as_usize());
let e = p.read();
SM::init(p, 1);
e
}
/// Clears the array-vector, dropping all values.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![16; 1, 2, 3];
/// assert_eq!(a, [1, 2, 3]);
/// a.clear();
/// assert_eq!(a, []);
/// ```
#[inline]
pub fn clear(&mut self) {
self.truncate(0)
}
/// Shortens the array-vector, keeping the first `len` elements and dropping the rest.
///
/// If `len` is greater than array-vector's current length, this has no effect.
///
/// # Safety
///
/// Spare memory policy is invoked only if all truncated elements drop successfully. I.e, if
/// any of the truncated elements panics during drop, spare memory policy isn't invoked
/// at all, including on successfully dropped elements.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![8; 1, 2, 3];
/// assert_eq!(a, [1, 2, 3]);
/// a.truncate(1);
/// assert_eq!(a, [1]);
/// a.truncate(2);
/// assert_eq!(a, [1]);
/// ```
#[inline]
pub fn truncate(&mut self, len: usize) {
let my_len = self.len.as_usize();
if len < my_len {
unsafe {
// `drop` of any of the truncated slots may panic, which may trigger destruction
// of `self`. Thus, update `self.len` *before* calling `drop_in_place` to avoid
// a possible double-drop of a truncated slot.
self.set_len(len);
// create a slice of truncated slots
let s = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), my_len - len);
// `drop_in_place` drops every slot in the slice. If one slot panics, it will first
// try to drop the rest and only then re-raise the panic.
// If more than one slot panic, the program aborts.
ptr::drop_in_place(s);
// TODO: invoke SM-policy on every successfully dropped element, even if one panics
// invoke spare memory policy
SM::init(s.as_mut_ptr(), s.len());
}
}
}
/// Returns an iterator over the slice.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let v = array_vec![3; 1, 2];
/// let mut iterator = v.iter();
/// assert_eq!(iterator.next(), Some(&1));
/// assert_eq!(iterator.next(), Some(&2));
/// assert_eq!(iterator.next(), None);
/// ```
#[inline]
pub fn iter(&self) -> slice::Iter<'_, T> {
self.as_slice().iter()
}
/// Returns an iterator over the slice that allows modifying each value.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; 1, 2];
/// for e in v.iter_mut() {
/// *e *= 2;
/// }
/// assert_eq!(v, [2, 4]);
/// ```
#[inline]
pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
self.as_mut_slice().iter_mut()
}
/// Creates an array-vector from an iterator.
///
/// Returns [`InsufficientCapacityError`] if the iterator yields more than [`CAPACITY`]
/// elements.
///
/// [`CAPACITY`]: ArrayVec::CAPACITY
///
/// # Examples
///
/// ```rust
/// # use cds::{
/// # arrayvec::{ArrayVec, errors::InsufficientCapacityError},
/// # len::U8, mem::Uninitialized
/// # };
/// # use std::error::Error;
/// # fn example() -> Result<(), InsufficientCapacityError> {
/// type A = ArrayVec<usize, 3, U8, Uninitialized>;
/// let a = [1, 2, 3];
/// let v = A::try_from_iter(a.iter().filter(|x| **x % 2 == 0).cloned())?;
/// assert_eq!(v, [2]);
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn try_from_iter<I>(iter: I) -> Result<Self, InsufficientCapacityError>
where
I: IntoIterator<Item = T>,
{
let mut tmp = Self::new();
let mut p = tmp.as_mut_ptr();
for e in iter {
if tmp.len >= Self::CAPACITY {
return Err(InsufficientCapacityError {});
}
unsafe {
p.write(e);
p = p.add(1);
tmp.len += 1;
}
}
Ok(tmp)
}
/// Inserts an element at position `index` within the vector, shifting all elements after it to
/// the right.
///
/// Note that the worst case performance of this operation is O(n), because all elements of the
/// array may be shifted right. If order of elements is not needed to be preserved, use [`push`]
/// instead.
///
/// # Panics
///
/// This method panics if any of the following conditions is met:
/// - `index > len()`
/// - there is no spare capacity in the array-vector
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2];
/// assert_eq!(v, [1, 2]);
/// v.insert(1, 0);
/// assert_eq!(v, [1, 0, 2]);
/// ```
/// [`insert`] panics if `index > len()`:
///
/// ```should_panic
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1];
/// assert_eq!(v.len(), 1);
/// v.insert(2, 1); // <-- this panics because 2 > v.len()
/// ```
///
/// [`insert`] also panics if there is no spare capacity:
///
/// ```should_panic
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64; 1, 2];
/// assert_eq!(v.has_spare_capacity(), false);
/// v.insert(0, 0); // <-- this panics
/// ```
///
/// [`insert`]: ArrayVec::insert
/// [`push`]: ArrayVec::push
#[inline]
pub fn insert(&mut self, index: usize, element: T) {
self.try_insert(index, element).expect("cannot insert")
}
/// Tries to insert an element at position `index` within the vector, shifting all elements
/// after it to the right.
///
/// Returns [`InsertError`] if there is no spare capacity in the array vector, or if `index` is
/// out of bounds.
///
/// Note that in case of an error `value` is lost if it is not [`Copy`]. Use [`try_insert_val`]
/// to receive the element back in case of an error.
///
/// Note that the worst case performance of this operation is O(n), because all elements of the
/// array may be shifted right. If order of elements is not needed to be preserved,
/// use [`try_push`] instead.
///
/// This is a non-panic version of [`insert`].
///
/// # Examples
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsertError};
/// let mut v = array_vec![3; u64; 1, 2];
/// assert!(matches!(v.try_insert(3, 3), Err(InsertError::InvalidIndex)));
///
/// assert!(v.try_insert(0, 0).is_ok());
/// assert_eq!(v, [0, 1, 2]);
/// assert!(matches!(v.try_insert(1, 3), Err(InsertError::InsufficientCapacity)));
/// ```
///
/// [`try_push`]: ArrayVec::try_push
/// [`try_insert_val`]: ArrayVec::try_insert_val
/// [`insert`]: ArrayVec::insert
#[inline]
pub fn try_insert(&mut self, index: usize, value: T) -> Result<(), InsertError> {
let len = self.len();
if index > len {
return Err(InsertError::InvalidIndex);
}
if len >= Self::CAPACITY {
return Err(InsertError::InsufficientCapacity);
}
unsafe {
self.insert_unchecked(index, value);
}
Ok(())
}
/// Tries to insert an element at position `index` within the array-vector,
/// shifting all elements after it to the right.
///
/// Returns [`InsertErrorVal`] if there is no spare capacity in the array vector,
/// or if `index` is out of bounds.
///
/// The difference between this method and [`try_insert`], is that in case of an error
/// [`try_insert_val`] returns the element back to the caller.
///
/// Note that the worst case performance of this operation is O(n), because all elements of the
/// array may be shifted right. If order of elements is not needed to be preserved,
/// use [`try_push_val`] instead.
///
/// This is a non-panic version of [`insert`].
///
/// # Examples
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsertErrorVal};
/// let mut v = array_vec![3; u64; 1, 2];
/// assert!(matches!(
/// v.try_insert_val(5, 3),
/// Err(InsertErrorVal::InvalidIndex(v)) if v == 3
/// ));
/// assert_eq!(v, [1, 2]);
///
/// assert!(v.try_insert_val(0, 0).is_ok());
/// assert_eq!(v, [0, 1, 2]);
///
/// assert!(matches!(
/// v.try_insert_val(1, 5),
/// Err(InsertErrorVal::InsufficientCapacity(v)) if v == 5
/// ));
/// assert_eq!(v, [0, 1, 2]);
/// ```
///
/// [`try_insert_val`]: ArrayVec::try_insert_val
/// [`try_insert`]: ArrayVec::try_insert
/// [`try_push_val`]: ArrayVec::try_push_val
/// [`insert`]: ArrayVec::insert
#[inline]
pub fn try_insert_val(&mut self, index: usize, value: T) -> Result<(), InsertErrorVal<T>> {
if index > self.len.as_usize() {
return Err(InsertErrorVal::InvalidIndex(value));
}
if self.len >= Self::CAPACITY {
return Err(InsertErrorVal::InsufficientCapacity(value));
}
unsafe {
self.insert_unchecked(index, value);
}
Ok(())
}
/// Inserts an element at position `index` within the vector, shifting all elements after it
/// to the right.
///
/// # Safety
///
/// The caller must ensure the following conditions:
/// - `index <= len()`
/// - there is spare capacity in the array-vector
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2];
/// assert_eq!(v, [1, 2]);
/// assert_eq!(v.has_spare_capacity(), true);
///
/// unsafe { v.insert_unchecked(0, 0) };
/// assert_eq!(v, [0, 1, 2]);
///
/// v.pop();
/// assert_eq!(v, [0, 1]);
/// assert_eq!(v.has_spare_capacity(), true);
///
/// unsafe { v.insert_unchecked(2, 2) };
/// assert_eq!(v, [0, 1, 2]);
/// ```
#[inline]
pub unsafe fn insert_unchecked(&mut self, index: usize, value: T) {
let len = self.len();
let p = self.as_mut_ptr().add(index);
ptr::copy(p, p.add(1), len - index);
p.write(value);
self.set_len(len + 1);
}
/// Removes and returns the element at position `index` within the vector, shifting all elements
/// after it to the left.
///
/// Note: Because this shifts over the remaining elements, it has a worst-case performance of
/// O(n). If you don’t need the order of elements to be preserved, use [`swap_remove`] instead.
///
/// # Panics
///
/// This method panics if `index >= len()`.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2, 3];
/// assert_eq!(v, [1, 2, 3]);
/// assert_eq!(v.remove(1), 2);
/// assert_eq!(v, [1, 3]);
/// ```
///
/// [`remove`] panics if `index` is out of bounds:
///
/// ```should_panic
/// # use cds::array_vec;
/// let mut v = array_vec![2; u64; 1];
/// assert_eq!(v, [1]);
/// v.remove(1); // <-- this panics because index=1 is out of bounds
/// ```
///
/// [`swap_remove`]: ArrayVec::swap_remove
/// [`remove`]: ArrayVec::remove
#[inline]
pub fn remove(&mut self, index: usize) -> T {
if index >= self.len.as_usize() {
panic!("index is out of bounds [0, {}): {}", self.len, index);
}
unsafe { self.remove_unchecked(index) }
}
/// Tries to remove and return the element at position `index` within the vector, shifting all
/// elements after it to the left.
///
/// Returns `None` if `index` is out of bounds.
///
/// Note: Because this shifts over the remaining elements, it has a worst-case performance of
/// O(n). If you don’t need the order of elements to be preserved, use [`try_swap_remove`]
/// instead.
///
/// This is a non-panic version of [`remove`].
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2, 3];
/// assert_eq!(v.try_remove(3), None);
/// assert_eq!(v.try_remove(0), Some(1));
/// assert_eq!(v, [2, 3]);
/// ```
///
/// [`remove`]: ArrayVec::remove
/// [`try_swap_remove`]: ArrayVec::try_swap_remove
#[inline]
pub fn try_remove(&mut self, index: usize) -> Option<T> {
if index < self.len.as_usize() {
unsafe { Some(self.remove_unchecked(index)) }
} else {
None
}
}
/// Removes and returns the element at position `index` within the array-vector, shifting all
/// elements after it to the left.
///
/// Note: Because this shifts over the remaining elements, it has a worst-case performance of
/// O(n). If you don’t need the order of elements to be preserved, use [`swap_remove_unchecked`]
/// instead.
///
/// This is the unchecked version of [`remove`].
///
/// # Safety
///
/// The caller must ensure that `index < len()`.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2, 3];
/// assert_eq!(v, [1, 2, 3]);
/// assert_eq!(unsafe { v.remove_unchecked(0) }, 1);
/// assert_eq!(v, [2, 3]);
/// ```
///
/// [`remove`]: ArrayVec::remove
/// [`swap_remove_unchecked`]: ArrayVec::swap_remove_unchecked
#[inline]
pub unsafe fn remove_unchecked(&mut self, index: usize) -> T {
let base = self.as_mut_ptr();
let p = base.add(index);
let tmp = p.read();
ptr::copy(p.add(1), p, self.len.as_usize() - index - 1);
self.len -= 1;
SM::init(base.add(self.len.as_usize()), 1);
tmp
}
/// Removes an element at position `index` from the array-vector and returns it.
///
/// The removed element is replaced by the last element of the array-vector.
///
/// This does not preserve ordering, but is O(1).
///
/// # Panics
///
/// This method panics of `index` is out of bounds.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![4; u64; 1, 2, 3, 4];
/// assert_eq!(v.swap_remove(1), 2);
/// assert_eq!(v, [1, 4, 3]);
/// ```
#[inline]
pub fn swap_remove(&mut self, index: usize) -> T {
let len = self.len();
if index >= len {
panic!("index is out of bounds [0, {}): {}", len, index);
}
unsafe { self.swap_remove_unchecked(index) }
}
/// Tries to remove an element at position `index` from the array-vector and returns it.
///
/// The removed element is replaced by the last element of the array-vector.
///
/// This does not preserve ordering, but is O(1).
///
/// Returns `None` if `index` is out of bounds.
///
/// This is a non-panic version of [`swap_remove`].
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![3; u64; 1, 2, 3];
/// assert_eq!(v.try_swap_remove(3), None);
/// assert_eq!(v.try_swap_remove(0), Some(1));
/// assert_eq!(v, [3, 2]);
/// ```
///
/// [`swap_remove`]: ArrayVec::swap_remove
#[inline]
pub fn try_swap_remove(&mut self, index: usize) -> Option<T> {
if index < self.len.as_usize() {
unsafe { Some(self.swap_remove_unchecked(index)) }
} else {
None
}
}
/// Removes an element at position `index` from the array-vector and returns it, without
/// bounds check.
///
/// The removed element is replaced by the last element of the array-vector.
/// This does not preserve ordering, but is O(1).
///
/// # Safety
///
/// The caller must ensure that `index < len()`.
///
/// # Example
///
/// ```rust
/// # use cds::array_vec;
/// let mut v = array_vec![4; u64; 1, 2, 3, 4];
/// assert_eq!(v, [1, 2, 3, 4]);
/// assert_eq!(unsafe { v.swap_remove_unchecked(2) }, 3);
/// assert_eq!(v, [1, 2, 4]);
/// ```
#[inline]
pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T {
let base = self.as_mut_ptr();
let p = base.add(index);
let value = p.read();
self.len -= 1;
let last = base.add(self.len.as_usize());
ptr::copy(last, p, 1);
SM::init(last, 1);
value
}
/// Creates a draining iterator that removes the specified range in the array-vector
/// and yields the removed items.
///
/// When the iterator is dropped, all elements in the range are removed from the array-vector,
/// even if the iterator was not fully consumed.
/// If the iterator is not dropped (with [`mem::forget`] for example),
/// it is unspecified how many elements are removed.
///
/// # Panics
///
/// Panics if the starting point is greater than the end point or if the end point is greater
/// than the length of the vector.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; usize; 1, 2, 3, 4, 5];
/// assert_eq!(a, [1, 2, 3, 4, 5]);
/// for (index, i) in a.drain(0..3).enumerate() {
/// assert_eq!(index + 1, i);
/// }
/// assert_eq!(a, [4, 5]);
/// ```
///
/// [`mem::forget`]: core::mem::forget
#[inline]
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, L, SM, C>
where
R: RangeBounds<usize>,
{
let end = match range.end_bound() {
Bound::Included(e) => e
.checked_add(1)
.unwrap_or_else(|| panic!("end bound overflows")),
Bound::Excluded(e) => *e,
Bound::Unbounded => self.len(),
};
if end > self.len() {
panic!("invalid end bound");
}
let start = match range.start_bound() {
Bound::Included(s) => *s,
Bound::Excluded(s) => s
.checked_add(1)
.unwrap_or_else(|| panic!("start bound overflows")),
Bound::Unbounded => 0,
};
if start > end {
panic!("invalid range");
}
unsafe {
let len = self.len();
let (iter, tail, tail_len) = if start < end {
// set `len` to reflect the head only
self.set_len(start);
(
slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start).iter(),
L::new(end),
L::new(len - end),
)
} else {
// empty drained range, mark it with an impossible combination of `tail/tail_len`
([].iter(), L::new(L::MAX), L::new(L::MAX))
};
Drain {
av: ptr::NonNull::new_unchecked(self),
iter,
tail,
tail_len,
}
}
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
/// This method operates in place, visiting each element exactly once in the original order,
/// and preserves the order of the retained elements.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; 0, 1, 2, 3, 4];
/// assert_eq!(a, [0, 1, 2, 3, 4]);
/// a.retain(|e| (*e & 1) != 0);
/// assert_eq!(a, [1, 3]);
/// ```
#[inline]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
self.retain_mut(|e| f(e))
}
/// Retains only the elements specified by the predicate, passing a mutable reference to it.
///
/// In other words, remove all elements `e` such that `f(&mut e)` returns `false`.
/// This method operates in place, visiting each element exactly once in the original order,
/// and preserves the order of the retained elements.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; 0, 1, 2, 3, 4];
/// assert_eq!(a, [0, 1, 2, 3, 4]);
/// a.retain_mut(|e| if (*e & 1) == 0 {
/// *e *= *e;
/// true
/// } else {
/// false
/// });
/// assert_eq!(a, [0, 4, 16]);
/// ```
#[inline]
pub fn retain_mut<F>(&mut self, mut f: F)
where
F: FnMut(&mut T) -> bool,
{
let len = self.len();
// set `len` to zero, to avoid double-drop of deleted items.
// `len` is restored by RetainGuard.
unsafe { self.set_len(0) };
let mut g = RetainGuard {
av: self,
len,
deleted: 0,
processed: 0,
};
unsafe {
// no empty slot found yet, so there is nothing to move
while g.processed < len {
let item_mut_ref = &mut *g.av.as_mut_ptr().add(g.processed);
if !f(item_mut_ref) {
// update counters before drop_in_place, as it may panic
g.processed += 1;
g.deleted += 1;
ptr::drop_in_place(item_mut_ref);
break;
}
g.processed += 1;
}
// If there are items left to process, there must be an empty slot.
// Move every retained slot to an empty one.
while g.processed < len {
let base_p = g.av.as_mut_ptr();
let item_mut_ref = &mut *base_p.add(g.processed);
if !f(item_mut_ref) {
// update counters before drop_in_place, as it may panic
g.processed += 1;
g.deleted += 1;
ptr::drop_in_place(item_mut_ref);
continue;
} else {
ptr::copy_nonoverlapping(
item_mut_ref as *mut _,
base_p.add(g.processed - g.deleted),
1,
);
}
g.processed += 1;
}
}
}
/// Returns the remaining spare capacity of the array-vector as a slice of `MaybeUninit<T>`.
///
/// The returned slice can be used to fill the array-vector with data (e.g. by reading from a
/// file) before marking the data as initialized using the [`set_len`] method.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![32; 1, 2]; // <-- an array-vector for IO of 32 elements
/// assert_eq!(a, [1, 2]);
///
/// let spare_capacity = a.spare_capacity_mut();
/// spare_capacity[0].write(3); // <-- read another 2 elements into the array-vector
/// spare_capacity[1].write(4);
///
/// unsafe { a.set_len(a.len() + 2) }; // <-- reflect the new size
///
/// assert_eq!(a, [1, 2, 3, 4]);
/// ```
///
/// [`set_len`]: ArrayVec::set_len
#[inline]
pub fn spare_capacity_mut(&mut self) -> &mut [mem::MaybeUninit<T>] {
unsafe {
slice::from_raw_parts_mut(self.arr.as_mut_ptr().add(self.len()), self.spare_capacity())
}
}
/// Returns array-vector content as a slice of `T`, along with the remaining spare capacity of
/// the array-vector as a slice of `MaybeUninit<T>`.
///
/// The returned spare capacity slice can be used to fill the array-vector with data
/// (e.g. by reading from a file) before marking the data as initialized using the [`set_len`]
/// method.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![32; 1, 2]; // <-- an array-vector for IO of 32 elements
///
/// let (init, spare) = a.split_at_spare_mut();
/// assert_eq!(init, &[1, 2]);
///
/// assert_eq!(spare.len(), 30); // <-- read another 2 elements into the array-vector
/// spare[0].write(3);
/// spare[1].write(4);
///
/// unsafe { a.set_len(a.len() + 2) }; // <-- reflect the new size
///
/// assert_eq!(a, [1, 2, 3, 4]);
/// ```
///
/// [`set_len`]: ArrayVec::set_len
#[inline]
pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [mem::MaybeUninit<T>]) {
let len = self.len();
let spare_capacity = self.spare_capacity();
let p = self.as_mut_ptr();
unsafe {
(
slice::from_raw_parts_mut(p, len),
slice::from_raw_parts_mut(p.add(len) as *mut mem::MaybeUninit<T>, spare_capacity),
)
}
}
/// Resizes the array-vector in-place so that `len` is equal to `new_len`.
///
/// If `new_len` is greater than `len`, the array-vector is extended by the difference,
/// with each additional slot filled with the result of calling the closure `f`.
/// The return values from `f` will end up in the array-vector in the order they have been
/// generated.
///
/// If `new_len` is less than `len`, the array-vector is simply truncated.
///
/// This method uses a closure to create new values on every push.
/// If you’d rather [`Clone`] a given value, use [`try_resize`].
/// If you want to use the [`Default`] trait to generate values, you can pass
/// [`Default::default`] as the second argument.
///
/// # Panics
///
/// This method panics of `new_len > CAPACITY`. To avoid panic use [`try_resize_with`] which
/// returns [`InsufficientCapacityError`] instead.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; 1];
/// assert_eq!(a, [1]);
///
/// let mut g = 1;
///
/// a.resize_with(3, || { g += 1; g });
/// assert_eq!(a, [1, 2, 3]);
///
/// a.resize_with(5, || { g *= 2; g });
/// assert_eq!(a, [1, 2, 3, 6, 12]);
///
/// a.resize_with(1, || 0);
/// assert_eq!(a, [1]);
/// ```
///
/// [`try_resize`]: ArrayVec::try_resize
/// [`try_resize_with`]: ArrayVec::try_resize_with
/// [`resize_with`]: ArrayVec::resize_with
/// [`Clone`]: core::clone::Clone
/// [`Default`]: core::default::Default
/// [`Default::default`]: core::default::Default::default
#[inline]
pub fn resize_with<F>(&mut self, new_len: usize, f: F)
where
F: FnMut() -> T,
{
self.try_resize_with(new_len, f)
.expect("insufficient capacity")
}
/// Tries to resize the array-vector in-place so that `len` is equal to `new_len`.
///
/// This is a non-panic version of [`resize_with`].
///
/// If `new_len` is greater than `len`, the array-vector is extended by the difference,
/// with each additional slot filled with the result of calling the closure `f`.
/// The return values from `f` will end up in the array-vector in the order they have been
/// generated.
///
/// If `new_len` is less than `len`, the array-vector is simply truncated.
///
/// This method uses a closure to create new values on every push.
/// If you’d rather [`Clone`] a given value, use [`try_resize`].
/// If you want to use the [`Default`] trait to generate values, you can pass
/// [`Default::default`] as the second argument.
///
/// # Examples
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityError};
/// # fn foo() -> Result<(), InsufficientCapacityError> {
/// let mut a = array_vec![5;];
/// assert_eq!(a, []);
///
/// a.try_resize_with(3, Default::default)?;
/// assert_eq!(a, [0, 0, 0]);
///
/// let mut g = 2;
/// a.try_resize_with(5, move || { g += 1; g })?;
/// assert_eq!(a, [0, 0, 0, 3, 4]);
///
/// a.try_resize_with(1, || 1)?;
/// assert_eq!(a, [0]);
///
/// assert!(matches!(a.try_resize_with(10, || 7), Err(e) if e == InsufficientCapacityError));
/// # Ok(())
/// # }
/// # foo();
/// ```
///
/// [`try_resize`]: ArrayVec::try_resize
/// [`resize_with`]: ArrayVec::resize_with
/// [`Clone`]: core::clone::Clone
/// [`Default`]: core::default::Default
/// [`Default::default`]: core::default::Default::default
#[inline]
pub fn try_resize_with<F>(
&mut self,
new_len: usize,
mut f: F,
) -> Result<(), InsufficientCapacityError>
where
F: FnMut() -> T,
{
if new_len > Self::CAPACITY {
return Err(InsufficientCapacityError {});
}
if new_len < self.len() {
self.truncate(new_len);
return Ok(());
}
while self.len() < new_len {
unsafe { self.push_unchecked(f()) };
}
Ok(())
}
}
impl<T, L, SM, const C: usize> ArrayVec<T, C, L, SM>
where
T: Clone,
L: LengthType,
SM: SpareMemoryPolicy<T>,
{
/// Resizes the array-vector in-place so that `len` is equal to `new_len`.
///
/// If `new_len` is greater than `len`, the array-vector is extended by the difference,
/// with each additional slot filled with `value`. If `new_len` is less than `len`,
/// the array-vector is simply truncated.
///
/// If you need only to resize to a smaller size, use [`truncate`].
///
/// # Panics
///
/// This method panics if `new_len > CAPACITY`. To avoid panic use [`try_resize`] which
/// returns [`InsufficientCapacityError`] instead.
///
/// # Examples
///
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5;];
/// assert_eq!(a, []);
///
/// a.resize(2, 1);
/// assert_eq!(a, [1, 1]);
///
/// a.resize(4, 5);
/// assert_eq!(a, [1, 1, 5, 5]);
///
/// a.resize(1, 7);
/// assert_eq!(a, [1]);
/// ```
///
/// [`truncate`]: ArrayVec::truncate
/// [`try_resize`]: ArrayVec::try_resize
#[inline]
pub fn resize(&mut self, new_len: usize, value: T) {
self.try_resize(new_len, value)
.expect("insufficient capacity");
}
/// Tries to resize the array-vector in-place so that `len` is equal to `new_len`.
///
/// This method returns [`InsufficientCapacityError`] if `new_len > CAPACITY`.
///
/// This is a non-panic version of [`resize`].
///
/// If `new_len` is greater than `len`, the array-vector is extended by the difference,
/// with each additional slot filled with `value`. If `new_len` is less than `len`,
/// the array-vector is simply truncated.
///
/// If you need only to resize to a smaller size, use [`truncate`].
///
/// # Examples
///
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityError};
/// # fn foo() -> Result<(), InsufficientCapacityError> {
/// let mut a = array_vec![5; 1];
/// assert_eq!(a, [1]);
///
/// a.try_resize(5, 7)?;
/// assert_eq!(a, [1, 7, 7, 7, 7]);
///
/// a.try_resize(2, 0)?;
/// assert_eq!(a, [1, 7]);
///
/// assert!(matches!(a.try_resize(10, 7), Err(e) if e == InsufficientCapacityError));
/// # Ok(())
/// # }
/// # foo();
/// ```
///
/// [`truncate`]: ArrayVec::truncate
/// [`resize`]: ArrayVec::resize
pub fn try_resize(
&mut self,
new_len: usize,
value: T,
) -> Result<(), InsufficientCapacityError> {
if new_len > Self::CAPACITY {
return Err(InsufficientCapacityError {});
}
if new_len < self.len() {
self.truncate(new_len);
return Ok(());
}
while self.len() < new_len {
unsafe { self.push_unchecked(value.clone()) };
}
Ok(())
}
#[inline]
fn _clone_from(&mut self, other: &Self) {
unsafe {
self._clone_from_unchecked(other);
}
}
#[inline]
unsafe fn _clone_from_unchecked(&mut self, s: &[T]) {
debug_assert!(self.is_empty());
let mut p = self.as_mut_ptr();
// Clone every element in source and append to the back of `self`.
// Update `len` one-by-one, as `clone()` may panic and `self.drop()` may be implicitly
// invoked. This way we drop only successfully written slots.
for e in s {
p.write(e.clone());
p = p.add(1);
self.len += 1;
}
}
}
impl<T, L, SM, const C: usize> ArrayVec<T, C, L, SM>
where
T: Copy,
L: LengthType,
SM: SpareMemoryPolicy<T>,
{
/// Extends the array-vector by copying elements from a slice.
///
/// This is optimized for [`Copy`] types, elements are copied bytewise.
///
/// # Panics
///
/// This method panics if there is no enough spare capacity to accommodate
/// all elements from `s`. See [`try_copy_from_slice`] for a method that returns
/// [`InsufficientCapacityError`] instead.
///
/// [`try_copy_from_slice`]: ArrayVec::try_copy_from_slice
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; 1, 2];
/// assert_eq!(a, [1, 2]);
/// a.copy_from_slice(&[3, 4]);
/// assert_eq!(a, [1, 2, 3, 4]);
/// ```
/// ```should_panic
/// # use cds::array_vec;
/// let mut a = array_vec![3; 1, 2];
/// a.copy_from_slice(&[3, 4]); // <-- this panics as there is only one spare slot
/// ```
#[inline]
pub fn copy_from_slice(&mut self, s: &[T]) {
if self.len() + s.len() > Self::CAPACITY {
panic!("insufficient capacity");
}
unsafe { self.copy_from_slice_unchecked(s) };
}
/// Tries to extend the array-vector by copying elements from a slice.
///
/// This is optimized for [`Copy`] types, elements are copied bytewise.
///
/// This method is a non-panic version of [`copy_from_slice`].
///
/// It returns [`InsufficientCapacityError`] if there is no enough spare capacity to accommodate
/// all elements from `s`.
///
/// [`copy_from_slice`]: ArrayVec::copy_from_slice
///
/// # Examples
/// ```rust
/// # use cds::{array_vec, arrayvec::errors::InsufficientCapacityError};
/// # fn foo() -> Result<(), InsufficientCapacityError> {
/// let mut a = array_vec![5; 1, 2];
/// assert_eq!(a, [1, 2]);
/// a.try_copy_from_slice(&[1, 2])?;
/// assert_eq!(a, [1, 2, 1, 2]);
/// assert!(matches!(a.try_copy_from_slice(&[3, 4]), Err(e) if e == InsufficientCapacityError));
/// # Ok(())
/// # }
/// # foo().unwrap();
/// ```
pub fn try_copy_from_slice(&mut self, s: &[T]) -> Result<(), InsufficientCapacityError> {
if self.len() + s.len() > Self::CAPACITY {
return Err(InsufficientCapacityError {});
}
unsafe { self.copy_from_slice_unchecked(s) };
Ok(())
}
/// Extends the array-vector by copying elements from a slice.
///
/// This is optimized for [`Copy`] types, elements are copied bytewise.
///
/// # Safety
///
/// The caller must ensure that there is enough spare capacity to accommodate all elements
/// from `s`.
///
/// # Panics
///
/// This method uses debug assertions to ensure that array-vector's capacity is not exceeded.
///
/// # Examples
/// ```rust
/// # use cds::array_vec;
/// let mut a = array_vec![5; 1, 2];
/// assert_eq!(a, [1, 2]);
/// unsafe { a.copy_from_slice_unchecked(&[1, 2]) };
/// assert_eq!(a, [1, 2, 1, 2]);
/// ```
#[inline]
pub unsafe fn copy_from_slice_unchecked(&mut self, s: &[T]) {
// SAFETY: it is impossible that regions overlap
// as `self` cannot be borrowed as both mutable and immutable
ptr::copy_nonoverlapping(s.as_ptr(), self.as_mut_ptr().add(self.len()), s.len());
self.len += s.len();
}
}
mod macros;
mod traits;
#[cfg(test)]
mod test_arrayvec;