diff --git a/Cargo.toml b/Cargo.toml index 5f4fd2c..a32553e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayvec" -version = "0.7.4" +version = "0.8.0" authors = ["bluss"] license = "MIT OR Apache-2.0" edition = "2018" @@ -42,6 +42,7 @@ harness = false [features] default = ["std"] std = [] +copy = [] [profile.bench] debug = true diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs new file mode 100644 index 0000000..8740cf6 --- /dev/null +++ b/src/arrayvec_copy.rs @@ -0,0 +1,1273 @@ +use std::cmp; +use std::iter; +use std::mem; +use std::ops::{Bound, Deref, DerefMut, RangeBounds}; +use std::ptr; +use std::slice; + +// extra traits +use std::borrow::{Borrow, BorrowMut}; +use std::fmt; +use std::hash::{Hash, Hasher}; + +#[cfg(feature = "std")] +use std::io; + +use std::mem::MaybeUninit; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::arrayvec_impl::ArrayVecImpl; +use crate::errors::CapacityError; +use crate::utils::MakeMaybeUninit; +use crate::LenUint; + +/// A vector with a fixed capacity which implements `Copy` and its elemenents are constrained to also be `Copy`. +/// +/// The `ArrayVecCopy` is a vector backed by a fixed size array. It keeps track of +/// the number of initialized elements. The `ArrayVecCopy` is parameterized +/// by `T` for the element type and `CAP` for the maximum capacity. +/// +/// `CAP` is of type `usize` but is range limited to `u32::MAX`; attempting to create larger +/// arrayvecs with larger capacity will panic. +/// +/// The vector is a contiguous value (storing the elements inline) that you can store directly on +/// the stack if needed. +/// +/// It offers a simple API but also dereferences to a slice, so that the full slice API is +/// available. The ArrayVecCopy can be converted into a by value iterator. +pub struct ArrayVecCopy { + // the `len` first elements of the array are initialized + xs: [MaybeUninit; CAP], + len: LenUint, +} + +macro_rules! panic_oob { + ($method_name:expr, $index:expr, $len:expr) => { + panic!( + concat!( + "ArrayVecCopy::", + $method_name, + ": index {} is out of bounds in vector of length {}" + ), + $index, $len + ) + }; +} + +impl ArrayVecCopy { + /// Capacity + const CAPACITY: usize = CAP; + + /// Create a new empty `ArrayVecCopy`. + /// + /// The maximum capacity is given by the generic parameter `CAP`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 16>::new(); + /// array.push(1); + /// array.push(2); + /// assert_eq!(&array[..], &[1, 2]); + /// assert_eq!(array.capacity(), 16); + /// ``` + pub fn new() -> ArrayVecCopy { + assert_capacity_limit!(CAP); + unsafe { + ArrayVecCopy { + xs: MaybeUninit::uninit().assume_init(), + len: 0, + } + } + } + + /// Create a new empty `ArrayVecCopy` (const fn). + /// + /// The maximum capacity is given by the generic parameter `CAP`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// static ARRAY: ArrayVecCopy = ArrayVecCopy::new_const(); + /// ``` + pub const fn new_const() -> ArrayVecCopy { + assert_capacity_limit_const!(CAP); + ArrayVecCopy { + xs: MakeMaybeUninit::ARRAY, + len: 0, + } + } + + /// Return the number of elements in the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.len(), 2); + /// ``` + #[inline(always)] + pub fn len(&self) -> usize { + self.len as usize + } + + /// Returns whether the `ArrayVecCopy` is empty. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1]); + /// array.pop(); + /// assert_eq!(array.is_empty(), true); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return the capacity of the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let array = ArrayVecCopy::from([1, 2, 3]); + /// assert_eq!(array.capacity(), 3); + /// ``` + #[inline(always)] + pub fn capacity(&self) -> usize { + CAP + } + + /// Return true if the `ArrayVecCopy` is completely filled to its capacity, false otherwise. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 1>::new(); + /// assert!(!array.is_full()); + /// array.push(1); + /// assert!(array.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + self.len() == self.capacity() + } + + /// Returns the capacity left in the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.remaining_capacity(), 1); + /// ``` + pub fn remaining_capacity(&self) -> usize { + self.capacity() - self.len() + } + + /// Push `element` to the end of the vector. + /// + /// ***Panics*** if the vector is already full. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// array.push(1); + /// array.push(2); + /// + /// assert_eq!(&array[..], &[1, 2]); + /// ``` + pub fn push(&mut self, element: T) { + ArrayVecImpl::push(self, element) + } + + /// Push `element` to the end of the vector. + /// + /// Return `Ok` if the push succeeds, or return an error if the vector + /// is already full. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// let push1 = array.try_push(1); + /// let push2 = array.try_push(2); + /// + /// assert!(push1.is_ok()); + /// assert!(push2.is_ok()); + /// + /// assert_eq!(&array[..], &[1, 2]); + /// + /// let overflow = array.try_push(3); + /// + /// assert!(overflow.is_err()); + /// ``` + pub fn try_push(&mut self, element: T) -> Result<(), CapacityError> { + ArrayVecImpl::try_push(self, element) + } + + /// Push `element` to the end of the vector without checking the capacity. + /// + /// It is up to the caller to ensure the capacity of the vector is + /// sufficiently large. + /// + /// This method uses *debug assertions* to check that the arrayvec is not full. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// if array.len() + 2 <= array.capacity() { + /// unsafe { + /// array.push_unchecked(1); + /// array.push_unchecked(2); + /// } + /// } + /// + /// assert_eq!(&array[..], &[1, 2]); + /// ``` + pub unsafe fn push_unchecked(&mut self, element: T) { + ArrayVecImpl::push_unchecked(self, element) + } + + /// Shortens the vector, keeping the first `len` elements. + /// + /// If `len` is greater than the vector’s current length this has no + /// effect. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3, 4, 5]); + /// array.truncate(3); + /// assert_eq!(&array[..], &[1, 2, 3]); + /// array.truncate(4); + /// assert_eq!(&array[..], &[1, 2, 3]); + /// ``` + pub fn truncate(&mut self, new_len: usize) { + ArrayVecImpl::truncate(self, new_len) + } + + /// Remove all elements in the vector. + pub fn clear(&mut self) { + ArrayVecImpl::clear(self) + } + + /// Get pointer to where element at `index` would be + unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T { + self.as_mut_ptr().add(index) + } + + /// Insert `element` at position `index`. + /// + /// Shift up all elements after `index`. + /// + /// It is an error if the index is greater than the length or if the + /// arrayvec is full. + /// + /// ***Panics*** if the array is full or the `index` is out of bounds. See + /// `try_insert` for fallible version. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// array.insert(0, "x"); + /// array.insert(0, "y"); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + pub fn insert(&mut self, index: usize, element: T) { + self.try_insert(index, element).unwrap() + } + + /// Insert `element` at position `index`. + /// + /// Shift up all elements after `index`; the `index` must be less than + /// or equal to the length. + /// + /// Returns an error if vector is already at full capacity. + /// + /// ***Panics*** `index` is out of bounds. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// assert!(array.try_insert(0, "x").is_ok()); + /// assert!(array.try_insert(0, "y").is_ok()); + /// assert!(array.try_insert(0, "z").is_err()); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), CapacityError> { + if index > self.len() { + panic_oob!("try_insert", index, self.len()) + } + if self.len() == self.capacity() { + return Err(CapacityError::new(element)); + } + let len = self.len(); + + // follows is just like Vec + unsafe { + // infallible + // The spot to put the new value + { + let p: *mut _ = self.get_unchecked_ptr(index); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + Ok(()) + } + + /// Remove the last element in the vector and return it. + /// + /// Return `Some(` *element* `)` if the vector is non-empty, else `None`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// array.push(1); + /// + /// assert_eq!(array.pop(), Some(1)); + /// assert_eq!(array.pop(), None); + /// ``` + pub fn pop(&mut self) -> Option { + ArrayVecImpl::pop(self) + } + + /// Remove the element at `index` and swap the last element into its place. + /// + /// This operation is O(1). + /// + /// Return the *element* if the index is in bounds, else panic. + /// + /// ***Panics*** if the `index` is out of bounds. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// + /// assert_eq!(array.swap_remove(0), 1); + /// assert_eq!(&array[..], &[3, 2]); + /// + /// assert_eq!(array.swap_remove(1), 2); + /// assert_eq!(&array[..], &[3]); + /// ``` + pub fn swap_remove(&mut self, index: usize) -> T { + self.swap_pop(index) + .unwrap_or_else(|| panic_oob!("swap_remove", index, self.len())) + } + + /// Remove the element at `index` and swap the last element into its place. + /// + /// This is a checked version of `.swap_remove`. + /// This operation is O(1). + /// + /// Return `Some(` *element* `)` if the index is in bounds, else `None`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// + /// assert_eq!(array.swap_pop(0), Some(1)); + /// assert_eq!(&array[..], &[3, 2]); + /// + /// assert_eq!(array.swap_pop(10), None); + /// ``` + pub fn swap_pop(&mut self, index: usize) -> Option { + let len = self.len(); + if index >= len { + return None; + } + self.swap(index, len - 1); + self.pop() + } + + /// Remove the element at `index` and shift down the following elements. + /// + /// The `index` must be strictly less than the length of the vector. + /// + /// ***Panics*** if the `index` is out of bounds. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// + /// let removed_elt = array.remove(0); + /// assert_eq!(removed_elt, 1); + /// assert_eq!(&array[..], &[2, 3]); + /// ``` + pub fn remove(&mut self, index: usize) -> T { + self.pop_at(index) + .unwrap_or_else(|| panic_oob!("remove", index, self.len())) + } + + /// Remove the element at `index` and shift down the following elements. + /// + /// This is a checked version of `.remove(index)`. Returns `None` if there + /// is no element at `index`. Otherwise, return the element inside `Some`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// + /// assert!(array.pop_at(0).is_some()); + /// assert_eq!(&array[..], &[2, 3]); + /// + /// assert!(array.pop_at(2).is_none()); + /// assert!(array.pop_at(10).is_none()); + /// ``` + pub fn pop_at(&mut self, index: usize) -> Option { + if index >= self.len() { + None + } else { + self.drain(index..index + 1).next() + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns false. + /// This method operates in place and preserves the order of the retained + /// elements. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3, 4]); + /// array.retain(|x| *x & 1 != 0 ); + /// assert_eq!(&array[..], &[1, 3]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + // Check the implementation of + // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain + // for safety arguments (especially regarding panics in f and when + // dropping elements). Implementation closely mirrored here. + + let original_len = self.len(); + unsafe { self.set_len(0) }; + + struct BackshiftOnDrop<'a, T: Copy, const CAP: usize> { + v: &'a mut ArrayVecCopy, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, T, CAP> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + unsafe { + ptr::copy( + self.v.as_ptr().add(self.processed_len), + self.v + .as_mut_ptr() + .add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len, + ); + } + } + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); + } + } + } + + let mut g = BackshiftOnDrop { + v: self, + processed_len: 0, + deleted_cnt: 0, + original_len, + }; + + while g.processed_len < original_len { + let cur = unsafe { g.v.as_mut_ptr().add(g.processed_len) }; + if !f(unsafe { &mut *cur }) { + g.processed_len += 1; + g.deleted_cnt += 1; + continue; + } + if g.deleted_cnt > 0 { + unsafe { + let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + } + + drop(g); + } + + /// Set the vector’s length without moving out elements + /// + /// This method is `unsafe` because it changes the notion of the + /// number of “valid” elements in the vector. Use with care. + /// + /// This method uses *debug assertions* to check that `length` is + /// not greater than the capacity. + pub unsafe fn set_len(&mut self, length: usize) { + // type invariant that capacity always fits in LenUint + debug_assert!(length <= self.capacity()); + self.len = length as LenUint; + } + + /// Copy all elements from the slice and append to the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + /// vec.push(1); + /// vec.try_extend_from_slice(&[2, 3]).unwrap(); + /// assert_eq!(&vec[..], &[1, 2, 3]); + /// ``` + /// + /// # Errors + /// + /// This method will return an error if the capacity left (see + /// [`remaining_capacity`]) is smaller then the length of the provided + /// slice. + /// + /// [`remaining_capacity`]: #method.remaining_capacity + pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError> { + if self.remaining_capacity() < other.len() { + return Err(CapacityError::new(())); + } + + let self_len = self.len(); + let other_len = other.len(); + + unsafe { + let dst = self.get_unchecked_ptr(self_len); + ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len); + self.set_len(self_len + other_len); + } + Ok(()) + } + + /// Create a draining iterator that removes the specified range in the vector + /// and yields the removed items from start to end. The element range is + /// removed even if the iterator is not consumed until the end. + /// + /// Note: It is unspecified how many elements are removed from the vector, + /// if the `Drain` value is leaked. + /// + /// **Panics** if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut v1 = ArrayVecCopy::from([1, 2, 3]); + /// let v2: ArrayVecCopy<_, 3> = v1.drain(0..2).collect(); + /// assert_eq!(&v1[..], &[3]); + /// assert_eq!(&v2[..], &[1, 2]); + /// ``` + pub fn drain(&mut self, range: R) -> Drain + where + R: RangeBounds, + { + // Memory safety + // + // When the Drain is first created, it shortens the length of + // the source vector to make sure no uninitialized or moved-from elements + // are accessible at all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, remaining tail of the vec is copied back to cover + // the hole, and the vector length is restored to the new length. + // + let len = self.len(); + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) => i, + Bound::Excluded(&i) => i.saturating_add(1), + }; + let end = match range.end_bound() { + Bound::Excluded(&j) => j, + Bound::Included(&j) => j.saturating_add(1), + Bound::Unbounded => len, + }; + self.drain_range(start, end) + } + + fn drain_range(&mut self, start: usize, end: usize) -> Drain { + let len = self.len(); + + // bounds check happens here (before length is changed!) + let range_slice: *const _ = &self[start..end]; + + // Calling `set_len` creates a fresh and thus unique mutable references, making all + // older aliases we created invalid. So we cannot call that function. + self.len = start as LenUint; + + unsafe { + Drain { + tail_start: end, + tail_len: len - end, + iter: (*range_slice).iter(), + vec: self as *mut _, + } + } + } + + /// Return the inner fixed size array, if it is full to its capacity. + /// + /// Return an `Ok` value with the array if length equals capacity, + /// return an `Err` with self otherwise. + pub fn into_inner(self) -> Result<[T; CAP], Self> { + if self.len() < self.capacity() { + Err(self) + } else { + unsafe { Ok(self.into_inner_unchecked()) } + } + } + + /// Return the inner fixed size array. + /// + /// Safety: + /// This operation is safe if and only if length equals capacity. + pub unsafe fn into_inner_unchecked(self) -> [T; CAP] { + debug_assert_eq!(self.len(), self.capacity()); + let array = ptr::read(self.as_ptr() as *const [T; CAP]); + array + } + + /// Returns the ArrayVecCopy, replacing the original with a new empty ArrayVecCopy. + /// + /// ``` + /// use arrayvec::copy::ArrayVecCopy; + /// + /// let mut v = ArrayVecCopy::from([0, 1, 2, 3]); + /// assert_eq!([0, 1, 2, 3], v.take().into_inner().unwrap()); + /// assert!(v.is_empty()); + /// ``` + pub fn take(&mut self) -> Self { + mem::replace(self, Self::new()) + } + + /// Return a slice containing all elements of the vector. + pub fn as_slice(&self) -> &[T] { + ArrayVecImpl::as_slice(self) + } + + /// Return a mutable slice containing all elements of the vector. + pub fn as_mut_slice(&mut self) -> &mut [T] { + ArrayVecImpl::as_mut_slice(self) + } + + /// Return a raw pointer to the vector's buffer. + pub fn as_ptr(&self) -> *const T { + ArrayVecImpl::as_ptr(self) + } + + /// Return a raw mutable pointer to the vector's buffer. + pub fn as_mut_ptr(&mut self) -> *mut T { + ArrayVecImpl::as_mut_ptr(self) + } +} + +impl ArrayVecImpl for ArrayVecCopy { + type Item = T; + const CAPACITY: usize = CAP; + + fn len(&self) -> usize { + self.len() + } + + unsafe fn set_len(&mut self, length: usize) { + debug_assert!(length <= CAP); + self.len = length as LenUint; + } + + fn as_ptr(&self) -> *const Self::Item { + self.xs.as_ptr() as _ + } + + fn as_mut_ptr(&mut self) -> *mut Self::Item { + self.xs.as_mut_ptr() as _ + } +} + +impl Deref for ArrayVecCopy { + type Target = [T]; + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl DerefMut for ArrayVecCopy { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} + +/// Create an `ArrayVecCopy` from an array. +/// +/// ``` +/// use arrayvec::copy::ArrayVecCopy; +/// +/// let mut array = ArrayVecCopy::from([1, 2, 3]); +/// assert_eq!(array.len(), 3); +/// assert_eq!(array.capacity(), 3); +/// ``` +impl From<[T; CAP]> for ArrayVecCopy { + fn from(array: [T; CAP]) -> Self { + let mut vec = >::new(); + unsafe { + (&array as *const [T; CAP] as *const [MaybeUninit; CAP]) + .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); + vec.set_len(CAP); + } + vec + } +} + +/// Try to create an `ArrayVecCopy` from a slice. This will return an error if the slice was too big to +/// fit. +/// +/// ``` +/// use arrayvec::copy::ArrayVecCopy; +/// use std::convert::TryInto as _; +/// +/// let array: ArrayVecCopy<_, 4> = (&[1, 2, 3] as &[_]).try_into().unwrap(); +/// assert_eq!(array.len(), 3); +/// assert_eq!(array.capacity(), 4); +/// ``` +impl std::convert::TryFrom<&[T]> for ArrayVecCopy { + type Error = CapacityError; + + fn try_from(slice: &[T]) -> Result { + if Self::CAPACITY < slice.len() { + Err(CapacityError::new(())) + } else { + let mut array = Self::new(); + array.extend_from_slice(slice); + Ok(array) + } + } +} + +/// Iterate the `ArrayVecCopy` with references to each element. +/// +/// ``` +/// use arrayvec::copy::ArrayVecCopy; +/// +/// let array = ArrayVecCopy::from([1, 2, 3]); +/// +/// for elt in &array { +/// // ... +/// } +/// ``` +impl<'a, T: Copy + 'a, const CAP: usize> IntoIterator for &'a ArrayVecCopy { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// Iterate the `ArrayVecCopy` with mutable references to each element. +/// +/// ``` +/// use arrayvec::copy::ArrayVecCopy; +/// +/// let mut array = ArrayVecCopy::from([1, 2, 3]); +/// +/// for elt in &mut array { +/// // ... +/// } +/// ``` +impl<'a, T: Copy + 'a, const CAP: usize> IntoIterator for &'a mut ArrayVecCopy { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +/// Iterate the `ArrayVecCopy` with each element by value. +/// +/// The vector is consumed by this operation. +/// +/// ``` +/// use arrayvec::copy::ArrayVecCopy; +/// +/// for elt in ArrayVecCopy::from([1, 2, 3]) { +/// // ... +/// } +/// ``` +impl IntoIterator for ArrayVecCopy { + type Item = T; + type IntoIter = IntoIter; + fn into_iter(self) -> IntoIter { + IntoIter { index: 0, v: self } + } +} + +/// By-value iterator for `ArrayVecCopy`. +pub struct IntoIter { + index: usize, + v: ArrayVecCopy, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + if self.index == self.v.len() { + None + } else { + unsafe { + let index = self.index; + self.index = index + 1; + Some(ptr::read(self.v.get_unchecked_ptr(index))) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.v.len() - self.index; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + if self.index == self.v.len() { + None + } else { + unsafe { + let new_len = self.v.len() - 1; + self.v.set_len(new_len); + Some(ptr::read(self.v.get_unchecked_ptr(new_len))) + } + } + } +} + +impl ExactSizeIterator for IntoIter {} + +impl Clone for IntoIter { + fn clone(&self) -> IntoIter { + let mut v = ArrayVecCopy::new(); + v.extend_from_slice(&self.v[self.index..]); + v.into_iter() + } +} + +impl fmt::Debug for IntoIter +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(&self.v[self.index..]).finish() + } +} + +/// A draining iterator for `ArrayVecCopy`. +pub struct Drain<'a, T: Copy + 'a, const CAP: usize> { + /// Index of tail to preserve + tail_start: usize, + /// Length of tail + tail_len: usize, + /// Current remaining range to remove + iter: slice::Iter<'a, T>, + vec: *mut ArrayVecCopy, +} + +unsafe impl<'a, T: Copy + Sync, const CAP: usize> Sync for Drain<'a, T, CAP> {} +unsafe impl<'a, T: Copy + Send, const CAP: usize> Send for Drain<'a, T, CAP> {} + +impl<'a, T: Copy + 'a, const CAP: usize> Iterator for Drain<'a, T, CAP> { + type Item = T; + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, T: Copy + 'a, const CAP: usize> DoubleEndedIterator for Drain<'a, T, CAP> { + fn next_back(&mut self) -> Option { + self.iter + .next_back() + .map(|elt| unsafe { ptr::read(elt as *const _) }) + } +} + +impl<'a, T: Copy + 'a, const CAP: usize> ExactSizeIterator for Drain<'a, T, CAP> {} + +impl<'a, T: Copy + 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { + fn drop(&mut self) { + // len is currently 0 so panicking while dropping will not cause a double drop. + + // exhaust self first + while let Some(_) = self.next() {} + + if self.tail_len > 0 { + unsafe { + let source_vec = &mut *self.vec; + // memmove back untouched tail, update to new length + let start = source_vec.len(); + let tail = self.tail_start; + let src = source_vec.as_ptr().add(tail); + let dst = source_vec.as_mut_ptr().add(start); + ptr::copy(src, dst, self.tail_len); + source_vec.set_len(start + self.tail_len); + } + } + } +} + +struct ScopeExitGuard +where + F: FnMut(&Data, &mut T), +{ + value: T, + data: Data, + f: F, +} + +impl Drop for ScopeExitGuard +where + F: FnMut(&Data, &mut T), +{ + fn drop(&mut self) { + (self.f)(&self.data, &mut self.value) + } +} + +/// Extend the `ArrayVecCopy` with an iterator. +/// +/// ***Panics*** if extending the vector exceeds its capacity. +impl Extend for ArrayVecCopy { + /// Extend the `ArrayVecCopy` with an iterator. + /// + /// ***Panics*** if extending the vector exceeds its capacity. + fn extend>(&mut self, iter: I) { + unsafe { self.extend_from_iter::<_, true>(iter) } + } +} + +#[inline(never)] +#[cold] +fn extend_panic() { + panic!("ArrayVecCopy: capacity exceeded in extend/from_iter"); +} + +impl ArrayVecCopy { + /// Extend the arrayvec from the iterable. + /// + /// ## Safety + /// + /// Unsafe because if CHECK is false, the length of the input is not checked. + /// The caller must ensure the length of the input fits in the capacity. + pub(crate) unsafe fn extend_from_iter(&mut self, iterable: I) + where + I: IntoIterator, + { + if mem::size_of::() == 0 { + let capacity = self.capacity(); + + let mut iter = iterable.into_iter(); + loop { + if iter.next().is_some() { + if self.len as usize == capacity && CHECK { + extend_panic(); + } + debug_assert_ne!(self.len as usize, capacity); + self.len += 1; + } else { + return; // success + } + } + } else { + let take = self.capacity() - self.len(); + let len = self.len(); + let mut ptr = self.as_mut_ptr().add(len); + let end_ptr = ptr.add(take); + // Keep the length in a separate variable, write it back on scope + // exit. To help the compiler with alias analysis and stuff. + // We update the length to handle panic in the iteration of the + // user's iterator, without dropping any elements on the floor. + let mut guard = ScopeExitGuard { + value: &mut self.len, + data: len, + f: move |&len, self_len| { + **self_len = len as LenUint; + }, + }; + let mut iter = iterable.into_iter(); + loop { + if let Some(elt) = iter.next() { + if ptr == end_ptr && CHECK { + extend_panic(); + } + debug_assert_ne!(ptr, end_ptr); + ptr.write(elt); + ptr = ptr.add(1); + guard.data += 1; + } else { + return; // success + } + } + } + } + + /// Extend the ArrayVecCopy with clones of elements from the slice; + /// the length of the slice must be <= the remaining capacity in the arrayvec. + pub(crate) fn extend_from_slice(&mut self, slice: &[T]) { + let take = self.capacity() - self.len(); + debug_assert!(slice.len() <= take); + unsafe { + let slice = if take < slice.len() { + &slice[..take] + } else { + slice + }; + self.extend_from_iter::<_, false>(slice.iter().cloned()); + } + } +} + +/// Create an `ArrayVecCopy` from an iterator. +/// +/// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. +impl iter::FromIterator for ArrayVecCopy { + /// Create an `ArrayVecCopy` from an iterator. + /// + /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. + fn from_iter>(iter: I) -> Self { + let mut array = ArrayVecCopy::new(); + array.extend(iter); + array + } +} + +impl Clone for ArrayVecCopy { + fn clone(&self) -> Self { + self.iter().cloned().collect() + } + + fn clone_from(&mut self, rhs: &Self) { + // recursive case for the common prefix + let prefix = cmp::min(self.len(), rhs.len()); + self[..prefix].clone_from_slice(&rhs[..prefix]); + + if prefix < self.len() { + // rhs was shorter + self.truncate(prefix); + } else { + let rhs_elems = &rhs[self.len()..]; + self.extend_from_slice(rhs_elems); + } + } +} + +impl Hash for ArrayVecCopy +where + T: Hash, +{ + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} + +impl PartialEq for ArrayVecCopy +where + T: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl PartialEq<[T]> for ArrayVecCopy +where + T: PartialEq, +{ + fn eq(&self, other: &[T]) -> bool { + **self == *other + } +} + +impl Eq for ArrayVecCopy where T: Eq {} + +impl Borrow<[T]> for ArrayVecCopy { + fn borrow(&self) -> &[T] { + self + } +} + +impl BorrowMut<[T]> for ArrayVecCopy { + fn borrow_mut(&mut self) -> &mut [T] { + self + } +} + +impl AsRef<[T]> for ArrayVecCopy { + fn as_ref(&self) -> &[T] { + self + } +} + +impl AsMut<[T]> for ArrayVecCopy { + fn as_mut(&mut self) -> &mut [T] { + self + } +} + +impl fmt::Debug for ArrayVecCopy +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} + +impl Default for ArrayVecCopy { + /// Return an empty array + fn default() -> ArrayVecCopy { + ArrayVecCopy::new() + } +} + +impl PartialOrd for ArrayVecCopy +where + T: PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + (**self).partial_cmp(other) + } + + fn lt(&self, other: &Self) -> bool { + (**self).lt(other) + } + + fn le(&self, other: &Self) -> bool { + (**self).le(other) + } + + fn ge(&self, other: &Self) -> bool { + (**self).ge(other) + } + + fn gt(&self, other: &Self) -> bool { + (**self).gt(other) + } +} + +impl Ord for ArrayVecCopy +where + T: Ord, +{ + fn cmp(&self, other: &Self) -> cmp::Ordering { + (**self).cmp(other) + } +} + +#[cfg(feature = "std")] +/// `Write` appends written data to the end of the vector. +/// +/// Requires `features="std"`. +impl io::Write for ArrayVecCopy { + fn write(&mut self, data: &[u8]) -> io::Result { + let len = cmp::min(self.remaining_capacity(), data.len()); + let _result = self.try_extend_from_slice(&data[..len]); + debug_assert!(_result.is_ok()); + Ok(len) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "serde")] +/// Requires crate feature `"serde"` +impl Serialize for ArrayVecCopy { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } +} + +#[cfg(feature = "serde")] +/// Requires crate feature `"serde"` +impl<'de, T: Copy + Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVecCopy { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::{Error, SeqAccess, Visitor}; + use std::marker::PhantomData; + + struct ArrayVecCopyVisitor<'de, T: Copy + Deserialize<'de>, const CAP: usize>( + PhantomData<(&'de (), [T; CAP])>, + ); + + impl<'de, T: Copy + Deserialize<'de>, const CAP: usize> Visitor<'de> + for ArrayVecCopyVisitor<'de, T, CAP> + { + type Value = ArrayVecCopy; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "an array with no more than {} items", CAP) + } + + fn visit_seq(self, mut seq: SA) -> Result + where + SA: SeqAccess<'de>, + { + let mut values = ArrayVecCopy::::new(); + + while let Some(value) = seq.next_element()? { + if let Err(_) = values.try_push(value) { + return Err(SA::Error::invalid_length(CAP + 1, &self)); + } + } + + Ok(values) + } + } + + deserializer.deserialize_seq(ArrayVecCopyVisitor::(PhantomData)) + } +} diff --git a/src/lib.rs b/src/lib.rs index f9a2fe6..458645c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,3 +61,10 @@ pub use crate::array_string::ArrayString; pub use crate::errors::CapacityError; pub use crate::arrayvec::{ArrayVec, IntoIter, Drain}; + +#[cfg(feature = "copy")] +mod arrayvec_copy; +#[cfg(feature = "copy")] +pub mod copy { + pub use crate::arrayvec_copy::{ArrayVecCopy, IntoIter, Drain}; +} diff --git a/tests/tests_copy.rs b/tests/tests_copy.rs new file mode 100644 index 0000000..7329bf7 --- /dev/null +++ b/tests/tests_copy.rs @@ -0,0 +1,432 @@ +#[allow(unused)] +#[macro_use] +extern crate matches; + +#[cfg(feature = "copy")] +mod copy_tests { + extern crate arrayvec; + + use arrayvec::copy::ArrayVecCopy; + use arrayvec::CapacityError; + use std::mem; + + #[test] + fn test_simple() { + let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + + vec.push(4); + vec.push(10); + vec.push(11); + + let real_vec: Vec = vec![4, 10, 11]; + + for (elt, vec_elt) in vec.iter().zip(real_vec.iter()) { + assert_eq!(elt, vec_elt); + } + + assert_eq!(*vec, *real_vec); + } + + #[test] + fn test_capacity_left() { + let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + assert_eq!(vec.remaining_capacity(), 4); + vec.push(1); + assert_eq!(vec.remaining_capacity(), 3); + vec.push(2); + assert_eq!(vec.remaining_capacity(), 2); + vec.push(3); + assert_eq!(vec.remaining_capacity(), 1); + vec.push(4); + assert_eq!(vec.remaining_capacity(), 0); + } + + #[test] + fn test_extend_from_slice() { + let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + + vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); + assert_eq!(vec.len(), 3); + assert_eq!(&vec[..], &[1, 2, 3]); + assert_eq!(vec.pop(), Some(3)); + assert_eq!(&vec[..], &[1, 2]); + } + + #[test] + fn test_extend_from_slice_error() { + let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + + vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); + let res = vec.try_extend_from_slice(&[0; 8]); + assert_matches!(res, Err(_)); + + let mut vec: ArrayVecCopy = ArrayVecCopy::new(); + let res = vec.try_extend_from_slice(&[0; 1]); + assert_matches!(res, Err(_)); + } + + #[test] + fn test_try_from_slice_error() { + use std::convert::TryInto as _; + + let res: Result, _> = (&[1, 2, 3] as &[_]).try_into(); + assert_matches!(res, Err(_)); + } + + #[test] + fn test_u16_index() { + const N: usize = 4096; + let mut vec: ArrayVecCopy<_, N> = ArrayVecCopy::new(); + for _ in 0..N { + assert!(vec.try_push(1u8).is_ok()); + } + assert!(vec.try_push(0).is_err()); + assert_eq!(vec.len(), N); + } + + #[test] + fn test_iter() { + let mut iter = ArrayVecCopy::from([1, 2, 3]).into_iter(); + assert_eq!(iter.size_hint(), (3, Some(3))); + assert_eq!(iter.next_back(), Some(3)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next_back(), Some(2)); + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next_back(), None); + } + + #[test] + fn test_extend() { + let mut range = 0..10; + + let mut array: ArrayVecCopy<_, 5> = range.by_ref().take(5).collect(); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); + assert_eq!(range.next(), Some(5)); + + array.extend(range.by_ref().take(0)); + assert_eq!(range.next(), Some(6)); + + let mut array: ArrayVecCopy<_, 10> = (0..3).collect(); + assert_eq!(&array[..], &[0, 1, 2]); + array.extend(3..5); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); + } + + #[should_panic] + #[test] + fn test_extend_capacity_panic_1() { + let mut range = 0..10; + + let _: ArrayVecCopy<_, 5> = range.by_ref().collect(); + } + + #[should_panic] + #[test] + fn test_extend_capacity_panic_2() { + let mut range = 0..10; + + let mut array: ArrayVecCopy<_, 5> = range.by_ref().take(5).collect(); + assert_eq!(&array[..], &[0, 1, 2, 3, 4]); + assert_eq!(range.next(), Some(5)); + array.extend(range.by_ref().take(1)); + } + + #[test] + fn test_is_send_sync() { + let data = ArrayVecCopy::::new(); + &data as &dyn Send; + &data as &dyn Sync; + } + + #[test] + fn test_compact_size() { + // 4 bytes + padding + length + type ByteArray = ArrayVecCopy; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= 2 * mem::size_of::()); + + // just length + type EmptyArray = ArrayVecCopy; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= mem::size_of::()); + + // 3 elements + padding + length + type QuadArray = ArrayVecCopy; + println!("{}", mem::size_of::()); + assert!(mem::size_of::() <= 4 * 4 + mem::size_of::()); + } + + #[test] + fn test_still_works_with_option_arrayvec() { + type RefArray = ArrayVecCopy<&'static i32, 2>; + let array = Some(RefArray::new()); + assert!(array.is_some()); + println!("{:?}", array); + } + + #[test] + fn test_drain() { + let mut v = ArrayVecCopy::from([0; 8]); + v.pop(); + v.drain(0..7); + assert_eq!(&v[..], &[]); + + v.extend(0..8); + v.drain(1..4); + assert_eq!(&v[..], &[0, 4, 5, 6, 7]); + let u: ArrayVecCopy<_, 3> = v.drain(1..4).rev().collect(); + assert_eq!(&u[..], &[6, 5, 4]); + assert_eq!(&v[..], &[0, 7]); + v.drain(..); + assert_eq!(&v[..], &[]); + } + + #[test] + fn test_drain_range_inclusive() { + let mut v = ArrayVecCopy::from([0; 8]); + v.drain(0..=7); + assert_eq!(&v[..], &[]); + + v.extend(0..8); + v.drain(1..=4); + assert_eq!(&v[..], &[0, 5, 6, 7]); + let u: ArrayVecCopy<_, 3> = v.drain(1..=2).rev().collect(); + assert_eq!(&u[..], &[6, 5]); + assert_eq!(&v[..], &[0, 7]); + v.drain(..); + assert_eq!(&v[..], &[]); + } + + #[test] + #[should_panic] + fn test_drain_range_inclusive_oob() { + let mut v = ArrayVecCopy::from([0; 0]); + v.drain(0..=0); + } + + #[test] + fn test_retain() { + let mut v = ArrayVecCopy::from([0; 8]); + for (i, elt) in v.iter_mut().enumerate() { + *elt = i; + } + v.retain(|_| true); + assert_eq!(&v[..], &[0, 1, 2, 3, 4, 5, 6, 7]); + v.retain(|elt| { + *elt /= 2; + *elt % 2 == 0 + }); + assert_eq!(&v[..], &[0, 0, 2, 2]); + v.retain(|_| false); + assert_eq!(&v[..], &[]); + } + + #[test] + #[should_panic] + fn test_drain_oob() { + let mut v = ArrayVecCopy::from([0; 8]); + v.pop(); + v.drain(0..8); + } + + #[test] + fn test_insert() { + let mut v = ArrayVecCopy::from([]); + assert_matches!(v.try_push(1), Err(_)); + + let mut v = ArrayVecCopy::<_, 3>::new(); + v.insert(0, 0); + v.insert(1, 1); + //let ret1 = v.try_insert(3, 3); + //assert_matches!(ret1, Err(InsertError::OutOfBounds(_))); + assert_eq!(&v[..], &[0, 1]); + v.insert(2, 2); + assert_eq!(&v[..], &[0, 1, 2]); + + let ret2 = v.try_insert(1, 9); + assert_eq!(&v[..], &[0, 1, 2]); + assert_matches!(ret2, Err(_)); + + let mut v = ArrayVecCopy::from([2]); + assert_matches!(v.try_insert(0, 1), Err(CapacityError { .. })); + assert_matches!(v.try_insert(1, 1), Err(CapacityError { .. })); + //assert_matches!(v.try_insert(2, 1), Err(CapacityError { .. })); + } + + #[test] + fn test_into_inner_1() { + let mut v = ArrayVecCopy::from([1, 2]); + v.pop(); + let u = v.clone(); + assert_eq!(v.into_inner(), Err(u)); + } + + #[test] + fn test_into_inner_2() { + let mut v = ArrayVecCopy::::new(); + v.push('a'); + v.push('b'); + v.push('c'); + v.push('d'); + assert_eq!(v.into_inner().unwrap(), ['a', 'b', 'c', 'd']); + } + + #[test] + fn test_into_inner_3() { + let mut v = ArrayVecCopy::::new(); + v.extend(1..=4); + assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]); + } + + #[test] + fn test_take() { + let mut v1 = ArrayVecCopy::::new(); + v1.extend(1..=4); + let v2 = v1.take(); + assert!(v1.into_inner().is_err()); + assert_eq!(v2.into_inner().unwrap(), [1, 2, 3, 4]); + } + + #[cfg(feature = "std")] + #[test] + fn test_write() { + use std::io::Write; + let mut v = ArrayVecCopy::<_, 8>::new(); + write!(&mut v, "\x01\x02\x03").unwrap(); + assert_eq!(&v[..], &[1, 2, 3]); + let r = v.write(&[9; 16]).unwrap(); + assert_eq!(r, 5); + assert_eq!(&v[..], &[1, 2, 3, 9, 9, 9, 9, 9]); + } + + #[test] + fn array_clone_from() { + let mut v = ArrayVecCopy::::new(); + v.push(1); + v.push(5); + v.push(6); + let reference = v.to_vec(); + let mut u = ArrayVecCopy::::new(); + u.clone_from(&v); + assert_eq!(&u, &reference[..]); + + let mut t = ArrayVecCopy::::new(); + t.push(97); + t.push(0); + t.push(5); + t.push(2); + t.clone_from(&v); + assert_eq!(&t, &reference[..]); + t.clear(); + t.clone_from(&v); + assert_eq!(&t, &reference[..]); + } + + #[test] + fn test_insert_at_length() { + let mut v = ArrayVecCopy::<_, 8>::new(); + let result1 = v.try_insert(0, "a"); + let result2 = v.try_insert(1, "b"); + assert!(result1.is_ok() && result2.is_ok()); + assert_eq!(&v[..], &["a", "b"]); + } + + #[should_panic] + #[test] + fn test_insert_out_of_bounds() { + let mut v = ArrayVecCopy::<_, 8>::new(); + let _ = v.try_insert(1, "test"); + } + + #[test] + fn test_pop_at() { + let mut v = ArrayVecCopy::<&'static str, 4>::new(); + v.push("a"); + v.push("b"); + v.push("c"); + v.push("d"); + + assert_eq!(v.pop_at(4), None); + assert_eq!(v.pop_at(1), Some("b")); + assert_eq!(v.pop_at(1), Some("c")); + assert_eq!(v.pop_at(2), None); + assert_eq!(&v[..], &["a", "d"]); + } + + #[test] + fn test_sizes() { + let v = ArrayVecCopy::from([0u8; 1 << 16]); + assert_eq!(vec![0u8; v.len()], &v[..]); + } + + #[cfg(feature = "array-sizes-33-128")] + #[test] + fn test_sizes_33_128() { + ArrayVecCopy::from([0u8; 52]); + ArrayVecCopy::from([0u8; 127]); + } + + #[cfg(feature = "array-sizes-129-255")] + #[test] + fn test_sizes_129_255() { + ArrayVecCopy::from([0u8; 237]); + ArrayVecCopy::from([0u8; 255]); + } + + #[test] + fn test_extend_zst() { + let mut range = 0..10; + #[derive(Copy, Clone, PartialEq, Debug)] + struct Z; // Zero sized type + + let mut array: ArrayVecCopy<_, 5> = range.by_ref().take(5).map(|_| Z).collect(); + assert_eq!(&array[..], &[Z; 5]); + assert_eq!(range.next(), Some(5)); + + array.extend(range.by_ref().take(0).map(|_| Z)); + assert_eq!(range.next(), Some(6)); + + let mut array: ArrayVecCopy<_, 10> = (0..3).map(|_| Z).collect(); + assert_eq!(&array[..], &[Z; 3]); + array.extend((3..5).map(|_| Z)); + assert_eq!(&array[..], &[Z; 5]); + assert_eq!(array.len(), 5); + } + + #[test] + fn allow_max_capacity_arrayvec_type() { + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVecCopy<(), { usize::MAX }>; + } + + #[should_panic(expected = "largest supported capacity")] + #[test] + fn deny_max_capacity_arrayvec_value() { + if mem::size_of::() <= mem::size_of::() { + panic!("This test does not work on this platform. 'largest supported capacity'"); + } + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVecCopy<(), { usize::MAX }> = ArrayVecCopy::new(); + } + + #[should_panic(expected = "index out of bounds")] + #[test] + fn deny_max_capacity_arrayvec_value_const() { + if mem::size_of::() <= mem::size_of::() { + panic!("This test does not work on this platform. 'index out of bounds'"); + } + // this type is allowed to be used (but can't be constructed) + let _v: ArrayVecCopy<(), { usize::MAX }> = ArrayVecCopy::new_const(); + } + + #[test] + fn test_arrayvec_const_constructible() { + const OF_U8: ArrayVecCopy = ArrayVecCopy::new_const(); + + let mut var = OF_U8; + assert!(var.is_empty()); + assert_eq!(var, ArrayVecCopy::new()); + var.push(3); + assert_eq!(var[..], [3]); + } +}