From 5caad4c71f83a519e6494db193a6949522520b83 Mon Sep 17 00:00:00 2001 From: nitram Date: Thu, 17 Oct 2024 16:13:01 +0200 Subject: [PATCH 1/6] Add `ArrayVecCopy` Fixes #32. --- src/arrayvec_copy.rs | 1355 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 6 + 2 files changed, 1361 insertions(+) create mode 100644 src/arrayvec_copy.rs diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs new file mode 100644 index 0000000..d36e5fb --- /dev/null +++ b/src/arrayvec_copy.rs @@ -0,0 +1,1355 @@ + +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::hash::{Hash, Hasher}; +use std::fmt; + +#[cfg(feature="std")] +use std::io; + +use std::mem::MaybeUninit; + +#[cfg(feature="serde")] +use serde::{Serialize, Deserialize, Serializer, Deserializer}; + +use crate::LenUint; +use crate::errors::CapacityError; +use crate::arrayvec_impl::ArrayVecImpl; +use crate::utils::MakeMaybeUninit; + +/// 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` (or `u16::MAX` on 16-bit targets); +/// 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. +#[repr(C)] +pub struct ArrayVecCopy { + len: LenUint, + // the `len` first elements of the array are initialized + xs: [MaybeUninit; CAP], +} + +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::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 16>::new(); + /// array.push(1); + /// array.push(2); + /// assert_eq!(&array[..], &[1, 2]); + /// assert_eq!(array.capacity(), 16); + /// ``` + #[inline] + #[track_caller] + 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::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::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.len(), 2); + /// ``` + #[inline(always)] + pub const fn len(&self) -> usize { self.len as usize } + + /// Returns whether the `ArrayVecCopy` is empty. + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1]); + /// array.pop(); + /// assert_eq!(array.is_empty(), true); + /// ``` + #[inline] + pub const fn is_empty(&self) -> bool { self.len() == 0 } + + /// Return the capacity of the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// let array = ArrayVecCopy::from([1, 2, 3]); + /// assert_eq!(array.capacity(), 3); + /// ``` + #[inline(always)] + pub const fn capacity(&self) -> usize { CAP } + + /// Return true if the `ArrayVecCopy` is completely filled to its capacity, false otherwise. + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 1>::new(); + /// assert!(!array.is_full()); + /// array.push(1); + /// assert!(array.is_full()); + /// ``` + pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + + /// Returns the capacity left in the `ArrayVecCopy`. + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::from([1, 2, 3]); + /// array.pop(); + /// assert_eq!(array.remaining_capacity(), 1); + /// ``` + pub const 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::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// array.push(1); + /// array.push(2); + /// + /// assert_eq!(&array[..], &[1, 2]); + /// ``` + #[track_caller] + 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::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::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::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::ArrayVecCopy; + /// + /// let mut array = ArrayVecCopy::<_, 2>::new(); + /// + /// array.insert(0, "x"); + /// array.insert(0, "y"); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + #[track_caller] + 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::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::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::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::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::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::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::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 }; + + #[inline(always)] + fn process_one bool, const CAP: usize, const DELETED: bool>( + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, CAP> + ) -> bool { + 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; + return false; + } + if DELETED { + unsafe { + let hole_slot = cur.sub(g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + true + } + + // Stage 1: Nothing was deleted. + while g.processed_len != original_len { + if !process_one::(&mut f, &mut g) { + break; + } + } + + // Stage 2: Some elements were deleted. + while g.processed_len != original_len { + process_one::(&mut f, &mut g); + } + + drop(g); + } + + /// Returns the remaining spare capacity of the vector as a slice of + /// `MaybeUninit`. + /// + /// The returned slice can be used to fill the vector with data (e.g. by + /// reading from a file) before marking the data as initialized using the + /// [`set_len`] method. + /// + /// [`set_len`]: ArrayVecCopy::set_len + /// + /// # Examples + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// // Allocate vector big enough for 10 elements. + /// let mut v: ArrayVecCopy = ArrayVecCopy::new(); + /// + /// // Fill in the first 3 elements. + /// let uninit = v.spare_capacity_mut(); + /// uninit[0].write(0); + /// uninit[1].write(1); + /// uninit[2].write(2); + /// + /// // Mark the first 3 elements of the vector as being initialized. + /// unsafe { + /// v.set_len(3); + /// } + /// + /// assert_eq!(&v[..], &[0, 1, 2]); + /// ``` + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + let len = self.len(); + &mut self.xs[len..] + } + + /// 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::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> + where T: Copy, + { + 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::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::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::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 { + #[track_caller] + 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::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 + where T: Clone, +{ + 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::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::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::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, } + } +} + + +#[cfg(feature = "zeroize")] +/// "Best efforts" zeroing of the `ArrayVecCopy`'s buffer when the `zeroize` feature is enabled. +/// +/// The length is set to 0, and the buffer is dropped and zeroized. +/// Cannot ensure that previous moves of the `ArrayVecCopy` did not leave values on the stack. +/// +/// ``` +/// use arrayvec::ArrayVecCopy; +/// use zeroize::Zeroize; +/// let mut array = ArrayVecCopy::from([1, 2, 3]); +/// array.zeroize(); +/// assert_eq!(array.len(), 0); +/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; +/// assert_eq!(data, [0, 0, 0]); +/// ``` +impl zeroize::Zeroize for ArrayVecCopy { + fn zeroize(&mut self) { + // Zeroize all the contained elements. + self.iter_mut().zeroize(); + // Drop all the elements and set the length to 0. + self.clear(); + // Zeroize the backing array. + self.xs.zeroize(); + } +} + +/// By-value iterator for `ArrayVecCopy`. +pub struct IntoIter { + index: usize, + v: ArrayVecCopy, +} +impl IntoIter { + /// Returns the remaining items of this iterator as a slice. + pub fn as_slice(&self) -> &[T] { + &self.v[self.index..] + } + + /// Returns the remaining items of this iterator as a mutable slice. + pub fn as_mut_slice(&mut self) -> &mut [T] { + &mut self.v[self.index..] + } +} + +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 +where T: Clone, +{ + 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 ptr = source_vec.as_mut_ptr(); + ptr::copy(ptr.add(tail), ptr.add(start), 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. + #[track_caller] + fn extend>(&mut self, iter: I) { + unsafe { + self.extend_from_iter::<_, true>(iter) + } + } +} + +#[inline(never)] +#[cold] +#[track_caller] +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. + #[track_caller] + pub(crate) unsafe fn extend_from_iter(&mut self, iterable: I) + where I: IntoIterator + { + let take = self.capacity() - self.len(); + let len = self.len(); + let mut ptr = raw_ptr_add(self.as_mut_ptr(), len); + let end_ptr = raw_ptr_add(ptr, 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); + if mem::size_of::() != 0 { + ptr.write(elt); + } + ptr = raw_ptr_add(ptr, 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]) + where T: Clone + { + 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()); + } + } +} + +/// Rawptr add but uses arithmetic distance for ZST +unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { + if mem::size_of::() == 0 { + // Special case for ZST + ptr.cast::().wrapping_add(offset).cast::() + } else { + ptr.add(offset) + } +} + +/// 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 + where T: Clone +{ + 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::{Visitor, SeqAccess, Error}; + 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)) + } +} + +#[cfg(feature = "borsh")] +/// Requires crate feature `"borsh"` +impl borsh::BorshSerialize for ArrayVecCopy +where + T: borsh::BorshSerialize, +{ + fn serialize(&self, writer: &mut W) -> borsh::io::Result<()> { + <[T] as borsh::BorshSerialize>::serialize(self.as_slice(), writer) + } +} + +#[cfg(feature = "borsh")] +/// Requires crate feature `"borsh"` +impl borsh::BorshDeserialize for ArrayVecCopy +where + T: borsh::BorshDeserialize, +{ + fn deserialize_reader(reader: &mut R) -> borsh::io::Result { + let mut values = Self::new(); + let len = ::deserialize_reader(reader)?; + for _ in 0..len { + let elem = ::deserialize_reader(reader)?; + if let Err(_) = values.try_push(elem) { + return Err(borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + format!("Expected an array with no more than {} items", CAP), + )); + } + } + + Ok(values) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5c4bcee..8e8c1a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ macro_rules! assert_capacity_limit_const { } } +mod arrayvec_copy; mod arrayvec_impl; mod arrayvec; mod array_string; @@ -64,6 +65,11 @@ mod char; mod errors; mod utils; +pub mod copy { + pub use crate::arrayvec_copy::{Drain, IntoIter}; +} + +pub use crate::arrayvec_copy::ArrayVecCopy; pub use crate::array_string::ArrayString; pub use crate::errors::CapacityError; From 33f89bc73a5e3b534efd8f722fabd48215b5b572 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 17 Oct 2024 16:27:56 +0200 Subject: [PATCH 2/6] Add infrastructure to generate `src/arrayvec_copy.rs` It works by replacing a couple of strings in `src/arrayvec.rs` and then applying a small patch. Check that the patch is up-to-date in CI. --- .github/workflows/ci.yml | 13 ++++ generate_arrayvec_copy | 36 +++++++++ src/arrayvec_copy.patch | 160 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100755 generate_arrayvec_copy create mode 100644 src/arrayvec_copy.patch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a390ff5..b52da37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,3 +92,16 @@ jobs: cargo miri setup - name: Test with Miri run: cargo miri test --all-features + + check-generated: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Regenerate src/arrayvec_copy.rs + run: | + rm src/arrayvec_copy.rs + ./generate_arrayvec_copy + - name: Verify that nothing has changed + run: | + git diff + test -z "$(git status --porcelain)" diff --git a/generate_arrayvec_copy b/generate_arrayvec_copy new file mode 100755 index 0000000..bf3b150 --- /dev/null +++ b/generate_arrayvec_copy @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -o errexit +set -o nounset +set -o pipefail + +sed \ + -e "s/\\/ArrayVecCopy/g" \ + -e "s/\\/ArrayVecCopyVisitor/g" \ + -e "s/impl<\\('[A-Za-z_]*, \\)\\?T:/impl<\\1T: Copy +/g" \ + -e "s/impl<\\('[A-Za-z_]*, \\)\\?T,/impl<\\1T: Copy,/g" \ + -e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/struct \\1<\\2T: Copy +/g" \ + -e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/struct \\1<\\2T: Copy,/g" \ + -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/fn \\1<\\2T: Copy +/g" \ + -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/fn \\1<\\2T: Copy,/g" \ + src/arrayvec.rs \ + > src/arrayvec_copy_generated.rs + +trap "rm src/arrayvec_copy_generated.rs" EXIT + +if [ -e src/arrayvec_copy.patch ]; then + if [ -e src/arrayvec_copy.rs ]; then + echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs exist." > /dev/stderr + echo "Delete one of them and start again." > /dev/stderr + exit 1 + else + patch -o src/arrayvec_copy.rs src/arrayvec_copy_generated.rs src/arrayvec_copy.patch > /dev/null + fi +else + if [ -e src/arrayvec_copy.rs ]; then + git diff --no-index src/arrayvec_copy_generated.rs src/arrayvec_copy.rs > src/arrayvec_copy.patch || true + else + echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs are missing." > /dev/stderr + echo "One of them is needed to generate the other." > /dev/stderr + exit 1 + fi +fi diff --git a/src/arrayvec_copy.patch b/src/arrayvec_copy.patch new file mode 100644 index 0000000..989a69d --- /dev/null +++ b/src/arrayvec_copy.patch @@ -0,0 +1,160 @@ +diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs +index 6719868..d36e5fb 100644 +--- a/src/arrayvec_copy_generated.rs ++++ b/src/arrayvec_copy.rs +@@ -14,7 +14,6 @@ use std::fmt; + #[cfg(feature="std")] + use std::io; + +-use std::mem::ManuallyDrop; + use std::mem::MaybeUninit; + + #[cfg(feature="serde")] +@@ -25,7 +24,7 @@ use crate::errors::CapacityError; + use crate::arrayvec_impl::ArrayVecImpl; + use crate::utils::MakeMaybeUninit; + +-/// A vector with a fixed capacity. ++/// 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 +@@ -46,14 +45,6 @@ pub struct ArrayVecCopy { + xs: [MaybeUninit; CAP], + } + +-impl Drop for ArrayVecCopy { +- fn drop(&mut self) { +- self.clear(); +- +- // MaybeUninit inhibits array's drop +- } +-} +- + 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 {}"), +@@ -231,8 +222,7 @@ impl ArrayVecCopy { + ArrayVecImpl::push_unchecked(self, element) + } + +- /// Shortens the vector, keeping the first `len` elements and dropping +- /// the rest. ++ /// Shortens the vector, keeping the first `len` elements. + /// + /// If `len` is greater than the vector’s current length this has no + /// effect. +@@ -499,7 +489,7 @@ impl ArrayVecCopy { + let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; + + #[inline(always)] +- fn process_one bool, T, const CAP: usize, const DELETED: bool>( ++ fn process_one bool, const CAP: usize, const DELETED: bool>( + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, CAP> + ) -> bool { +@@ -507,7 +497,6 @@ impl ArrayVecCopy { + if !f(unsafe { &mut *cur }) { + g.processed_len += 1; + g.deleted_cnt += 1; +- unsafe { ptr::drop_in_place(cur) }; + return false; + } + if DELETED { +@@ -522,14 +511,14 @@ impl ArrayVecCopy { + + // Stage 1: Nothing was deleted. + while g.processed_len != original_len { +- if !process_one::(&mut f, &mut g) { ++ if !process_one::(&mut f, &mut g) { + break; + } + } + + // Stage 2: Some elements were deleted. + while g.processed_len != original_len { +- process_one::(&mut f, &mut g); ++ process_one::(&mut f, &mut g); + } + + drop(g); +@@ -570,7 +559,7 @@ impl ArrayVecCopy { + &mut self.xs[len..] + } + +- /// Set the vector’s length without dropping or moving out elements ++ /// 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. +@@ -703,8 +692,7 @@ impl ArrayVecCopy { + /// 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 self_ = ManuallyDrop::new(self); +- let array = ptr::read(self_.as_ptr() as *const [T; CAP]); ++ let array = ptr::read(self.as_ptr() as *const [T; CAP]); + array + } + +@@ -790,10 +778,9 @@ impl DerefMut for ArrayVecCopy { + impl From<[T; CAP]> for ArrayVecCopy { + #[track_caller] + fn from(array: [T; CAP]) -> Self { +- let array = ManuallyDrop::new(array); + let mut vec = >::new(); + unsafe { +- (&*array as *const [T; CAP] as *const [MaybeUninit; CAP]) ++ (&array as *const [T; CAP] as *const [MaybeUninit; CAP]) + .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); + vec.set_len(CAP); + } +@@ -899,7 +886,7 @@ impl IntoIterator for ArrayVecCopy { + /// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; + /// assert_eq!(data, [0, 0, 0]); + /// ``` +-impl zeroize::Zeroize for ArrayVecCopy { ++impl zeroize::Zeroize for ArrayVecCopy { + fn zeroize(&mut self) { + // Zeroize all the contained elements. + self.iter_mut().zeroize(); +@@ -964,21 +951,6 @@ impl DoubleEndedIterator for IntoIter { + + impl ExactSizeIterator for IntoIter { } + +-impl Drop for IntoIter { +- fn drop(&mut self) { +- // panic safety: Set length to 0 before dropping elements. +- let index = self.index; +- let len = self.v.len(); +- unsafe { +- self.v.set_len(0); +- let elements = slice::from_raw_parts_mut( +- self.v.get_unchecked_ptr(index), +- len - index); +- ptr::drop_in_place(elements); +- } +- } +-} +- + impl Clone for IntoIter + where T: Clone, + { +@@ -1064,7 +1036,7 @@ impl<'a, T: Copy + 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { + } + } + +-struct ScopeExitGuard ++struct ScopeExitGuard + where F: FnMut(&Data, &mut T) + { + value: T, +@@ -1072,7 +1044,7 @@ struct ScopeExitGuard + f: F, + } + +-impl Drop for ScopeExitGuard ++impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut T) + { + fn drop(&mut self) { From 67c47790a37a7afb59e7d68b0ca3dbb23e6eb06c Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 17 Oct 2024 16:55:27 +0200 Subject: [PATCH 3/6] Minimize diff between `src/arrayvec{,_copy}.rs` --- src/arrayvec.rs | 18 +++--- src/arrayvec_copy.patch | 127 +++------------------------------------- src/arrayvec_copy.rs | 28 +++++---- 3 files changed, 36 insertions(+), 137 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e5ea52d..fa9b8eb 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -499,7 +499,7 @@ impl ArrayVec { let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; #[inline(always)] - fn process_one bool, T, const CAP: usize, const DELETED: bool>( + fn process_one bool, const CAP: usize, const DELETED: bool>( f: &mut F, g: &mut BackshiftOnDrop<'_, T, CAP> ) -> bool { @@ -522,14 +522,14 @@ impl ArrayVec { // Stage 1: Nothing was deleted. while g.processed_len != original_len { - if !process_one::(&mut f, &mut g) { + if !process_one::(&mut f, &mut g) { break; } } // Stage 2: Some elements were deleted. while g.processed_len != original_len { - process_one::(&mut f, &mut g); + process_one::(&mut f, &mut g); } drop(g); @@ -899,7 +899,7 @@ impl IntoIterator for ArrayVec { /// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; /// assert_eq!(data, [0, 0, 0]); /// ``` -impl zeroize::Zeroize for ArrayVec { +impl zeroize::Zeroize for ArrayVec { fn zeroize(&mut self) { // Zeroize all the contained elements. self.iter_mut().zeroize(); @@ -1064,16 +1064,16 @@ impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { } } -struct ScopeExitGuard - where F: FnMut(&Data, &mut T) +struct ScopeExitGuard + where F: FnMut(&Data, &mut V) { - value: T, + value: V, data: Data, f: F, } -impl Drop for ScopeExitGuard - where F: FnMut(&Data, &mut T) +impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut V) { fn drop(&mut self) { (self.f)(&self.data, &mut self.value) diff --git a/src/arrayvec_copy.patch b/src/arrayvec_copy.patch index 989a69d..00744a9 100644 --- a/src/arrayvec_copy.patch +++ b/src/arrayvec_copy.patch @@ -1,25 +1,18 @@ diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs -index 6719868..d36e5fb 100644 +index b12aa9e..5597af9 100644 --- a/src/arrayvec_copy_generated.rs +++ b/src/arrayvec_copy.rs -@@ -14,7 +14,6 @@ use std::fmt; - #[cfg(feature="std")] - use std::io; +@@ -27,6 +27,9 @@ use crate::utils::MakeMaybeUninit; --use std::mem::ManuallyDrop; - use std::mem::MaybeUninit; - - #[cfg(feature="serde")] -@@ -25,7 +24,7 @@ use crate::errors::CapacityError; - use crate::arrayvec_impl::ArrayVecImpl; - use crate::utils::MakeMaybeUninit; - --/// A vector with a fixed capacity. -+/// A vector with a fixed capacity which implements `Copy` and its elemenents are constrained to also be `Copy`. + /// A vector with a fixed capacity. /// ++/// **Its only difference to [`ArrayVec`](crate::ArrayVec) is that its elements ++/// are constrained to be `Copy` which allows it to be `Copy` itself.** ++/// /// The `ArrayVecCopy` is a vector backed by a fixed size array. It keeps track of /// the number of initialized elements. The `ArrayVecCopy` is parameterized -@@ -46,14 +45,6 @@ pub struct ArrayVecCopy { + /// by `T` for the element type and `CAP` for the maximum capacity. +@@ -46,14 +49,6 @@ pub struct ArrayVecCopy { xs: [MaybeUninit; CAP], } @@ -34,91 +27,7 @@ index 6719868..d36e5fb 100644 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 {}"), -@@ -231,8 +222,7 @@ impl ArrayVecCopy { - ArrayVecImpl::push_unchecked(self, element) - } - -- /// Shortens the vector, keeping the first `len` elements and dropping -- /// the rest. -+ /// Shortens the vector, keeping the first `len` elements. - /// - /// If `len` is greater than the vector’s current length this has no - /// effect. -@@ -499,7 +489,7 @@ impl ArrayVecCopy { - let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - - #[inline(always)] -- fn process_one bool, T, const CAP: usize, const DELETED: bool>( -+ fn process_one bool, const CAP: usize, const DELETED: bool>( - f: &mut F, - g: &mut BackshiftOnDrop<'_, T, CAP> - ) -> bool { -@@ -507,7 +497,6 @@ impl ArrayVecCopy { - if !f(unsafe { &mut *cur }) { - g.processed_len += 1; - g.deleted_cnt += 1; -- unsafe { ptr::drop_in_place(cur) }; - return false; - } - if DELETED { -@@ -522,14 +511,14 @@ impl ArrayVecCopy { - - // Stage 1: Nothing was deleted. - while g.processed_len != original_len { -- if !process_one::(&mut f, &mut g) { -+ if !process_one::(&mut f, &mut g) { - break; - } - } - - // Stage 2: Some elements were deleted. - while g.processed_len != original_len { -- process_one::(&mut f, &mut g); -+ process_one::(&mut f, &mut g); - } - - drop(g); -@@ -570,7 +559,7 @@ impl ArrayVecCopy { - &mut self.xs[len..] - } - -- /// Set the vector’s length without dropping or moving out elements -+ /// 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. -@@ -703,8 +692,7 @@ impl ArrayVecCopy { - /// 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 self_ = ManuallyDrop::new(self); -- let array = ptr::read(self_.as_ptr() as *const [T; CAP]); -+ let array = ptr::read(self.as_ptr() as *const [T; CAP]); - array - } - -@@ -790,10 +778,9 @@ impl DerefMut for ArrayVecCopy { - impl From<[T; CAP]> for ArrayVecCopy { - #[track_caller] - fn from(array: [T; CAP]) -> Self { -- let array = ManuallyDrop::new(array); - let mut vec = >::new(); - unsafe { -- (&*array as *const [T; CAP] as *const [MaybeUninit; CAP]) -+ (&array as *const [T; CAP] as *const [MaybeUninit; CAP]) - .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); - vec.set_len(CAP); - } -@@ -899,7 +886,7 @@ impl IntoIterator for ArrayVecCopy { - /// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; - /// assert_eq!(data, [0, 0, 0]); - /// ``` --impl zeroize::Zeroize for ArrayVecCopy { -+impl zeroize::Zeroize for ArrayVecCopy { - fn zeroize(&mut self) { - // Zeroize all the contained elements. - self.iter_mut().zeroize(); -@@ -964,21 +951,6 @@ impl DoubleEndedIterator for IntoIter { +@@ -964,21 +959,6 @@ impl DoubleEndedIterator for IntoIter { impl ExactSizeIterator for IntoIter { } @@ -140,21 +49,3 @@ index 6719868..d36e5fb 100644 impl Clone for IntoIter where T: Clone, { -@@ -1064,7 +1036,7 @@ impl<'a, T: Copy + 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { - } - } - --struct ScopeExitGuard -+struct ScopeExitGuard - where F: FnMut(&Data, &mut T) - { - value: T, -@@ -1072,7 +1044,7 @@ struct ScopeExitGuard - f: F, - } - --impl Drop for ScopeExitGuard -+impl Drop for ScopeExitGuard - where F: FnMut(&Data, &mut T) - { - fn drop(&mut self) { diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs index d36e5fb..5597af9 100644 --- a/src/arrayvec_copy.rs +++ b/src/arrayvec_copy.rs @@ -14,6 +14,7 @@ use std::fmt; #[cfg(feature="std")] use std::io; +use std::mem::ManuallyDrop; use std::mem::MaybeUninit; #[cfg(feature="serde")] @@ -24,7 +25,10 @@ use crate::errors::CapacityError; use crate::arrayvec_impl::ArrayVecImpl; use crate::utils::MakeMaybeUninit; -/// A vector with a fixed capacity which implements `Copy` and its elemenents are constrained to also be `Copy`. +/// A vector with a fixed capacity. +/// +/// **Its only difference to [`ArrayVec`](crate::ArrayVec) is that its elements +/// are constrained to be `Copy` which allows it to be `Copy` itself.** /// /// The `ArrayVecCopy` is a vector backed by a fixed size array. It keeps track of /// the number of initialized elements. The `ArrayVecCopy` is parameterized @@ -222,7 +226,8 @@ impl ArrayVecCopy { ArrayVecImpl::push_unchecked(self, element) } - /// Shortens the vector, keeping the first `len` elements. + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. /// /// If `len` is greater than the vector’s current length this has no /// effect. @@ -497,6 +502,7 @@ impl ArrayVecCopy { if !f(unsafe { &mut *cur }) { g.processed_len += 1; g.deleted_cnt += 1; + unsafe { ptr::drop_in_place(cur) }; return false; } if DELETED { @@ -559,7 +565,7 @@ impl ArrayVecCopy { &mut self.xs[len..] } - /// Set the vector’s length without moving out elements + /// Set the vector’s length without dropping or moving out elements /// /// This method is `unsafe` because it changes the notion of the /// number of “valid” elements in the vector. Use with care. @@ -692,7 +698,8 @@ impl ArrayVecCopy { /// 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]); + let self_ = ManuallyDrop::new(self); + let array = ptr::read(self_.as_ptr() as *const [T; CAP]); array } @@ -778,9 +785,10 @@ impl DerefMut for ArrayVecCopy { impl From<[T; CAP]> for ArrayVecCopy { #[track_caller] fn from(array: [T; CAP]) -> Self { + let array = ManuallyDrop::new(array); let mut vec = >::new(); unsafe { - (&array as *const [T; CAP] as *const [MaybeUninit; CAP]) + (&*array as *const [T; CAP] as *const [MaybeUninit; CAP]) .copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit; CAP], 1); vec.set_len(CAP); } @@ -1036,16 +1044,16 @@ impl<'a, T: Copy + 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { } } -struct ScopeExitGuard - where F: FnMut(&Data, &mut T) +struct ScopeExitGuard + where F: FnMut(&Data, &mut V) { - value: T, + value: V, data: Data, f: F, } -impl Drop for ScopeExitGuard - where F: FnMut(&Data, &mut T) +impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut V) { fn drop(&mut self) { (self.f)(&self.data, &mut self.value) From 6a182a2153d0fddf6d0c686c824570ac6747c371 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 17 Oct 2024 22:43:38 +0200 Subject: [PATCH 4/6] Make `ArrayVecCopy` functions non-`const` They don't work on Rust 1.51 ``` error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> src/arrayvec_copy.rs:59:6 | 59 | impl ArrayVecCopy { | ^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable ``` --- generate_arrayvec_copy | 1 + src/arrayvec_copy.patch | 33 +++++++++++++++++++++++++++++---- src/arrayvec_copy.rs | 25 +++++-------------------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/generate_arrayvec_copy b/generate_arrayvec_copy index bf3b150..b27f508 100755 --- a/generate_arrayvec_copy +++ b/generate_arrayvec_copy @@ -12,6 +12,7 @@ sed \ -e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/struct \\1<\\2T: Copy,/g" \ -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/fn \\1<\\2T: Copy +/g" \ -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/fn \\1<\\2T: Copy,/g" \ + -e "s/const fn/fn/" \ src/arrayvec.rs \ > src/arrayvec_copy_generated.rs diff --git a/src/arrayvec_copy.patch b/src/arrayvec_copy.patch index 00744a9..16fd8fb 100644 --- a/src/arrayvec_copy.patch +++ b/src/arrayvec_copy.patch @@ -1,8 +1,12 @@ diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs -index b12aa9e..5597af9 100644 +index f61b5b3..fab45ec 100644 --- a/src/arrayvec_copy_generated.rs +++ b/src/arrayvec_copy.rs -@@ -27,6 +27,9 @@ use crate::utils::MakeMaybeUninit; +@@ -23,10 +23,12 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; + use crate::LenUint; + use crate::errors::CapacityError; + use crate::arrayvec_impl::ArrayVecImpl; +-use crate::utils::MakeMaybeUninit; /// A vector with a fixed capacity. /// @@ -12,7 +16,7 @@ index b12aa9e..5597af9 100644 /// 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. -@@ -46,14 +49,6 @@ pub struct ArrayVecCopy { +@@ -46,14 +48,6 @@ pub struct ArrayVecCopy { xs: [MaybeUninit; CAP], } @@ -27,7 +31,28 @@ index b12aa9e..5597af9 100644 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 {}"), -@@ -964,21 +959,6 @@ impl DoubleEndedIterator for IntoIter { +@@ -87,20 +81,6 @@ impl ArrayVecCopy { + } + } + +- /// Create a new empty `ArrayVecCopy` (fn). +- /// +- /// The maximum capacity is given by the generic parameter `CAP`. +- /// +- /// ``` +- /// use arrayvec::ArrayVecCopy; +- /// +- /// static ARRAY: ArrayVecCopy = ArrayVecCopy::new_const(); +- /// ``` +- pub fn new_const() -> ArrayVecCopy { +- assert_capacity_limit_const!(CAP); +- ArrayVecCopy { xs: MakeMaybeUninit::ARRAY, len: 0 } +- } +- + /// Return the number of elements in the `ArrayVecCopy`. + /// + /// ``` +@@ -964,21 +944,6 @@ impl DoubleEndedIterator for IntoIter { impl ExactSizeIterator for IntoIter { } diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs index 5597af9..fab45ec 100644 --- a/src/arrayvec_copy.rs +++ b/src/arrayvec_copy.rs @@ -23,7 +23,6 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; use crate::LenUint; use crate::errors::CapacityError; use crate::arrayvec_impl::ArrayVecImpl; -use crate::utils::MakeMaybeUninit; /// A vector with a fixed capacity. /// @@ -82,20 +81,6 @@ impl ArrayVecCopy { } } - /// Create a new empty `ArrayVecCopy` (const fn). - /// - /// The maximum capacity is given by the generic parameter `CAP`. - /// - /// ``` - /// use arrayvec::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`. /// /// ``` @@ -106,7 +91,7 @@ impl ArrayVecCopy { /// assert_eq!(array.len(), 2); /// ``` #[inline(always)] - pub const fn len(&self) -> usize { self.len as usize } + pub fn len(&self) -> usize { self.len as usize } /// Returns whether the `ArrayVecCopy` is empty. /// @@ -118,7 +103,7 @@ impl ArrayVecCopy { /// assert_eq!(array.is_empty(), true); /// ``` #[inline] - pub const fn is_empty(&self) -> bool { self.len() == 0 } + pub fn is_empty(&self) -> bool { self.len() == 0 } /// Return the capacity of the `ArrayVecCopy`. /// @@ -129,7 +114,7 @@ impl ArrayVecCopy { /// assert_eq!(array.capacity(), 3); /// ``` #[inline(always)] - pub const fn capacity(&self) -> usize { CAP } + pub fn capacity(&self) -> usize { CAP } /// Return true if the `ArrayVecCopy` is completely filled to its capacity, false otherwise. /// @@ -141,7 +126,7 @@ impl ArrayVecCopy { /// array.push(1); /// assert!(array.is_full()); /// ``` - pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + pub fn is_full(&self) -> bool { self.len() == self.capacity() } /// Returns the capacity left in the `ArrayVecCopy`. /// @@ -152,7 +137,7 @@ impl ArrayVecCopy { /// array.pop(); /// assert_eq!(array.remaining_capacity(), 1); /// ``` - pub const fn remaining_capacity(&self) -> usize { + pub fn remaining_capacity(&self) -> usize { self.capacity() - self.len() } From 028b3e6088a14b7cb433b2e686b52aa9ca5c8acf Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 19 Oct 2024 18:14:02 +0200 Subject: [PATCH 5/6] Generate ArrayVecCopy without using patch Invent this little hack, insert directives like this in ArrayVec: ```rust // DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)] ``` And replace them as follows in ArrayVecCopy: ```rust #[cfg(not_in_arrayvec_copy)] ``` --- Cargo.toml | 4 +++ generate_arrayvec_copy | 28 +++++---------- src/arrayvec.rs | 15 ++++++++ src/arrayvec_copy.patch | 76 ----------------------------------------- src/arrayvec_copy.rs | 56 ++++++++++++++++++++++++++++-- 5 files changed, 81 insertions(+), 98 deletions(-) delete mode 100644 src/arrayvec_copy.patch diff --git a/Cargo.toml b/Cargo.toml index 13917b0..350d875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,3 +60,7 @@ features = ["borsh", "serde", "zeroize"] [package.metadata.release] no-dev-version = true tag-name = "{{version}}" + + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(not_in_arrayvec_copy)'] } diff --git a/generate_arrayvec_copy b/generate_arrayvec_copy index b27f508..7538df3 100755 --- a/generate_arrayvec_copy +++ b/generate_arrayvec_copy @@ -3,6 +3,13 @@ set -o errexit set -o nounset set -o pipefail +# Generate ArrayVecCopy from ArrayVec +# Replace type name with ArrayVecCopy +# Insert `T: Copy` bound as needed. +# +# Replace `// DIRECTIVE ArrayVecCopy` with empty string anywhere to allow +# items to be cfg'ed out for arrayvec copy + sed \ -e "s/\\/ArrayVecCopy/g" \ -e "s/\\/ArrayVecCopyVisitor/g" \ @@ -13,25 +20,8 @@ sed \ -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/fn \\1<\\2T: Copy +/g" \ -e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/fn \\1<\\2T: Copy,/g" \ -e "s/const fn/fn/" \ + -e "s/\\/\\/ DIRECTIVE ArrayVecCopy \\+//" \ src/arrayvec.rs \ > src/arrayvec_copy_generated.rs -trap "rm src/arrayvec_copy_generated.rs" EXIT - -if [ -e src/arrayvec_copy.patch ]; then - if [ -e src/arrayvec_copy.rs ]; then - echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs exist." > /dev/stderr - echo "Delete one of them and start again." > /dev/stderr - exit 1 - else - patch -o src/arrayvec_copy.rs src/arrayvec_copy_generated.rs src/arrayvec_copy.patch > /dev/null - fi -else - if [ -e src/arrayvec_copy.rs ]; then - git diff --no-index src/arrayvec_copy_generated.rs src/arrayvec_copy.rs > src/arrayvec_copy.patch || true - else - echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs are missing." > /dev/stderr - echo "One of them is needed to generate the other." > /dev/stderr - exit 1 - fi -fi +mv -v -f src/arrayvec_copy_generated.rs src/arrayvec_copy.rs diff --git a/src/arrayvec.rs b/src/arrayvec.rs index fa9b8eb..0c3358a 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -1,3 +1,11 @@ +// The ArrayVec and ArrayVecCopy implementation +// +// NOTE: arrayvec.rs is the original source of both arrayvec.rs and arrayvec_copy.rs. +// NOTE: Do not modify arrayvec_copy.rs manually. It is generated using the script +// ./generate_arrayvec_copy. +// +// Any lines marked with a comment and then `DIRECTIVE ArrayVecCopy` will have that prefix removed +// and have the rest of the line active in the ArrayVecCopy implementation. use std::cmp; use std::iter; @@ -23,6 +31,7 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; use crate::LenUint; use crate::errors::CapacityError; use crate::arrayvec_impl::ArrayVecImpl; +// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)] use crate::utils::MakeMaybeUninit; /// A vector with a fixed capacity. @@ -39,6 +48,9 @@ use crate::utils::MakeMaybeUninit; /// /// It offers a simple API but also dereferences to a slice, so that the full slice API is /// available. The ArrayVec can be converted into a by value iterator. +// DIRECTIVE ArrayVecCopy #[doc = ""] +// DIRECTIVE ArrayVecCopy #[doc = "**ArrayVecCopy's only difference to [`\x41rrayVec`](crate::\x41rrayVec) is that its"] +// DIRECTIVE ArrayVecCopy #[doc = "elements are constrained to be `Copy` which allows it to be `Copy` itself.** "] #[repr(C)] pub struct ArrayVec { len: LenUint, @@ -46,6 +58,7 @@ pub struct ArrayVec { xs: [MaybeUninit; CAP], } +// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)] impl Drop for ArrayVec { fn drop(&mut self) { self.clear(); @@ -87,6 +100,7 @@ impl ArrayVec { } } + // DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)] /// Create a new empty `ArrayVec` (const fn). /// /// The maximum capacity is given by the generic parameter `CAP`. @@ -964,6 +978,7 @@ impl DoubleEndedIterator for IntoIter { impl ExactSizeIterator for IntoIter { } +// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)] impl Drop for IntoIter { fn drop(&mut self) { // panic safety: Set length to 0 before dropping elements. diff --git a/src/arrayvec_copy.patch b/src/arrayvec_copy.patch deleted file mode 100644 index 16fd8fb..0000000 --- a/src/arrayvec_copy.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs -index f61b5b3..fab45ec 100644 ---- a/src/arrayvec_copy_generated.rs -+++ b/src/arrayvec_copy.rs -@@ -23,10 +23,12 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; - use crate::LenUint; - use crate::errors::CapacityError; - use crate::arrayvec_impl::ArrayVecImpl; --use crate::utils::MakeMaybeUninit; - - /// A vector with a fixed capacity. - /// -+/// **Its only difference to [`ArrayVec`](crate::ArrayVec) is that its elements -+/// are constrained to be `Copy` which allows it to be `Copy` itself.** -+/// - /// 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. -@@ -46,14 +48,6 @@ pub struct ArrayVecCopy { - xs: [MaybeUninit; CAP], - } - --impl Drop for ArrayVecCopy { -- fn drop(&mut self) { -- self.clear(); -- -- // MaybeUninit inhibits array's drop -- } --} -- - 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 {}"), -@@ -87,20 +81,6 @@ impl ArrayVecCopy { - } - } - -- /// Create a new empty `ArrayVecCopy` (fn). -- /// -- /// The maximum capacity is given by the generic parameter `CAP`. -- /// -- /// ``` -- /// use arrayvec::ArrayVecCopy; -- /// -- /// static ARRAY: ArrayVecCopy = ArrayVecCopy::new_const(); -- /// ``` -- pub fn new_const() -> ArrayVecCopy { -- assert_capacity_limit_const!(CAP); -- ArrayVecCopy { xs: MakeMaybeUninit::ARRAY, len: 0 } -- } -- - /// Return the number of elements in the `ArrayVecCopy`. - /// - /// ``` -@@ -964,21 +944,6 @@ impl DoubleEndedIterator for IntoIter { - - impl ExactSizeIterator for IntoIter { } - --impl Drop for IntoIter { -- fn drop(&mut self) { -- // panic safety: Set length to 0 before dropping elements. -- let index = self.index; -- let len = self.v.len(); -- unsafe { -- self.v.set_len(0); -- let elements = slice::from_raw_parts_mut( -- self.v.get_unchecked_ptr(index), -- len - index); -- ptr::drop_in_place(elements); -- } -- } --} -- - impl Clone for IntoIter - where T: Clone, - { diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs index fab45ec..1f11758 100644 --- a/src/arrayvec_copy.rs +++ b/src/arrayvec_copy.rs @@ -1,3 +1,11 @@ +// The ArrayVecCopy and ArrayVecCopy implementation +// +// NOTE: arrayvec.rs is the original source of both arrayvec.rs and arrayvec_copy.rs. +// NOTE: Do not modify arrayvec_copy.rs manually. It is generated using the script +// ./generate_arrayvec_copy. +// +// Any lines marked with a comment and then `DIRECTIVE ArrayVecCopy` will have that prefix removed +// and have the rest of the line active in the ArrayVecCopy implementation. use std::cmp; use std::iter; @@ -23,12 +31,11 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer}; use crate::LenUint; use crate::errors::CapacityError; use crate::arrayvec_impl::ArrayVecImpl; +#[cfg(not_in_arrayvec_copy)] +use crate::utils::MakeMaybeUninit; /// A vector with a fixed capacity. /// -/// **Its only difference to [`ArrayVec`](crate::ArrayVec) is that its elements -/// are constrained to be `Copy` which allows it to be `Copy` itself.** -/// /// 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. @@ -41,6 +48,9 @@ use crate::arrayvec_impl::ArrayVecImpl; /// /// 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. +#[doc = ""] +#[doc = "**ArrayVecCopy's only difference to [`\x41rrayVec`](crate::\x41rrayVec) is that its"] +#[doc = "elements are constrained to be `Copy` which allows it to be `Copy` itself.** "] #[repr(C)] pub struct ArrayVecCopy { len: LenUint, @@ -48,6 +58,15 @@ pub struct ArrayVecCopy { xs: [MaybeUninit; CAP], } +#[cfg(not_in_arrayvec_copy)] +impl Drop for ArrayVecCopy { + fn drop(&mut self) { + self.clear(); + + // MaybeUninit inhibits array's drop + } +} + 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 {}"), @@ -81,6 +100,21 @@ impl ArrayVecCopy { } } + #[cfg(not_in_arrayvec_copy)] + /// Create a new empty `ArrayVecCopy` (fn). + /// + /// The maximum capacity is given by the generic parameter `CAP`. + /// + /// ``` + /// use arrayvec::ArrayVecCopy; + /// + /// static ARRAY: ArrayVecCopy = ArrayVecCopy::new_const(); + /// ``` + pub fn new_const() -> ArrayVecCopy { + assert_capacity_limit_const!(CAP); + ArrayVecCopy { xs: MakeMaybeUninit::ARRAY, len: 0 } + } + /// Return the number of elements in the `ArrayVecCopy`. /// /// ``` @@ -944,6 +978,22 @@ impl DoubleEndedIterator for IntoIter { impl ExactSizeIterator for IntoIter { } +#[cfg(not_in_arrayvec_copy)] +impl Drop for IntoIter { + fn drop(&mut self) { + // panic safety: Set length to 0 before dropping elements. + let index = self.index; + let len = self.v.len(); + unsafe { + self.v.set_len(0); + let elements = slice::from_raw_parts_mut( + self.v.get_unchecked_ptr(index), + len - index); + ptr::drop_in_place(elements); + } + } +} + impl Clone for IntoIter where T: Clone, { From 77ae631d2f89e0b040d1e5234ae0df9c688b67af Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 19 Oct 2024 19:51:23 +0200 Subject: [PATCH 6/6] ArrayVecCopy: Skip rename of ArrayVecVisitor It's a type nested in a function, does not need renaming. --- generate_arrayvec_copy | 1 - src/arrayvec_copy.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/generate_arrayvec_copy b/generate_arrayvec_copy index 7538df3..7b8e2a9 100755 --- a/generate_arrayvec_copy +++ b/generate_arrayvec_copy @@ -12,7 +12,6 @@ set -o pipefail sed \ -e "s/\\/ArrayVecCopy/g" \ - -e "s/\\/ArrayVecCopyVisitor/g" \ -e "s/impl<\\('[A-Za-z_]*, \\)\\?T:/impl<\\1T: Copy +/g" \ -e "s/impl<\\('[A-Za-z_]*, \\)\\?T,/impl<\\1T: Copy,/g" \ -e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/struct \\1<\\2T: Copy +/g" \ diff --git a/src/arrayvec_copy.rs b/src/arrayvec_copy.rs index 1f11758..79b48f9 100644 --- a/src/arrayvec_copy.rs +++ b/src/arrayvec_copy.rs @@ -1335,9 +1335,9 @@ impl<'de, T: Copy + Deserialize<'de>, const CAP: usize> Deserialize<'de> for Arr use serde::de::{Visitor, SeqAccess, Error}; use std::marker::PhantomData; - struct ArrayVecCopyVisitor<'de, T: Copy + Deserialize<'de>, const CAP: usize>(PhantomData<(&'de (), [T; CAP])>); + struct ArrayVecVisitor<'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> { + impl<'de, T: Copy + Deserialize<'de>, const CAP: usize> Visitor<'de> for ArrayVecVisitor<'de, T, CAP> { type Value = ArrayVecCopy; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -1359,7 +1359,7 @@ impl<'de, T: Copy + Deserialize<'de>, const CAP: usize> Deserialize<'de> for Arr } } - deserializer.deserialize_seq(ArrayVecCopyVisitor::(PhantomData)) + deserializer.deserialize_seq(ArrayVecVisitor::(PhantomData)) } }