From 3392b793be5879a4eb51f7b8fcb8970430531b7a Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 17 Oct 2024 16:27:56 +0200 Subject: [PATCH] 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 | 11 +++ generate_arrayvec_copy | 36 ++++++++++ src/arrayvec_copy.patch | 149 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 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 10fb573..dc1b493 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,3 +90,14 @@ 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: test -z "$(git status --porcelain)" diff --git a/generate_arrayvec_copy b/generate_arrayvec_copy new file mode 100755 index 0000000..cfc4676 --- /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, \\)\\?T:/impl<\\1T: Copy +/g" \ + -e "s/impl<\\('a, \\)\\?T,/impl<\\1T: Copy,/g" \ + -e "s/struct \\([A-Za-z_]*\\)<\\('a, \\)\\?T:/struct \\1<\\2T: Copy +/g" \ + -e "s/struct \\([A-Za-z_]*\\)<\\('a, \\)\\?T,/struct \\1<\\2T: Copy,/g" \ + -e "s/fn \\([A-Za-z_]*\\)<\\('a, \\)\\?T:/fn \\1<\\2T: Copy +/g" \ + -e "s/fn \\([A-Za-z_]*\\)<\\('a, \\)\\?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 + 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..99fa7dd --- /dev/null +++ b/src/arrayvec_copy.patch @@ -0,0 +1,149 @@ +diff --git a/src/arrayvec_copy_generated.rs b/src/arrayvec_copy.rs +index 2c32eed..ada0728 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,20 +511,20 @@ 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); + } + +- /// 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. +@@ -668,8 +657,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 + } + +@@ -755,10 +743,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); + } +@@ -929,21 +916,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, + { +@@ -1029,7 +1001,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, +@@ -1037,7 +1009,7 @@ struct ScopeExitGuard + f: F, + } + +-impl Drop for ScopeExitGuard ++impl Drop for ScopeExitGuard + where F: FnMut(&Data, &mut T) + { + fn drop(&mut self) {