Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ArrayVecCopy #280

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)'] }
25 changes: 25 additions & 0 deletions generate_arrayvec_copy
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
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/\\<ArrayVec\\>/ArrayVecCopy/g" \
-e "s/\\<arrayvec::ArrayVecCopy\\>/arrayvec::copy::ArrayVecCopy/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" \
-e "s/const fn/fn/" \
-e "s/\\/\\/ DIRECTIVE ArrayVecCopy \\+//" \
src/arrayvec.rs \
> src/arrayvec_copy.rs
34 changes: 25 additions & 9 deletions src/arrayvec.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.
Expand All @@ -39,13 +48,18 @@ 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)]
// DIRECTIVE ArrayVecCopy #[derive(Copy)]
pub struct ArrayVec<T, const CAP: usize> {
len: LenUint,
// the `len` first elements of the array are initialized
xs: [MaybeUninit<T>; CAP],
}

// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)]
impl<T, const CAP: usize> Drop for ArrayVec<T, CAP> {
fn drop(&mut self) {
self.clear();
Expand Down Expand Up @@ -87,6 +101,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
}
}

// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)]
/// Create a new empty `ArrayVec` (const fn).
///
/// The maximum capacity is given by the generic parameter `CAP`.
Expand Down Expand Up @@ -499,7 +514,7 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len };

#[inline(always)]
fn process_one<F: FnMut(&mut T) -> bool, T, const CAP: usize, const DELETED: bool>(
fn process_one<T, F: FnMut(&mut T) -> bool, const CAP: usize, const DELETED: bool>(
f: &mut F,
g: &mut BackshiftOnDrop<'_, T, CAP>
) -> bool {
Expand All @@ -522,14 +537,14 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {

// Stage 1: Nothing was deleted.
while g.processed_len != original_len {
if !process_one::<F, T, CAP, false>(&mut f, &mut g) {
if !process_one::<T, F, CAP, false>(&mut f, &mut g) {
break;
}
}

// Stage 2: Some elements were deleted.
while g.processed_len != original_len {
process_one::<F, T, CAP, true>(&mut f, &mut g);
process_one::<T, F, CAP, true>(&mut f, &mut g);
}

drop(g);
Expand Down Expand Up @@ -899,7 +914,7 @@ impl<T, const CAP: usize> IntoIterator for ArrayVec<T, CAP> {
/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) };
/// assert_eq!(data, [0, 0, 0]);
/// ```
impl<Z: zeroize::Zeroize, const CAP: usize> zeroize::Zeroize for ArrayVec<Z, CAP> {
impl<T: zeroize::Zeroize, const CAP: usize> zeroize::Zeroize for ArrayVec<T, CAP> {
fn zeroize(&mut self) {
// Zeroize all the contained elements.
self.iter_mut().zeroize();
Expand Down Expand Up @@ -964,6 +979,7 @@ impl<T, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> {

impl<T, const CAP: usize> ExactSizeIterator for IntoIter<T, CAP> { }

// DIRECTIVE ArrayVecCopy #[cfg(not_in_arrayvec_copy)]
impl<T, const CAP: usize> Drop for IntoIter<T, CAP> {
fn drop(&mut self) {
// panic safety: Set length to 0 before dropping elements.
Expand Down Expand Up @@ -1064,16 +1080,16 @@ impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> {
}
}

struct ScopeExitGuard<T, Data, F>
where F: FnMut(&Data, &mut T)
struct ScopeExitGuard<V, Data, F>
where F: FnMut(&Data, &mut V)
{
value: T,
value: V,
data: Data,
f: F,
}

impl<T, Data, F> Drop for ScopeExitGuard<T, Data, F>
where F: FnMut(&Data, &mut T)
impl<V, Data, F> Drop for ScopeExitGuard<V, Data, F>
where F: FnMut(&Data, &mut V)
{
fn drop(&mut self) {
(self.f)(&self.data, &mut self.value)
Expand Down
Loading