Skip to content

Commit 2b807d3

Browse files
committed
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.
1 parent 5caad4c commit 2b807d3

File tree

3 files changed

+209
-0
lines changed

3 files changed

+209
-0
lines changed

.github/workflows/ci.yml

+13
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,16 @@ jobs:
9292
cargo miri setup
9393
- name: Test with Miri
9494
run: cargo miri test --all-features
95+
96+
check-generated:
97+
runs-on: ubuntu-latest
98+
steps:
99+
- uses: actions/checkout@v4
100+
- name: Regenerate src/arrayvec_copy.rs
101+
run: |
102+
rm src/arrayvec_copy.rs
103+
./generate_arrayvec_copy
104+
- name: Verify that nothing has changed
105+
run: |
106+
git diff
107+
test -z "$(git status --porcelain)"

generate_arrayvec_copy

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
set -o errexit
3+
set -o nounset
4+
set -o pipefail
5+
6+
sed \
7+
-e "s/\\<ArrayVec\\>/ArrayVecCopy/g" \
8+
-e "s/\\<ArrayVecVisitor\\>/ArrayVecCopyVisitor/g" \
9+
-e "s/impl<\\('[A-Za-z_]*, \\)\\?T:/impl<\\1T: Copy +/g" \
10+
-e "s/impl<\\('[A-Za-z_]*, \\)\\?T,/impl<\\1T: Copy,/g" \
11+
-e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/struct \\1<\\2T: Copy +/g" \
12+
-e "s/struct \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/struct \\1<\\2T: Copy,/g" \
13+
-e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T:/fn \\1<\\2T: Copy +/g" \
14+
-e "s/fn \\([A-Za-z_]*\\)<\\('[A-Za-z_]*, \\)\\?T,/fn \\1<\\2T: Copy,/g" \
15+
src/arrayvec.rs \
16+
> src/arrayvec_copy_generated.rs
17+
18+
trap "rm src/arrayvec_copy_generated.rs" EXIT
19+
20+
if [ -e src/arrayvec_copy.patch ]; then
21+
if [ -e src/arrayvec_copy.rs ]; then
22+
echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs exist." > /dev/stderr
23+
echo "Delete one of them and start again." > /dev/stderr
24+
exit 1
25+
else
26+
patch -o src/arrayvec_copy.rs src/arrayvec_copy_generated.rs src/arrayvec_copy.patch > /dev/null
27+
fi
28+
else
29+
if [ -e src/arrayvec_copy.rs ]; then
30+
git diff --no-index src/arrayvec_copy_generated.rs src/arrayvec_copy.rs > src/arrayvec_copy.patch
31+
else
32+
echo "Both src/arrayvec_copy.patch and src/arrayvec_copy.rs are missing." > /dev/stderr
33+
echo "One of them is needed to generate the other." > /dev/stderr
34+
exit 1
35+
fi
36+
fi

src/arrayvec_copy.patch

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs
2+
index 6719868..d36e5fb 100644
3+
--- a/src/arrayvec_copy_generated.rs
4+
+++ b/src/arrayvec_copy.rs
5+
@@ -14,7 +14,6 @@ use std::fmt;
6+
#[cfg(feature="std")]
7+
use std::io;
8+
9+
-use std::mem::ManuallyDrop;
10+
use std::mem::MaybeUninit;
11+
12+
#[cfg(feature="serde")]
13+
@@ -25,7 +24,7 @@ use crate::errors::CapacityError;
14+
use crate::arrayvec_impl::ArrayVecImpl;
15+
use crate::utils::MakeMaybeUninit;
16+
17+
-/// A vector with a fixed capacity.
18+
+/// A vector with a fixed capacity which implements `Copy` and its elemenents are constrained to also be `Copy`.
19+
///
20+
/// The `ArrayVecCopy` is a vector backed by a fixed size array. It keeps track of
21+
/// the number of initialized elements. The `ArrayVecCopy<T, CAP>` is parameterized
22+
@@ -46,14 +45,6 @@ pub struct ArrayVecCopy<T: Copy, const CAP: usize> {
23+
xs: [MaybeUninit<T>; CAP],
24+
}
25+
26+
-impl<T: Copy, const CAP: usize> Drop for ArrayVecCopy<T, CAP> {
27+
- fn drop(&mut self) {
28+
- self.clear();
29+
-
30+
- // MaybeUninit inhibits array's drop
31+
- }
32+
-}
33+
-
34+
macro_rules! panic_oob {
35+
($method_name:expr, $index:expr, $len:expr) => {
36+
panic!(concat!("ArrayVecCopy::", $method_name, ": index {} is out of bounds in vector of length {}"),
37+
@@ -231,8 +222,7 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
38+
ArrayVecImpl::push_unchecked(self, element)
39+
}
40+
41+
- /// Shortens the vector, keeping the first `len` elements and dropping
42+
- /// the rest.
43+
+ /// Shortens the vector, keeping the first `len` elements.
44+
///
45+
/// If `len` is greater than the vector’s current length this has no
46+
/// effect.
47+
@@ -499,7 +489,7 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
48+
let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len };
49+
50+
#[inline(always)]
51+
- fn process_one<F: FnMut(&mut T) -> bool, T, const CAP: usize, const DELETED: bool>(
52+
+ fn process_one<T: Copy, F: FnMut(&mut T) -> bool, const CAP: usize, const DELETED: bool>(
53+
f: &mut F,
54+
g: &mut BackshiftOnDrop<'_, T, CAP>
55+
) -> bool {
56+
@@ -507,7 +497,6 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
57+
if !f(unsafe { &mut *cur }) {
58+
g.processed_len += 1;
59+
g.deleted_cnt += 1;
60+
- unsafe { ptr::drop_in_place(cur) };
61+
return false;
62+
}
63+
if DELETED {
64+
@@ -522,14 +511,14 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
65+
66+
// Stage 1: Nothing was deleted.
67+
while g.processed_len != original_len {
68+
- if !process_one::<F, T, CAP, false>(&mut f, &mut g) {
69+
+ if !process_one::<T, F, CAP, false>(&mut f, &mut g) {
70+
break;
71+
}
72+
}
73+
74+
// Stage 2: Some elements were deleted.
75+
while g.processed_len != original_len {
76+
- process_one::<F, T, CAP, true>(&mut f, &mut g);
77+
+ process_one::<T, F, CAP, true>(&mut f, &mut g);
78+
}
79+
80+
drop(g);
81+
@@ -570,7 +559,7 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
82+
&mut self.xs[len..]
83+
}
84+
85+
- /// Set the vector’s length without dropping or moving out elements
86+
+ /// Set the vector’s length without moving out elements
87+
///
88+
/// This method is `unsafe` because it changes the notion of the
89+
/// number of “valid” elements in the vector. Use with care.
90+
@@ -703,8 +692,7 @@ impl<T: Copy, const CAP: usize> ArrayVecCopy<T, CAP> {
91+
/// This operation is safe if and only if length equals capacity.
92+
pub unsafe fn into_inner_unchecked(self) -> [T; CAP] {
93+
debug_assert_eq!(self.len(), self.capacity());
94+
- let self_ = ManuallyDrop::new(self);
95+
- let array = ptr::read(self_.as_ptr() as *const [T; CAP]);
96+
+ let array = ptr::read(self.as_ptr() as *const [T; CAP]);
97+
array
98+
}
99+
100+
@@ -790,10 +778,9 @@ impl<T: Copy, const CAP: usize> DerefMut for ArrayVecCopy<T, CAP> {
101+
impl<T: Copy, const CAP: usize> From<[T; CAP]> for ArrayVecCopy<T, CAP> {
102+
#[track_caller]
103+
fn from(array: [T; CAP]) -> Self {
104+
- let array = ManuallyDrop::new(array);
105+
let mut vec = <ArrayVecCopy<T, CAP>>::new();
106+
unsafe {
107+
- (&*array as *const [T; CAP] as *const [MaybeUninit<T>; CAP])
108+
+ (&array as *const [T; CAP] as *const [MaybeUninit<T>; CAP])
109+
.copy_to_nonoverlapping(&mut vec.xs as *mut [MaybeUninit<T>; CAP], 1);
110+
vec.set_len(CAP);
111+
}
112+
@@ -899,7 +886,7 @@ impl<T: Copy, const CAP: usize> IntoIterator for ArrayVecCopy<T, CAP> {
113+
/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) };
114+
/// assert_eq!(data, [0, 0, 0]);
115+
/// ```
116+
-impl<Z: zeroize::Zeroize, const CAP: usize> zeroize::Zeroize for ArrayVecCopy<Z, CAP> {
117+
+impl<T: Copy + zeroize::Zeroize, const CAP: usize> zeroize::Zeroize for ArrayVecCopy<T, CAP> {
118+
fn zeroize(&mut self) {
119+
// Zeroize all the contained elements.
120+
self.iter_mut().zeroize();
121+
@@ -964,21 +951,6 @@ impl<T: Copy, const CAP: usize> DoubleEndedIterator for IntoIter<T, CAP> {
122+
123+
impl<T: Copy, const CAP: usize> ExactSizeIterator for IntoIter<T, CAP> { }
124+
125+
-impl<T: Copy, const CAP: usize> Drop for IntoIter<T, CAP> {
126+
- fn drop(&mut self) {
127+
- // panic safety: Set length to 0 before dropping elements.
128+
- let index = self.index;
129+
- let len = self.v.len();
130+
- unsafe {
131+
- self.v.set_len(0);
132+
- let elements = slice::from_raw_parts_mut(
133+
- self.v.get_unchecked_ptr(index),
134+
- len - index);
135+
- ptr::drop_in_place(elements);
136+
- }
137+
- }
138+
-}
139+
-
140+
impl<T: Copy, const CAP: usize> Clone for IntoIter<T, CAP>
141+
where T: Clone,
142+
{
143+
@@ -1064,7 +1036,7 @@ impl<'a, T: Copy + 'a, const CAP: usize> Drop for Drain<'a, T, CAP> {
144+
}
145+
}
146+
147+
-struct ScopeExitGuard<T: Copy, Data, F>
148+
+struct ScopeExitGuard<T, Data, F>
149+
where F: FnMut(&Data, &mut T)
150+
{
151+
value: T,
152+
@@ -1072,7 +1044,7 @@ struct ScopeExitGuard<T: Copy, Data, F>
153+
f: F,
154+
}
155+
156+
-impl<T: Copy, Data, F> Drop for ScopeExitGuard<T, Data, F>
157+
+impl<T, Data, F> Drop for ScopeExitGuard<T, Data, F>
158+
where F: FnMut(&Data, &mut T)
159+
{
160+
fn drop(&mut self) {

0 commit comments

Comments
 (0)