From 5e7d3d52891dda390d3d38df17e7c598ce8b38e9 Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sat, 23 Jul 2022 17:19:03 +0300 Subject: [PATCH 1/6] Cargo fmt --- benches/arraystring.rs | 21 ++-- benches/extend.rs | 19 +-- src/array_string.rs | 206 ++++++++++++++++++-------------- src/arrayvec.rs | 263 +++++++++++++++++++++++++---------------- src/arrayvec_impl.rs | 9 +- src/char.rs | 25 ++-- src/errors.rs | 13 +- src/lib.rs | 18 +-- src/utils.rs | 1 - tests/serde.rs | 58 +++++---- tests/tests.rs | 119 +++++++++---------- 11 files changed, 412 insertions(+), 340 deletions(-) diff --git a/benches/arraystring.rs b/benches/arraystring.rs index 5b986fa..fabb8cd 100644 --- a/benches/arraystring.rs +++ b/benches/arraystring.rs @@ -1,6 +1,6 @@ - extern crate arrayvec; -#[macro_use] extern crate bencher; +#[macro_use] +extern crate bencher; use arrayvec::ArrayString; @@ -10,8 +10,7 @@ fn try_push_c(b: &mut Bencher) { let mut v = ArrayString::<512>::new(); b.iter(|| { v.clear(); - while v.try_push('c').is_ok() { - } + while v.try_push('c').is_ok() {} v.len() }); b.bytes = v.capacity() as u64; @@ -21,8 +20,7 @@ fn try_push_alpha(b: &mut Bencher) { let mut v = ArrayString::<512>::new(); b.iter(|| { v.clear(); - while v.try_push('α').is_ok() { - } + while v.try_push('α').is_ok() {} v.len() }); b.bytes = v.capacity() as u64; @@ -85,6 +83,13 @@ fn push_string(b: &mut Bencher) { b.bytes = v.capacity() as u64; } -benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c, - push_alpha, push_string); +benchmark_group!( + benches, + try_push_c, + try_push_alpha, + try_push_string, + push_c, + push_alpha, + push_string +); benchmark_main!(benches); diff --git a/benches/extend.rs b/benches/extend.rs index ba33a93..7aad2c7 100644 --- a/benches/extend.rs +++ b/benches/extend.rs @@ -1,13 +1,13 @@ - extern crate arrayvec; -#[macro_use] extern crate bencher; +#[macro_use] +extern crate bencher; use std::io::Write; use arrayvec::ArrayVec; -use bencher::Bencher; use bencher::black_box; +use bencher::Bencher; fn extend_with_constant(b: &mut Bencher) { let mut v = ArrayVec::::new(); @@ -67,12 +67,13 @@ fn extend_from_slice(b: &mut Bencher) { b.bytes = v.capacity() as u64; } -benchmark_group!(benches, - extend_with_constant, - extend_with_range, - extend_with_slice, - extend_with_write, - extend_from_slice +benchmark_group!( + benches, + extend_with_constant, + extend_with_range, + extend_with_slice, + extend_with_write, + extend_from_slice ); benchmark_main!(benches); diff --git a/src/array_string.rs b/src/array_string.rs index c4712a0..230fcdd 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -11,14 +11,13 @@ use std::str; use std::str::FromStr; use std::str::Utf8Error; -use crate::CapacityError; -use crate::LenUint; use crate::char::encode_utf8; use crate::utils::MakeMaybeUninit; +use crate::CapacityError; +use crate::LenUint; -#[cfg(feature="serde")] -use serde::{Serialize, Deserialize, Serializer, Deserializer}; - +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// A string with a fixed capacity. /// @@ -37,16 +36,14 @@ pub struct ArrayString { len: LenUint, } -impl Default for ArrayString -{ +impl Default for ArrayString { /// Return an empty `ArrayString` fn default() -> ArrayString { ArrayString::new() } } -impl ArrayString -{ +impl ArrayString { /// Create a new empty `ArrayString`. /// /// Capacity is inferred from the type parameter. @@ -62,7 +59,10 @@ impl ArrayString pub fn new() -> ArrayString { assert_capacity_limit!(CAP); unsafe { - ArrayString { xs: MaybeUninit::uninit().assume_init(), len: 0 } + ArrayString { + xs: MaybeUninit::uninit().assume_init(), + len: 0, + } } } @@ -77,16 +77,23 @@ impl ArrayString /// ``` pub const fn new_const() -> ArrayString { assert_capacity_limit_const!(CAP); - ArrayString { xs: MakeMaybeUninit::ARRAY, len: 0 } + ArrayString { + xs: MakeMaybeUninit::ARRAY, + len: 0, + } } /// Return the length of the string. #[inline] - pub const fn len(&self) -> usize { self.len as usize } + pub const fn len(&self) -> usize { + self.len as usize + } /// Returns whether the string is empty. #[inline] - pub const fn is_empty(&self) -> bool { self.len() == 0 } + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } /// Create a new `ArrayString` from a `str`. /// @@ -146,7 +153,7 @@ impl ArrayString unsafe { ArrayString { xs: MaybeUninit::zeroed().assume_init(), - len: CAP as _ + len: CAP as _, } } } @@ -160,7 +167,9 @@ impl ArrayString /// assert_eq!(string.capacity(), 3); /// ``` #[inline(always)] - pub const fn capacity(&self) -> usize { CAP } + pub const fn capacity(&self) -> usize { + CAP + } /// Return if the `ArrayString` is completely filled. /// @@ -172,7 +181,9 @@ impl ArrayString /// string.push_str("A"); /// assert!(string.is_full()); /// ``` - pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + pub const fn is_full(&self) -> bool { + self.len() == self.capacity() + } /// Returns the capacity left in the `ArrayString`. /// @@ -296,7 +307,7 @@ impl ArrayString /// /// ``` /// use arrayvec::ArrayString; - /// + /// /// let mut s = ArrayString::<3>::from("foo").unwrap(); /// /// assert_eq!(s.pop(), Some('o')); @@ -336,7 +347,7 @@ impl ArrayString pub fn truncate(&mut self, new_len: usize) { if new_len <= self.len() { assert!(self.is_char_boundary(new_len)); - unsafe { + unsafe { // In libstd truncate is called on the underlying vector, // which in turns drops each element. // As we know we don't have to worry about Drop, @@ -356,7 +367,7 @@ impl ArrayString /// /// ``` /// use arrayvec::ArrayString; - /// + /// /// let mut s = ArrayString::<3>::from("foo").unwrap(); /// /// assert_eq!(s.remove(0), 'f'); @@ -372,9 +383,11 @@ impl ArrayString let next = idx + ch.len_utf8(); let len = self.len(); unsafe { - ptr::copy(self.as_ptr().add(next), - self.as_mut_ptr().add(idx), - len - next); + ptr::copy( + self.as_ptr().add(next), + self.as_mut_ptr().add(idx), + len - next, + ); self.set_len(len - (next - idx)); } ch @@ -419,8 +432,7 @@ impl ArrayString } } -impl Deref for ArrayString -{ +impl Deref for ArrayString { type Target = str; #[inline] fn deref(&self) -> &str { @@ -431,8 +443,7 @@ impl Deref for ArrayString } } -impl DerefMut for ArrayString -{ +impl DerefMut for ArrayString { #[inline] fn deref_mut(&mut self) -> &mut str { unsafe { @@ -443,60 +454,58 @@ impl DerefMut for ArrayString } } -impl PartialEq for ArrayString -{ +impl PartialEq for ArrayString { fn eq(&self, rhs: &Self) -> bool { **self == **rhs } } -impl PartialEq for ArrayString -{ +impl PartialEq for ArrayString { fn eq(&self, rhs: &str) -> bool { &**self == rhs } } -impl PartialEq> for str -{ +impl PartialEq> for str { fn eq(&self, rhs: &ArrayString) -> bool { self == &**rhs } } -impl Eq for ArrayString -{ } +impl Eq for ArrayString {} -impl Hash for ArrayString -{ +impl Hash for ArrayString { fn hash(&self, h: &mut H) { (**self).hash(h) } } -impl Borrow for ArrayString -{ - fn borrow(&self) -> &str { self } +impl Borrow for ArrayString { + fn borrow(&self) -> &str { + self + } } -impl AsRef for ArrayString -{ - fn as_ref(&self) -> &str { self } +impl AsRef for ArrayString { + fn as_ref(&self) -> &str { + self + } } -impl fmt::Debug for ArrayString -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +impl fmt::Debug for ArrayString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } } -impl fmt::Display for ArrayString -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +impl fmt::Display for ArrayString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } } /// `Write` appends written data to the end of the string. -impl fmt::Write for ArrayString -{ +impl fmt::Write for ArrayString { fn write_char(&mut self, c: char) -> fmt::Result { self.try_push(c).map_err(|_| fmt::Error) } @@ -506,8 +515,7 @@ impl fmt::Write for ArrayString } } -impl Clone for ArrayString -{ +impl Clone for ArrayString { fn clone(&self) -> ArrayString { *self } @@ -518,48 +526,67 @@ impl Clone for ArrayString } } -impl PartialOrd for ArrayString -{ +impl PartialOrd for ArrayString { fn partial_cmp(&self, rhs: &Self) -> Option { (**self).partial_cmp(&**rhs) } - fn lt(&self, rhs: &Self) -> bool { **self < **rhs } - fn le(&self, rhs: &Self) -> bool { **self <= **rhs } - fn gt(&self, rhs: &Self) -> bool { **self > **rhs } - fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } + fn lt(&self, rhs: &Self) -> bool { + **self < **rhs + } + fn le(&self, rhs: &Self) -> bool { + **self <= **rhs + } + fn gt(&self, rhs: &Self) -> bool { + **self > **rhs + } + fn ge(&self, rhs: &Self) -> bool { + **self >= **rhs + } } -impl PartialOrd for ArrayString -{ +impl PartialOrd for ArrayString { fn partial_cmp(&self, rhs: &str) -> Option { (**self).partial_cmp(rhs) } - fn lt(&self, rhs: &str) -> bool { &**self < rhs } - fn le(&self, rhs: &str) -> bool { &**self <= rhs } - fn gt(&self, rhs: &str) -> bool { &**self > rhs } - fn ge(&self, rhs: &str) -> bool { &**self >= rhs } + fn lt(&self, rhs: &str) -> bool { + &**self < rhs + } + fn le(&self, rhs: &str) -> bool { + &**self <= rhs + } + fn gt(&self, rhs: &str) -> bool { + &**self > rhs + } + fn ge(&self, rhs: &str) -> bool { + &**self >= rhs + } } -impl PartialOrd> for str -{ +impl PartialOrd> for str { fn partial_cmp(&self, rhs: &ArrayString) -> Option { self.partial_cmp(&**rhs) } - fn lt(&self, rhs: &ArrayString) -> bool { self < &**rhs } - fn le(&self, rhs: &ArrayString) -> bool { self <= &**rhs } - fn gt(&self, rhs: &ArrayString) -> bool { self > &**rhs } - fn ge(&self, rhs: &ArrayString) -> bool { self >= &**rhs } + fn lt(&self, rhs: &ArrayString) -> bool { + self < &**rhs + } + fn le(&self, rhs: &ArrayString) -> bool { + self <= &**rhs + } + fn gt(&self, rhs: &ArrayString) -> bool { + self > &**rhs + } + fn ge(&self, rhs: &ArrayString) -> bool { + self >= &**rhs + } } -impl Ord for ArrayString -{ +impl Ord for ArrayString { fn cmp(&self, rhs: &Self) -> cmp::Ordering { (**self).cmp(&**rhs) } } -impl FromStr for ArrayString -{ +impl FromStr for ArrayString { type Err = CapacityError; fn from_str(s: &str) -> Result { @@ -567,23 +594,23 @@ impl FromStr for ArrayString } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] /// Requires crate feature `"serde"` -impl Serialize for ArrayString -{ +impl Serialize for ArrayString { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { serializer.serialize_str(&*self) } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] /// Requires crate feature `"serde"` -impl<'de, const CAP: usize> Deserialize<'de> for ArrayString -{ +impl<'de, const CAP: usize> Deserialize<'de> for ArrayString { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { use serde::de::{self, Visitor}; use std::marker::PhantomData; @@ -598,15 +625,18 @@ impl<'de, const CAP: usize> Deserialize<'de> for ArrayString } fn visit_str(self, v: &str) -> Result - where E: de::Error, + where + E: de::Error, { ArrayString::from(v).map_err(|_| E::invalid_length(v.len(), &self)) } fn visit_bytes(self, v: &[u8]) -> Result - where E: de::Error, + where + E: de::Error, { - let s = str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self))?; + let s = str::from_utf8(v) + .map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self))?; ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self)) } @@ -616,8 +646,7 @@ impl<'de, const CAP: usize> Deserialize<'de> for ArrayString } } -impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString -{ +impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString { type Error = CapacityError<&'a str>; fn try_from(f: &'a str) -> Result { @@ -627,8 +656,7 @@ impl<'a, const CAP: usize> TryFrom<&'a str> for ArrayString } } -impl<'a, const CAP: usize> TryFrom> for ArrayString -{ +impl<'a, const CAP: usize> TryFrom> for ArrayString { type Error = CapacityError; fn try_from(f: fmt::Arguments<'a>) -> Result { diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e69e60c..0b29620 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -1,4 +1,3 @@ - use std::cmp; use std::iter; use std::mem; @@ -8,22 +7,22 @@ use std::slice; // extra traits use std::borrow::{Borrow, BorrowMut}; -use std::hash::{Hash, Hasher}; use std::fmt; +use std::hash::{Hash, Hasher}; -#[cfg(feature="std")] +#[cfg(feature = "std")] use std::io; use std::mem::ManuallyDrop; use std::mem::MaybeUninit; -#[cfg(feature="serde")] -use serde::{Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::LenUint; -use crate::errors::CapacityError; use crate::arrayvec_impl::ArrayVecImpl; +use crate::errors::CapacityError; use crate::utils::MakeMaybeUninit; +use crate::LenUint; /// A vector with a fixed capacity. /// @@ -55,9 +54,15 @@ impl Drop for ArrayVec { macro_rules! panic_oob { ($method_name:expr, $index:expr, $len:expr) => { - panic!(concat!("ArrayVec::", $method_name, ": index {} is out of bounds in vector of length {}"), - $index, $len) - } + panic!( + concat!( + "ArrayVec::", + $method_name, + ": index {} is out of bounds in vector of length {}" + ), + $index, $len + ) + }; } impl ArrayVec { @@ -80,7 +85,10 @@ impl ArrayVec { pub fn new() -> ArrayVec { assert_capacity_limit!(CAP); unsafe { - ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 } + ArrayVec { + xs: MaybeUninit::uninit().assume_init(), + len: 0, + } } } @@ -95,7 +103,10 @@ impl ArrayVec { /// ``` pub const fn new_const() -> ArrayVec { assert_capacity_limit_const!(CAP); - ArrayVec { xs: MakeMaybeUninit::ARRAY, len: 0 } + ArrayVec { + xs: MakeMaybeUninit::ARRAY, + len: 0, + } } /// Return the number of elements in the `ArrayVec`. @@ -108,7 +119,9 @@ impl ArrayVec { /// assert_eq!(array.len(), 2); /// ``` #[inline(always)] - pub const fn len(&self) -> usize { self.len as usize } + pub const fn len(&self) -> usize { + self.len as usize + } /// Returns whether the `ArrayVec` is empty. /// @@ -120,7 +133,9 @@ impl ArrayVec { /// assert_eq!(array.is_empty(), true); /// ``` #[inline] - pub const fn is_empty(&self) -> bool { self.len() == 0 } + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } /// Return the capacity of the `ArrayVec`. /// @@ -131,7 +146,9 @@ impl ArrayVec { /// assert_eq!(array.capacity(), 3); /// ``` #[inline(always)] - pub const fn capacity(&self) -> usize { CAP } + pub const fn capacity(&self) -> usize { + CAP + } /// Return true if the `ArrayVec` is completely filled to its capacity, false otherwise. /// @@ -143,7 +160,9 @@ impl ArrayVec { /// array.push(1); /// assert!(array.is_full()); /// ``` - pub const fn is_full(&self) -> bool { self.len() == self.capacity() } + pub const fn is_full(&self) -> bool { + self.len() == self.capacity() + } /// Returns the capacity left in the `ArrayVec`. /// @@ -251,7 +270,6 @@ impl ArrayVec { 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) @@ -311,7 +329,8 @@ impl ArrayVec { let len = self.len(); // follows is just like Vec - unsafe { // infallible + unsafe { + // infallible // The spot to put the new value { let p: *mut _ = self.get_unchecked_ptr(index); @@ -366,9 +385,7 @@ impl ArrayVec { /// ``` pub fn swap_remove(&mut self, index: usize) -> T { self.swap_pop(index) - .unwrap_or_else(|| { - panic_oob!("swap_remove", index, self.len()) - }) + .unwrap_or_else(|| panic_oob!("swap_remove", index, self.len())) } /// Remove the element at `index` and swap the last element into its place. @@ -414,9 +431,7 @@ impl ArrayVec { /// ``` pub fn remove(&mut self, index: usize) -> T { self.pop_at(index) - .unwrap_or_else(|| { - panic_oob!("remove", index, self.len()) - }) + .unwrap_or_else(|| panic_oob!("remove", index, self.len())) } /// Remove the element at `index` and shift down the following elements. @@ -457,7 +472,8 @@ impl ArrayVec { /// assert_eq!(&array[..], &[1, 3]); /// ``` pub fn retain(&mut self, mut f: F) - where F: FnMut(&mut T) -> bool + where + F: FnMut(&mut T) -> bool, { // Check the implementation of // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain @@ -480,8 +496,10 @@ impl ArrayVec { 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 + self.v + .as_mut_ptr() + .add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len, ); } } @@ -491,12 +509,17 @@ impl ArrayVec { } } - let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; + 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>( f: &mut F, - g: &mut BackshiftOnDrop<'_, T, CAP> + g: &mut BackshiftOnDrop<'_, T, CAP>, ) -> bool { let cur = unsafe { g.v.as_mut_ptr().add(g.processed_len) }; if !f(unsafe { &mut *cur }) { @@ -562,7 +585,8 @@ impl ArrayVec { /// /// [`remaining_capacity`]: #method.remaining_capacity pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError> - where T: Copy, + where + T: Copy, { if self.remaining_capacity() < other.len() { return Err(CapacityError::new(())); @@ -598,7 +622,8 @@ impl ArrayVec { /// assert_eq!(&v2[..], &[1, 2]); /// ``` pub fn drain(&mut self, range: R) -> Drain - where R: RangeBounds + where + R: RangeBounds, { // Memory safety // @@ -624,8 +649,7 @@ impl ArrayVec { self.drain_range(start, end) } - fn drain_range(&mut self, start: usize, end: usize) -> Drain - { + fn drain_range(&mut self, start: usize, end: usize) -> Drain { let len = self.len(); // bounds check happens here (before length is changed!) @@ -677,7 +701,7 @@ impl ArrayVec { /// assert_eq!([0, 1, 2, 3], v.take().into_inner().unwrap()); /// assert!(v.is_empty()); /// ``` - pub fn take(&mut self) -> Self { + pub fn take(&mut self) -> Self { mem::replace(self, Self::new()) } @@ -706,7 +730,9 @@ impl ArrayVecImpl for ArrayVec { type Item = T; const CAPACITY: usize = CAP; - fn len(&self) -> usize { self.len() } + fn len(&self) -> usize { + self.len() + } unsafe fn set_len(&mut self, length: usize) { debug_assert!(length <= CAP); @@ -737,7 +763,6 @@ impl DerefMut for ArrayVec { } } - /// Create an `ArrayVec` from an array. /// /// ``` @@ -760,7 +785,6 @@ impl From<[T; CAP]> for ArrayVec { } } - /// Try to create an `ArrayVec` from a slice. This will return an error if the slice was too big to /// fit. /// @@ -773,7 +797,8 @@ impl From<[T; CAP]> for ArrayVec { /// assert_eq!(array.capacity(), 4); /// ``` impl std::convert::TryFrom<&[T]> for ArrayVec - where T: Clone, +where + T: Clone, { type Error = CapacityError; @@ -788,7 +813,6 @@ impl std::convert::TryFrom<&[T]> for ArrayVec } } - /// Iterate the `ArrayVec` with references to each element. /// /// ``` @@ -803,7 +827,9 @@ impl std::convert::TryFrom<&[T]> for ArrayVec impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a ArrayVec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { self.iter() } + fn into_iter(self) -> Self::IntoIter { + self.iter() + } } /// Iterate the `ArrayVec` with mutable references to each element. @@ -820,7 +846,9 @@ impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a ArrayVec { impl<'a, T: 'a, const CAP: usize> IntoIterator for &'a mut ArrayVec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; - fn into_iter(self) -> Self::IntoIter { self.iter_mut() } + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } } /// Iterate the `ArrayVec` with each element by value. @@ -838,11 +866,10 @@ impl IntoIterator for ArrayVec { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { - IntoIter { index: 0, v: self, } + IntoIter { index: 0, v: self } } } - /// By-value iterator for `ArrayVec`. pub struct IntoIter { index: usize, @@ -884,7 +911,7 @@ impl DoubleEndedIterator for IntoIter { } } -impl ExactSizeIterator for IntoIter { } +impl ExactSizeIterator for IntoIter {} impl Drop for IntoIter { fn drop(&mut self) { @@ -893,16 +920,15 @@ impl Drop for IntoIter { 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); + 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, +where + T: Clone, { fn clone(&self) -> IntoIter { let mut v = ArrayVec::new(); @@ -916,9 +942,7 @@ where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list() - .entries(&self.v[self.index..]) - .finish() + f.debug_list().entries(&self.v[self.index..]).finish() } } @@ -940,11 +964,9 @@ impl<'a, T: '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 _) - } - ) + self.iter + .next() + .map(|elt| unsafe { ptr::read(elt as *const _) }) } fn size_hint(&self) -> (usize, Option) { @@ -952,14 +974,11 @@ impl<'a, T: 'a, const CAP: usize> Iterator for Drain<'a, T, CAP> { } } -impl<'a, T: 'a, const CAP: usize> DoubleEndedIterator for Drain<'a, T, CAP> -{ +impl<'a, T: '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 _) - } - ) + self.iter + .next_back() + .map(|elt| unsafe { ptr::read(elt as *const _) }) } } @@ -970,7 +989,7 @@ impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { // len is currently 0 so panicking while dropping will not cause a double drop. // exhaust self first - while let Some(_) = self.next() { } + while let Some(_) = self.next() {} if self.tail_len > 0 { unsafe { @@ -988,7 +1007,8 @@ impl<'a, T: 'a, const CAP: usize> Drop for Drain<'a, T, CAP> { } struct ScopeExitGuard - where F: FnMut(&Data, &mut T) +where + F: FnMut(&Data, &mut T), { value: T, data: Data, @@ -996,26 +1016,23 @@ struct ScopeExitGuard } impl Drop for ScopeExitGuard - where F: FnMut(&Data, &mut T) +where + F: FnMut(&Data, &mut T), { fn drop(&mut self) { (self.f)(&self.data, &mut self.value) } } - - /// Extend the `ArrayVec` with an iterator. -/// +/// /// ***Panics*** if extending the vector exceeds its capacity. impl Extend for ArrayVec { /// Extend the `ArrayVec` with an iterator. - /// + /// /// ***Panics*** if extending the vector exceeds its capacity. - fn extend>(&mut self, iter: I) { - unsafe { - self.extend_from_iter::<_, true>(iter) - } + fn extend>(&mut self, iter: I) { + unsafe { self.extend_from_iter::<_, true>(iter) } } } @@ -1033,7 +1050,8 @@ impl ArrayVec { /// Unsafe because if CHECK is false, the length of the input is not checked. /// The caller must ensure the length of the input fits in the capacity. pub(crate) unsafe fn extend_from_iter(&mut self, iterable: I) - where I: IntoIterator + where + I: IntoIterator, { let take = self.capacity() - self.len(); let len = self.len(); @@ -1048,12 +1066,14 @@ impl ArrayVec { 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(); } + if ptr == end_ptr && CHECK { + extend_panic(); + } debug_assert_ne!(ptr, end_ptr); ptr.write(elt); ptr = raw_ptr_add(ptr, 1); @@ -1067,12 +1087,17 @@ impl ArrayVec { /// Extend the ArrayVec 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 + 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 }; + let slice = if take < slice.len() { + &slice[..take] + } else { + slice + }; self.extend_from_iter::<_, false>(slice.iter().cloned()); } } @@ -1089,13 +1114,13 @@ unsafe fn raw_ptr_add(ptr: *mut T, offset: usize) -> *mut T { } /// Create an `ArrayVec` from an iterator. -/// +/// /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. impl iter::FromIterator for ArrayVec { /// Create an `ArrayVec` from an iterator. - /// + /// /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { let mut array = ArrayVec::new(); array.extend(iter); array @@ -1103,7 +1128,8 @@ impl iter::FromIterator for ArrayVec { } impl Clone for ArrayVec - where T: Clone +where + T: Clone, { fn clone(&self) -> Self { self.iter().cloned().collect() @@ -1125,7 +1151,8 @@ impl Clone for ArrayVec } impl Hash for ArrayVec - where T: Hash +where + T: Hash, { fn hash(&self, state: &mut H) { Hash::hash(&**self, state) @@ -1133,7 +1160,8 @@ impl Hash for ArrayVec } impl PartialEq for ArrayVec - where T: PartialEq +where + T: PartialEq, { fn eq(&self, other: &Self) -> bool { **self == **other @@ -1141,33 +1169,47 @@ impl PartialEq for ArrayVec } impl PartialEq<[T]> for ArrayVec - where T: PartialEq +where + T: PartialEq, { fn eq(&self, other: &[T]) -> bool { **self == *other } } -impl Eq for ArrayVec where T: Eq { } +impl Eq for ArrayVec where T: Eq {} impl Borrow<[T]> for ArrayVec { - fn borrow(&self) -> &[T] { self } + fn borrow(&self) -> &[T] { + self + } } impl BorrowMut<[T]> for ArrayVec { - fn borrow_mut(&mut self) -> &mut [T] { self } + fn borrow_mut(&mut self) -> &mut [T] { + self + } } impl AsRef<[T]> for ArrayVec { - fn as_ref(&self) -> &[T] { self } + fn as_ref(&self) -> &[T] { + self + } } impl AsMut<[T]> for ArrayVec { - fn as_mut(&mut self) -> &mut [T] { self } + fn as_mut(&mut self) -> &mut [T] { + self + } } -impl fmt::Debug for ArrayVec where T: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } +impl fmt::Debug for ArrayVec +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } } impl Default for ArrayVec { @@ -1177,7 +1219,10 @@ impl Default for ArrayVec { } } -impl PartialOrd for ArrayVec where T: PartialOrd { +impl PartialOrd for ArrayVec +where + T: PartialOrd, +{ fn partial_cmp(&self, other: &Self) -> Option { (**self).partial_cmp(other) } @@ -1199,13 +1244,16 @@ impl PartialOrd for ArrayVec where T: PartialOrd { } } -impl Ord for ArrayVec where T: Ord { +impl Ord for ArrayVec +where + T: Ord, +{ fn cmp(&self, other: &Self) -> cmp::Ordering { (**self).cmp(other) } } -#[cfg(feature="std")] +#[cfg(feature = "std")] /// `Write` appends written data to the end of the vector. /// /// Requires `features="std"`. @@ -1216,29 +1264,35 @@ impl io::Write for ArrayVec { debug_assert!(_result.is_ok()); Ok(len) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] /// Requires crate feature `"serde"` impl Serialize for ArrayVec { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { serializer.collect_seq(self) } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] /// Requires crate feature `"serde"` impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { - use serde::de::{Visitor, SeqAccess, Error}; + use serde::de::{Error, SeqAccess, Visitor}; use std::marker::PhantomData; - struct ArrayVecVisitor<'de, T: Deserialize<'de>, const CAP: usize>(PhantomData<(&'de (), [T; CAP])>); + struct ArrayVecVisitor<'de, T: Deserialize<'de>, const CAP: usize>( + PhantomData<(&'de (), [T; CAP])>, + ); impl<'de, T: Deserialize<'de>, const CAP: usize> Visitor<'de> for ArrayVecVisitor<'de, T, CAP> { type Value = ArrayVec; @@ -1248,7 +1302,8 @@ impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec(self, mut seq: SA) -> Result - where SA: SeqAccess<'de>, + where + SA: SeqAccess<'de>, { let mut values = ArrayVec::::new(); diff --git a/src/arrayvec_impl.rs b/src/arrayvec_impl.rs index 6c09834..ae4772f 100644 --- a/src/arrayvec_impl.rs +++ b/src/arrayvec_impl.rs @@ -16,17 +16,13 @@ pub(crate) trait ArrayVecImpl { /// Return a slice containing all elements of the vector. fn as_slice(&self) -> &[Self::Item] { let len = self.len(); - unsafe { - slice::from_raw_parts(self.as_ptr(), len) - } + unsafe { slice::from_raw_parts(self.as_ptr(), len) } } /// Return a mutable slice containing all elements of the vector. fn as_mut_slice(&mut self) -> &mut [Self::Item] { let len = self.len(); - unsafe { - std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) - } + unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) } } /// Return a raw pointer to the vector's buffer. @@ -83,4 +79,3 @@ pub(crate) trait ArrayVecImpl { } } } - diff --git a/src/char.rs b/src/char.rs index 939b6b4..77df311 100644 --- a/src/char.rs +++ b/src/char.rs @@ -11,13 +11,13 @@ // Original authors: alexchrichton, bluss // UTF-8 ranges and tags for encoding characters -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; /// Placeholder pub struct EncodeUtf8Error; @@ -29,8 +29,7 @@ pub struct EncodeUtf8Error; /// /// Safety: `ptr` must be writable for `len` bytes. #[inline] -pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result -{ +pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result { let code = ch as u32; if code < MAX_ONE_B && len >= 1 { ptr.add(0).write(code as u8); @@ -41,20 +40,19 @@ pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result= 3 { ptr.add(0).write((code >> 12 & 0x0F) as u8 | TAG_THREE_B); - ptr.add(1).write((code >> 6 & 0x3F) as u8 | TAG_CONT); + ptr.add(1).write((code >> 6 & 0x3F) as u8 | TAG_CONT); ptr.add(2).write((code & 0x3F) as u8 | TAG_CONT); return Ok(3); } else if len >= 4 { ptr.add(0).write((code >> 18 & 0x07) as u8 | TAG_FOUR_B); ptr.add(1).write((code >> 12 & 0x3F) as u8 | TAG_CONT); - ptr.add(2).write((code >> 6 & 0x3F) as u8 | TAG_CONT); + ptr.add(2).write((code >> 6 & 0x3F) as u8 | TAG_CONT); ptr.add(3).write((code & 0x3F) as u8 | TAG_CONT); return Ok(4); }; Err(EncodeUtf8Error) } - #[test] #[cfg_attr(miri, ignore)] // Miri is too slow fn test_encode_utf8() { @@ -62,7 +60,9 @@ fn test_encode_utf8() { let mut data = [0u8; 16]; for codepoint in 0..=(std::char::MAX as u32) { if let Some(ch) = std::char::from_u32(codepoint) { - for elt in &mut data { *elt = 0; } + for elt in &mut data { + *elt = 0; + } let ptr = data.as_mut_ptr(); let len = data.len(); unsafe { @@ -89,4 +89,3 @@ fn test_encode_utf8_oob() { } } } - diff --git a/src/errors.rs b/src/errors.rs index 7ca3ebc..19e479e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,8 +1,8 @@ -use std::fmt; -#[cfg(feature="std")] +#[cfg(feature = "std")] use std::any::Any; -#[cfg(feature="std")] +#[cfg(feature = "std")] use std::error::Error; +use std::fmt; /// Error value indicating insufficient capacity #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] @@ -13,9 +13,7 @@ pub struct CapacityError { impl CapacityError { /// Create a new `CapacityError` from `element`. pub const fn new(element: T) -> CapacityError { - CapacityError { - element: element, - } + CapacityError { element: element } } /// Extract the overflowing element @@ -31,7 +29,7 @@ impl CapacityError { const CAPERROR: &'static str = "insufficient capacity"; -#[cfg(feature="std")] +#[cfg(feature = "std")] /// Requires `features="std"`. impl Error for CapacityError {} @@ -46,4 +44,3 @@ impl fmt::Debug for CapacityError { write!(f, "{}: {}", "CapacityError", CAPERROR) } } - diff --git a/src/lib.rs b/src/lib.rs index 5dc0273..68fcb11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! **arrayvec** provides the types [`ArrayVec`] and [`ArrayString`]: +//! **arrayvec** provides the types [`ArrayVec`] and [`ArrayString`]: //! array-backed vector and string types, which store their contents inline. //! //! The arrayvec package has the following cargo features: @@ -15,13 +15,13 @@ //! //! This version of arrayvec requires Rust 1.51 or later. //! -#![doc(html_root_url="https://docs.rs/arrayvec/0.7/")] -#![cfg_attr(not(feature="std"), no_std)] +#![doc(html_root_url = "https://docs.rs/arrayvec/0.7/")] +#![cfg_attr(not(feature = "std"), no_std)] -#[cfg(feature="serde")] +#[cfg(feature = "serde")] extern crate serde; -#[cfg(not(feature="std"))] +#[cfg(not(feature = "std"))] extern crate core as std; pub(crate) type LenUint = u32; @@ -33,7 +33,7 @@ macro_rules! assert_capacity_limit { panic!("ArrayVec: largest supported capacity is u32::MAX") } } - } + }; } macro_rules! assert_capacity_limit_const { @@ -46,9 +46,9 @@ macro_rules! assert_capacity_limit_const { } } -mod arrayvec_impl; -mod arrayvec; mod array_string; +mod arrayvec; +mod arrayvec_impl; mod char; mod errors; mod utils; @@ -56,4 +56,4 @@ mod utils; pub use crate::array_string::ArrayString; pub use crate::errors::CapacityError; -pub use crate::arrayvec::{ArrayVec, IntoIter, Drain}; +pub use crate::arrayvec::{ArrayVec, Drain, IntoIter}; diff --git a/src/utils.rs b/src/utils.rs index b8e5ddb..b425a51 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,4 +8,3 @@ impl MakeMaybeUninit { pub(crate) const ARRAY: [MaybeUninit; N] = [Self::VALUE; N]; } - diff --git a/tests/serde.rs b/tests/serde.rs index f02c693..58630f5 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -5,19 +5,15 @@ extern crate serde_test; mod array_vec { use arrayvec::ArrayVec; - use serde_test::{Token, assert_tokens, assert_de_tokens_error}; + use serde_test::{assert_de_tokens_error, assert_tokens, Token}; #[test] fn test_ser_de_empty() { let vec = ArrayVec::::new(); - assert_tokens(&vec, &[ - Token::Seq { len: Some(0) }, - Token::SeqEnd, - ]); + assert_tokens(&vec, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); } - #[test] fn test_ser_de() { let mut vec = ArrayVec::::new(); @@ -25,55 +21,57 @@ mod array_vec { vec.push(55); vec.push(123); - assert_tokens(&vec, &[ - Token::Seq { len: Some(3) }, - Token::U32(20), - Token::U32(55), - Token::U32(123), - Token::SeqEnd, - ]); + assert_tokens( + &vec, + &[ + Token::Seq { len: Some(3) }, + Token::U32(20), + Token::U32(55), + Token::U32(123), + Token::SeqEnd, + ], + ); } #[test] fn test_de_too_large() { - assert_de_tokens_error::>(&[ - Token::Seq { len: Some(3) }, - Token::U32(13), - Token::U32(42), - Token::U32(68), - ], "invalid length 3, expected an array with no more than 2 items"); + assert_de_tokens_error::>( + &[ + Token::Seq { len: Some(3) }, + Token::U32(13), + Token::U32(42), + Token::U32(68), + ], + "invalid length 3, expected an array with no more than 2 items", + ); } } mod array_string { use arrayvec::ArrayString; - use serde_test::{Token, assert_tokens, assert_de_tokens_error}; + use serde_test::{assert_de_tokens_error, assert_tokens, Token}; #[test] fn test_ser_de_empty() { let string = ArrayString::<0>::new(); - assert_tokens(&string, &[ - Token::Str(""), - ]); + assert_tokens(&string, &[Token::Str("")]); } - #[test] fn test_ser_de() { let string = ArrayString::<9>::from("1234 abcd") .expect("expected exact specified capacity to be enough"); - assert_tokens(&string, &[ - Token::Str("1234 abcd"), - ]); + assert_tokens(&string, &[Token::Str("1234 abcd")]); } #[test] fn test_de_too_large() { - assert_de_tokens_error::>(&[ - Token::Str("afd") - ], "invalid length 3, expected a string no more than 2 bytes long"); + assert_de_tokens_error::>( + &[Token::Str("afd")], + "invalid length 3, expected a string no more than 2 bytes long", + ); } } diff --git a/tests/tests.rs b/tests/tests.rs index 2f8a5ef..9b51cd9 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,19 +1,19 @@ extern crate arrayvec; -#[macro_use] extern crate matches; +#[macro_use] +extern crate matches; -use arrayvec::ArrayVec; use arrayvec::ArrayString; -use std::mem; +use arrayvec::ArrayVec; use arrayvec::CapacityError; +use std::mem; use std::collections::HashMap; - #[test] fn test_simple() { use std::ops::Add; - let mut vec: ArrayVec, 3> = ArrayVec::new(); + let mut vec: ArrayVec, 3> = ArrayVec::new(); vec.push(vec![1, 2, 3, 4]); vec.push(vec![10]); @@ -29,7 +29,7 @@ fn test_simple() { #[test] fn test_capacity_left() { - let mut vec: ArrayVec = ArrayVec::new(); + let mut vec: ArrayVec = ArrayVec::new(); assert_eq!(vec.remaining_capacity(), 4); vec.push(1); assert_eq!(vec.remaining_capacity(), 3); @@ -43,7 +43,7 @@ fn test_capacity_left() { #[test] fn test_extend_from_slice() { - let mut vec: ArrayVec = ArrayVec::new(); + let mut vec: ArrayVec = ArrayVec::new(); vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); assert_eq!(vec.len(), 3); @@ -54,13 +54,13 @@ fn test_extend_from_slice() { #[test] fn test_extend_from_slice_error() { - let mut vec: ArrayVec = ArrayVec::new(); + let mut vec: ArrayVec = ArrayVec::new(); vec.try_extend_from_slice(&[1, 2, 3]).unwrap(); let res = vec.try_extend_from_slice(&[0; 8]); assert_matches!(res, Err(_)); - let mut vec: ArrayVec = ArrayVec::new(); + let mut vec: ArrayVec = ArrayVec::new(); let res = vec.try_extend_from_slice(&[0; 1]); assert_matches!(res, Err(_)); } @@ -70,14 +70,14 @@ fn test_try_from_slice_error() { use arrayvec::ArrayVec; use std::convert::TryInto as _; - let res: Result, _> = (&[1, 2, 3] as &[_]).try_into(); + let res: Result, _> = (&[1, 2, 3] as &[_]).try_into(); assert_matches!(res, Err(_)); } #[test] fn test_u16_index() { const N: usize = 4096; - let mut vec: ArrayVec<_, N> = ArrayVec::new(); + let mut vec: ArrayVec<_, N> = ArrayVec::new(); for _ in 0..N { assert!(vec.try_push(1u8).is_ok()); } @@ -113,7 +113,7 @@ fn test_drop() { } { - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(Bump(flag)); array.push(Bump(flag)); } @@ -123,7 +123,7 @@ fn test_drop() { flag.set(0); { - let mut array = ArrayVec::<_, 3>::new(); + let mut array = ArrayVec::<_, 3>::new(); array.push(vec![Bump(flag)]); array.push(vec![Bump(flag), Bump(flag)]); array.push(vec![]); @@ -142,7 +142,7 @@ fn test_drop() { // test into_inner flag.set(0); { - let mut array = ArrayVec::<_, 3>::new(); + let mut array = ArrayVec::<_, 3>::new(); array.push(Bump(flag)); array.push(Bump(flag)); array.push(Bump(flag)); @@ -156,7 +156,7 @@ fn test_drop() { // test take flag.set(0); { - let mut array1 = ArrayVec::<_, 3>::new(); + let mut array1 = ArrayVec::<_, 3>::new(); array1.push(Bump(flag)); array1.push(Bump(flag)); array1.push(Bump(flag)); @@ -171,7 +171,7 @@ fn test_drop() { // test cloning into_iter flag.set(0); { - let mut array = ArrayVec::<_, 3>::new(); + let mut array = ArrayVec::<_, 3>::new(); array.push(Bump(flag)); array.push(Bump(flag)); array.push(Bump(flag)); @@ -225,7 +225,7 @@ fn test_drop_panics() { flag.set(0); { - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(Bump(flag)); array.push(Bump(flag)); array.push(Bump(flag)); @@ -238,10 +238,9 @@ fn test_drop_panics() { // Check that all the elements drop, even if the first drop panics. assert_eq!(flag.get(), 3); - flag.set(0); { - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(Bump(flag)); array.push(Bump(flag)); array.push(Bump(flag)); @@ -258,22 +257,20 @@ fn test_drop_panics() { // Check that all the tail elements drop, even if the first drop panics. assert_eq!(flag.get(), tail_len as i32); } - - } #[test] fn test_extend() { let mut range = 0..10; - let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); assert_eq!(&array[..], &[0, 1, 2, 3, 4]); assert_eq!(range.next(), Some(5)); array.extend(range.by_ref().take(0)); assert_eq!(range.next(), Some(6)); - let mut array: ArrayVec<_, 10> = (0..3).collect(); + let mut array: ArrayVec<_, 10> = (0..3).collect(); assert_eq!(&array[..], &[0, 1, 2]); array.extend(3..5); assert_eq!(&array[..], &[0, 1, 2, 3, 4]); @@ -284,7 +281,7 @@ fn test_extend() { fn test_extend_capacity_panic_1() { let mut range = 0..10; - let _: ArrayVec<_, 5> = range.by_ref().collect(); + let _: ArrayVec<_, 5> = range.by_ref().collect(); } #[should_panic] @@ -292,7 +289,7 @@ fn test_extend_capacity_panic_1() { fn test_extend_capacity_panic_2() { let mut range = 0..10; - let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect(); assert_eq!(&array[..], &[0, 1, 2, 3, 4]); assert_eq!(range.next(), Some(5)); array.extend(range.by_ref().take(1)); @@ -300,7 +297,7 @@ fn test_extend_capacity_panic_2() { #[test] fn test_is_send_sync() { - let data = ArrayVec::, 5>::new(); + let data = ArrayVec::, 5>::new(); &data as &dyn Send; &data as &dyn Sync; } @@ -308,24 +305,24 @@ fn test_is_send_sync() { #[test] fn test_compact_size() { // 4 bytes + padding + length - type ByteArray = ArrayVec; + type ByteArray = ArrayVec; println!("{}", mem::size_of::()); assert!(mem::size_of::() <= 2 * mem::size_of::()); // just length - type EmptyArray = ArrayVec; + type EmptyArray = ArrayVec; println!("{}", mem::size_of::()); assert!(mem::size_of::() <= mem::size_of::()); // 3 elements + padding + length - type QuadArray = ArrayVec; + type QuadArray = ArrayVec; println!("{}", mem::size_of::()); assert!(mem::size_of::() <= 4 * 4 + mem::size_of::()); } #[test] fn test_still_works_with_option_arrayvec() { - type RefArray = ArrayVec<&'static i32, 2>; + type RefArray = ArrayVec<&'static i32, 2>; let array = Some(RefArray::new()); assert!(array.is_some()); println!("{:?}", array); @@ -341,7 +338,7 @@ fn test_drain() { v.extend(0..8); v.drain(1..4); assert_eq!(&v[..], &[0, 4, 5, 6, 7]); - let u: ArrayVec<_, 3> = v.drain(1..4).rev().collect(); + let u: ArrayVec<_, 3> = v.drain(1..4).rev().collect(); assert_eq!(&u[..], &[6, 5, 4]); assert_eq!(&v[..], &[0, 7]); v.drain(..); @@ -357,7 +354,7 @@ fn test_drain_range_inclusive() { v.extend(0..8); v.drain(1..=4); assert_eq!(&v[..], &[0, 5, 6, 7]); - let u: ArrayVec<_, 3> = v.drain(1..=2).rev().collect(); + let u: ArrayVec<_, 3> = v.drain(1..=2).rev().collect(); assert_eq!(&u[..], &[6, 5]); assert_eq!(&v[..], &[0, 7]); v.drain(..); @@ -407,7 +404,7 @@ fn test_drop_panic() { } } - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(DropPanic); } @@ -422,7 +419,7 @@ fn test_drop_panic_into_iter() { } } - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(DropPanic); array.into_iter(); } @@ -432,7 +429,7 @@ fn test_insert() { let mut v = ArrayVec::from([]); assert_matches!(v.try_push(1), Err(_)); - let mut v = ArrayVec::<_, 3>::new(); + let mut v = ArrayVec::<_, 3>::new(); v.insert(0, 0); v.insert(1, 1); //let ret1 = v.try_insert(3, 3); @@ -461,7 +458,7 @@ fn test_into_inner_1() { #[test] fn test_into_inner_2() { - let mut v = ArrayVec::::new(); + let mut v = ArrayVec::::new(); v.push("a".into()); v.push("b".into()); v.push("c".into()); @@ -471,25 +468,25 @@ fn test_into_inner_2() { #[test] fn test_into_inner_3() { - let mut v = ArrayVec::::new(); + let mut v = ArrayVec::::new(); v.extend(1..=4); assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]); } #[test] fn test_take() { - let mut v1 = ArrayVec::::new(); + let mut v1 = ArrayVec::::new(); v1.extend(1..=4); let v2 = v1.take(); assert!(v1.into_inner().is_err()); assert_eq!(v2.into_inner().unwrap(), [1, 2, 3, 4]); } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn test_write() { use std::io::Write; - let mut v = ArrayVec::<_, 8>::new(); + let mut v = ArrayVec::<_, 8>::new(); write!(&mut v, "\x01\x02\x03").unwrap(); assert_eq!(&v[..], &[1, 2, 3]); let r = v.write(&[9; 16]).unwrap(); @@ -499,16 +496,16 @@ fn test_write() { #[test] fn array_clone_from() { - let mut v = ArrayVec::<_, 4>::new(); + let mut v = ArrayVec::<_, 4>::new(); v.push(vec![1, 2]); v.push(vec![3, 4, 5]); v.push(vec![6]); let reference = v.to_vec(); - let mut u = ArrayVec::<_, 4>::new(); + let mut u = ArrayVec::<_, 4>::new(); u.clone_from(&v); assert_eq!(&u, &reference[..]); - let mut t = ArrayVec::<_, 4>::new(); + let mut t = ArrayVec::<_, 4>::new(); t.push(vec![97]); t.push(vec![]); t.push(vec![5, 6, 2]); @@ -520,7 +517,7 @@ fn array_clone_from() { assert_eq!(&t, &reference[..]); } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[test] fn test_string() { use std::error::Error; @@ -557,7 +554,7 @@ fn test_string() { #[test] fn test_string_from() { let text = "hello world"; - // Test `from` constructor + // Test `from` constructor let u = ArrayString::<11>::from(text).unwrap(); assert_eq!(&u, text); assert_eq!(u.len(), text.len()); @@ -604,10 +601,9 @@ fn test_string_push() { assert!(s.try_push('x').is_err()); } - #[test] fn test_insert_at_length() { - let mut v = ArrayVec::<_, 8>::new(); + let mut v = ArrayVec::<_, 8>::new(); let result1 = v.try_insert(0, "a"); let result2 = v.try_insert(1, "b"); assert!(result1.is_ok() && result2.is_ok()); @@ -617,7 +613,7 @@ fn test_insert_at_length() { #[should_panic] #[test] fn test_insert_out_of_bounds() { - let mut v = ArrayVec::<_, 8>::new(); + let mut v = ArrayVec::<_, 8>::new(); let _ = v.try_insert(1, "test"); } @@ -650,7 +646,7 @@ fn test_drop_in_insert() { flag.set(0); { - let mut array = ArrayVec::<_, 2>::new(); + let mut array = ArrayVec::<_, 2>::new(); array.push(Bump(flag)); array.insert(0, Bump(flag)); assert_eq!(flag.get(), 0); @@ -665,7 +661,7 @@ fn test_drop_in_insert() { #[test] fn test_pop_at() { - let mut v = ArrayVec::::new(); + let mut v = ArrayVec::::new(); let s = String::from; v.push(s("a")); v.push(s("b")); @@ -690,19 +686,19 @@ fn test_default() { use std::net; let s: ArrayString<4> = Default::default(); // Something without `Default` implementation. - let v: ArrayVec = Default::default(); + let v: ArrayVec = Default::default(); assert_eq!(s.len(), 0); assert_eq!(v.len(), 0); } -#[cfg(feature="array-sizes-33-128")] +#[cfg(feature = "array-sizes-33-128")] #[test] fn test_sizes_33_128() { ArrayVec::from([0u8; 52]); ArrayVec::from([0u8; 127]); } -#[cfg(feature="array-sizes-129-255")] +#[cfg(feature = "array-sizes-129-255")] #[test] fn test_sizes_129_255() { ArrayVec::from([0u8; 237]); @@ -715,14 +711,14 @@ fn test_extend_zst() { #[derive(Copy, Clone, PartialEq, Debug)] struct Z; // Zero sized type - let mut array: ArrayVec<_, 5> = range.by_ref().take(5).map(|_| Z).collect(); + let mut array: ArrayVec<_, 5> = range.by_ref().take(5).map(|_| Z).collect(); assert_eq!(&array[..], &[Z; 5]); assert_eq!(range.next(), Some(5)); array.extend(range.by_ref().take(0).map(|_| Z)); assert_eq!(range.next(), Some(6)); - let mut array: ArrayVec<_, 10> = (0..3).map(|_| Z).collect(); + let mut array: ArrayVec<_, 10> = (0..3).map(|_| Z).collect(); assert_eq!(&array[..], &[Z; 3]); array.extend((3..5).map(|_| Z)); assert_eq!(&array[..], &[Z; 5]); @@ -739,27 +735,27 @@ fn test_try_from_argument() { #[test] fn allow_max_capacity_arrayvec_type() { // this type is allowed to be used (but can't be constructed) - let _v: ArrayVec<(), {usize::MAX}>; + let _v: ArrayVec<(), { usize::MAX }>; } -#[should_panic(expected="largest supported capacity")] +#[should_panic(expected = "largest supported capacity")] #[test] fn deny_max_capacity_arrayvec_value() { if mem::size_of::() <= mem::size_of::() { panic!("This test does not work on this platform. 'largest supported capacity'"); } // this type is allowed to be used (but can't be constructed) - let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new(); + let _v: ArrayVec<(), { usize::MAX }> = ArrayVec::new(); } -#[should_panic(expected="index out of bounds")] +#[should_panic(expected = "index out of bounds")] #[test] fn deny_max_capacity_arrayvec_value_const() { if mem::size_of::() <= mem::size_of::() { panic!("This test does not work on this platform. 'index out of bounds'"); } // this type is allowed to be used (but can't be constructed) - let _v: ArrayVec<(), {usize::MAX}> = ArrayVec::new_const(); + let _v: ArrayVec<(), { usize::MAX }> = ArrayVec::new_const(); } #[test] @@ -784,10 +780,9 @@ fn test_arraystring_const_constructible() { assert_eq!(var, *"hello"); } - #[test] fn test_arraystring_zero_filled_has_some_sanity_checks() { let string = ArrayString::<4>::zero_filled(); assert_eq!(string.as_str(), "\0\0\0\0"); assert_eq!(string.len(), 4); -} \ No newline at end of file +} From 7176f53203a1002cb06155b3fb4af9ec4a6c76ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Mar 2022 15:49:57 -0500 Subject: [PATCH 2/6] update Miri CI config --- .github/workflows/ci.yml | 10 +++++++--- ci/miri.sh | 15 --------------- 2 files changed, 7 insertions(+), 18 deletions(-) delete mode 100755 ci/miri.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65b6c53..ccbf423 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Miri - run: ci/miri.sh - + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + rustup override set nightly + cargo miri setup + - name: Test with Miri + run: cargo miri test diff --git a/ci/miri.sh b/ci/miri.sh deleted file mode 100755 index 272995c..0000000 --- a/ci/miri.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -set -ex - -export CARGO_NET_RETRY=5 -export CARGO_NET_TIMEOUT=10 - -MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) -echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" -rustup default "$MIRI_NIGHTLY" - -rustup component add miri -cargo miri setup - -cargo miri test From 61796b515ae9e90a983dc4e4c07ab1ec7977fb14 Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sat, 23 Jul 2022 05:40:30 +0300 Subject: [PATCH 3/6] Fixed miri errors for `fn drain(...)`. This required to rewrite `struct Drain` because old implementation had aliasing pointers in it which violated [Stacked Borrows][1]. New implementation separately borrows len field and parts of the slice to prevent aliasing. Also, we don't use slice iteration anymore because stacked borrows conflict with `ptr::copy` which we use to move the tail. We can wrote it valid for stacked borrows by using 2 memmoves (1 from tail beginning to removed slice and 1 from rest of the tail to beginning of the tail) but it is more complex to read and understand, more error prone and less effecient. This commit causes divergence with Rust `alloc::vec::Vec` implementation but we cannot implement it same way because it is only possible if `Vec` struct stored in different allocation than its buffer which isn't possible for `ArrayVec`. Also, added test that check drain behaviour when dropping. [1]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/ --- src/arrayvec.rs | 141 ++++++++++++++++++++++++++++++++++++++---------- tests/tests.rs | 26 +++++++++ 2 files changed, 138 insertions(+), 29 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 0b29620..14479a7 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -1,3 +1,5 @@ +use core::convert::TryInto; +use core::ptr::NonNull; use std::cmp; use std::iter; use std::mem; @@ -639,10 +641,14 @@ impl ArrayVec { let start = match range.start_bound() { Bound::Unbounded => 0, Bound::Included(&i) => i, + // You cannot have array bigger than usize anyway + // so saturating add wouldn't break anything here. Bound::Excluded(&i) => i.saturating_add(1), }; let end = match range.end_bound() { Bound::Excluded(&j) => j, + // You cannot have array bigger than usize anyway + // so saturating add wouldn't break anything here. Bound::Included(&j) => j.saturating_add(1), Bound::Unbounded => len, }; @@ -650,21 +656,35 @@ impl ArrayVec { } 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]; + let _ = &self[start..end]; + // Eagerly reduce len to prevent double frees in case of `drop::` panics. // Calling `set_len` creates a fresh and thus unique mutable references, making all // older aliases we created invalid. So we cannot call that function. + let old_len: usize = self.len.try_into().unwrap(); self.len = start as LenUint; + let start_ptr: *mut T = self.xs.as_mut_ptr().cast(); + + let tail_len = (old_len - end) as LenUint; + self.len = start.try_into().unwrap(); unsafe { + // SAFETY: length is valid because we made bounds check earlier. + let to_yield = end.saturating_sub(start); + let taken_start = start_ptr.add(start); + let tail_start = taken_start.add(to_yield); + + let taken_start = NonNull::new(taken_start).unwrap(); + let tail_start = NonNull::new(tail_start).unwrap(); + Drain { - tail_start: end, - tail_len: len - end, - iter: (*range_slice).iter(), - vec: self as *mut _, + vec_len: &mut self.len, + taken_start: taken_start, + to_yield: to_yield as LenUint, + current_ptr: taken_start, + tail_start: tail_start, + tail_len, } } } @@ -946,15 +966,31 @@ where } } +// Note: We cannot implement this same way as `std::vec::Drain` +// because keeping pointer to vec would violate Stacked Borrows +// because this pointer alias with pointers to our inner slice +// which get invalidated. +// `std::vec::Vec` doesn't have same problem because its buffer +// and object itself doesn't overlap. + /// A draining iterator for `ArrayVec`. pub struct Drain<'a, T: 'a, const CAP: usize> { - /// Index of tail to preserve - tail_start: usize, + /// Reference to `len` field of vec + vec_len: &'a mut LenUint, + + /// Pointer to position which we started to drain. + taken_start: ptr::NonNull, + /// How much items we need yield. + /// Use integer instead of pointer to track this + /// because it simplifies working with ZSTs. + to_yield: LenUint, + /// Points to next item to yield. + current_ptr: ptr::NonNull, + + /// Points to item right after drained range. + tail_start: ptr::NonNull, /// Length of tail - tail_len: usize, - /// Current remaining range to remove - iter: slice::Iter<'a, T>, - vec: *mut ArrayVec, + tail_len: LenUint, } unsafe impl<'a, T: Sync, const CAP: usize> Sync for Drain<'a, T, CAP> {} @@ -964,21 +1000,57 @@ impl<'a, T: '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 _) }) + if self.to_yield == 0 { + None + } else { + let current = self.current_ptr.as_ptr(); + self.to_yield -= 1; + self.current_ptr = NonNull::new( + // SAFETY: we just checked that we are in range. + // We just shortened range. + unsafe { current.add(1) }, + ) + // Note: rustc optimizes check here even with `-Copt-level=1` + // https://godbolt.org/z/br6eevnbx + .unwrap(); + + Some( + // SAFETY: we just checked that we are in range. + // Range must be valid by construction. + // We visit every item in drained range exactly once + // so they are read exactly once. + // Alignment is valid because it points to item in slice. + unsafe { current.read() }, + ) + } } fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + let remaining: usize = self.to_yield.try_into().unwrap(); + (remaining, Some(remaining)) } } impl<'a, T: '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 _) }) + if self.to_yield == 0 { + None + } else { + let to_yield: usize = self.to_yield.try_into().unwrap(); + self.to_yield -= 1; + + // SAFETY: We just checked our range. + // We just shortened range. + let src = unsafe { self.current_ptr.as_ptr().add(to_yield - 1) }; + Some( + // SAFETY: we just checked that we are in range. + // Range must be valid by construction. + // We visit every item in drained range exactly once + // so they are read exactly once. + // Alignment is valid because it points to item in slice. + unsafe { src.read() }, + ) + } } } @@ -988,19 +1060,30 @@ impl<'a, T: '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() {} + // Drop inner values first. + // Use slice `drop_in_place` because it is faster than iteration over self. + unsafe { + let remaining_start = self.current_ptr.as_ptr(); + let remaining_len: usize = self.to_yield.try_into().unwrap(); + self.to_yield = 0; + // SAFETY: It is safe because we dropping only unyielded items + // which must be initialized by `Drain` invariant. + ptr::drop_in_place(core::slice::from_raw_parts_mut( + remaining_start, + remaining_len, + )); + } if self.tail_len > 0 { unsafe { - let source_vec = &mut *self.vec; + let dst = self.taken_start.as_ptr(); + let src = self.tail_start.as_ptr() as *const _; + let tail_len: usize = self.tail_len.try_into().unwrap(); // memmove back untouched tail, update to new length - let start = source_vec.len(); - let tail = self.tail_start; - let src = source_vec.as_ptr().add(tail); - let dst = source_vec.as_mut_ptr().add(start); - ptr::copy(src, dst, self.tail_len); - source_vec.set_len(start + self.tail_len); + ptr::copy(src, dst, tail_len); + // Set len of vec. + // Safe because our tail contains exactly `tail_len` living items. + *self.vec_len += self.tail_len; } } } diff --git a/tests/tests.rs b/tests/tests.rs index 9b51cd9..eb0def1 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -8,6 +8,7 @@ use arrayvec::CapacityError; use std::mem; use std::collections::HashMap; +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; #[test] fn test_simple() { @@ -368,6 +369,31 @@ fn test_drain_range_inclusive_oob() { v.drain(0..=0); } +#[test] +fn test_drain_panic_in_the_middle() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + DROP_COUNTER.store(0, AtomicOrdering::Relaxed); + + struct CountOnDrop; + + impl Drop for CountOnDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, AtomicOrdering::Relaxed); + } + } + + let mut v = ArrayVec::from([(); 6].map(|_| CountOnDrop)); + + std::panic::catch_unwind(move || { + let mut d = v.drain(1..4); + d.next(); + panic!("We want to!"); + }) + .expect_err("We explicitly panic"); + // No double drops and no leaks. + assert_eq!(DROP_COUNTER.load(AtomicOrdering::Relaxed), 6); +} + #[test] fn test_retain() { let mut v = ArrayVec::from([0; 8]); From c9bc4d974adc502a86f86d6e282c5c91e9e87d32 Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sat, 23 Jul 2022 14:16:39 +0300 Subject: [PATCH 4/6] Synchronized `retain` method It have 2 differences from std method: 1. We call `as_mut_ptr` exactly once per iteration because we break `Stacked Borrows` otherwise. Reason of that is different data layout of `Vec` and `ArrayVec`. While `Vec::as_mut_ptr` only copy internal pointer, `ArrayVec::as_mut_ptr` needs to borrow whole array which cause aliasing between first call result and second call which in turn cause miri error. 2. We check if we processed all items so we don't do final `memmove` call as [`std::vec::Vec` does][1]. I think, in most cases it can be optimized away but still it is not guaranteed. Also, added tests to check behaviour on panics. [1]: https://godbolt.org/z/h664E5MKE --- src/arrayvec.rs | 68 ++++++++++++++++++++++++++-------------------- tests/tests.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 29 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 14479a7..bdee960 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -494,13 +494,12 @@ impl ArrayVec { impl Drop for BackshiftOnDrop<'_, T, CAP> { fn drop(&mut self) { - if self.deleted_cnt > 0 { + if self.deleted_cnt > 0 && self.original_len != self.processed_len { unsafe { + let p = self.v.as_mut_ptr(); ptr::copy( - self.v.as_ptr().add(self.processed_len), - self.v - .as_mut_ptr() - .add(self.processed_len - self.deleted_cnt), + p.add(self.processed_len), + p.add(self.processed_len - self.deleted_cnt), self.original_len - self.processed_len, ); } @@ -518,39 +517,50 @@ impl ArrayVec { original_len, }; - #[inline(always)] - fn process_one bool, T, const CAP: usize, const DELETED: bool>( + fn process_loop( + original_len: usize, 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; - unsafe { ptr::drop_in_place(cur) }; - return false; - } - if DELETED { - unsafe { - let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); - ptr::copy_nonoverlapping(cur, hole_slot, 1); + ) where + F: FnMut(&mut T) -> bool, + { + while g.processed_len != original_len { + // We differ from `std::vec::Vec` here because + // we need to borrow whole slice in `as_mut_ptr` call + // which violates Stacked Borrows if we already used `cur`. + let slice_ptr = g.v.as_mut_ptr(); + // SAFETY: Unchecked element must be valid. + let cur = unsafe { &mut *slice_ptr.add(g.processed_len) }; + if !f(cur) { + // Advance early to avoid double drop if `drop_in_place` panicked. + g.processed_len += 1; + g.deleted_cnt += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + // We already advanced the counter. + if DELETED { + continue; + } else { + break; + } + } + if DELETED { + // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. + // We use copy for move, and never touch this element again. + unsafe { + let hole_slot = slice_ptr.add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } } + g.processed_len += 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; - } - } + process_loop::(original_len, &mut f, &mut g); // Stage 2: Some elements were deleted. - while g.processed_len != original_len { - process_one::(&mut f, &mut g); - } + process_loop::(original_len, &mut f, &mut g); drop(g); } diff --git a/tests/tests.rs b/tests/tests.rs index eb0def1..2aeba14 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -411,6 +411,78 @@ fn test_retain() { assert_eq!(&v[..], &[]); } +#[test] +fn test_retain_on_panics() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + DROP_COUNTER.store(0, AtomicOrdering::Relaxed); + + struct CountOnDrop; + + impl Drop for CountOnDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, AtomicOrdering::Relaxed); + } + } + + let max_i = AtomicUsize::new(0); + let mut v = ArrayVec::from([(); 20].map(|_| CountOnDrop)); + // Check what happens if predicate panics. + std::panic::catch_unwind({ + let max_i = &max_i; + move || { + let mut i = 0; + v.retain(|_| { + i += 1; + max_i.store(i, AtomicOrdering::Relaxed); + if i == 10 { + panic!("We want to!"); + } + i & 1 == 0 + }); + } + }) + .expect_err("We explicitly panic"); + + assert_eq!(max_i.load(AtomicOrdering::Relaxed), 10); + // No leaks and no double frees. + assert_eq!(DROP_COUNTER.load(AtomicOrdering::Relaxed), 20); + + DROP_COUNTER.store(0, AtomicOrdering::Relaxed); + + struct PanicOnDrop(usize); + + impl Drop for PanicOnDrop { + fn drop(&mut self) { + if self.0 == 10 { + panic!("We want to!"); + } + } + } + + let max_i = AtomicUsize::new(0); + let mut i = 0; + let mut v = ArrayVec::from([(); 20].map(|_| { + let j = i; + i += 1; + (CountOnDrop, PanicOnDrop(j)) + })); + // Check what happens if drop panics. + std::panic::catch_unwind({ + let max_i = &max_i; + move || { + v.retain(|v| { + max_i.store(v.1 .0, AtomicOrdering::Relaxed); + v.1 .0 & 1 != 0 + }); + } + }) + .expect_err("We explicitly panic"); + + assert_eq!(max_i.load(AtomicOrdering::Relaxed), 10); + // No double frees and no leaks. + assert_eq!(DROP_COUNTER.load(AtomicOrdering::Relaxed), 20); +} + #[test] #[should_panic] fn test_drain_oob() { From a2b1fa9d624ac70ea047a5ce53d8e5815faaf052 Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sat, 23 Jul 2022 14:59:52 +0300 Subject: [PATCH 5/6] Fix miri errors from ZST handling in extend. It was invalid for ZSTs because it ignored alignment requirements. From [docs][1]: "Note that even if T has size 0, the pointer must be non-null and *properly aligned*." I just switched to using integer to bounds checks. [1]: https://doc.rust-lang.org/std/ptr/fn.write.html#safety --- src/arrayvec.rs | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index bdee960..1fdab0b 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -1148,8 +1148,8 @@ impl ArrayVec { { 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); + let mut ptr = self.as_mut_ptr().add(len); + // 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 @@ -1161,20 +1161,22 @@ impl ArrayVec { **self_len = len as LenUint; }, }; - let mut iter = iterable.into_iter(); - loop { - if let Some(elt) = iter.next() { - if ptr == end_ptr && CHECK { - extend_panic(); - } - debug_assert_ne!(ptr, end_ptr); - ptr.write(elt); - ptr = raw_ptr_add(ptr, 1); - guard.data += 1; - } else { - return; // success + let iter = iterable.into_iter(); + let mut current_offset = 0; + // Use `for_each` because it is more optimal for some iterators + // than calling `Iterator::next` in a loop. + // For example, `Chain`s extra branch is `next()` isn't optimized away. + iter.for_each(|elt| { + if CHECK && current_offset == take { + extend_panic(); } - } + debug_assert_ne!(current_offset, take); + current_offset += 1; + + ptr.write(elt); + ptr = ptr.add(1); + guard.data += 1; + }); } /// Extend the ArrayVec with clones of elements from the slice; @@ -1196,16 +1198,6 @@ impl ArrayVec { } } -/// 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 as usize).wrapping_add(offset) as _ - } else { - ptr.add(offset) - } -} - /// Create an `ArrayVec` from an iterator. /// /// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity. From bee0ffc5425690cbdc1ab31453b01e6a520b1484 Mon Sep 17 00:00:00 2001 From: AngelicosPhosphoros Date: Sat, 23 Jul 2022 15:14:25 +0300 Subject: [PATCH 6/6] Fixed stacked borrow violation in `ArrayString::remove`. Just avoid calling `as_mut_ptr` twice. --- src/array_string.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/array_string.rs b/src/array_string.rs index 230fcdd..393a037 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -380,15 +380,16 @@ impl ArrayString { None => panic!("cannot remove a char from the end of a string"), }; - let next = idx + ch.len_utf8(); let len = self.len(); + let removed_len = ch.len_utf8(); + let next = idx + removed_len; + let tail_len = len - next; unsafe { - ptr::copy( - self.as_ptr().add(next), - self.as_mut_ptr().add(idx), - len - next, - ); - self.set_len(len - (next - idx)); + // SAFETY: `idx` is in bounds because we just checked that. + // `next` is in bounds because we cannot contain character partially. + let p = self.as_mut_ptr(); + ptr::copy(p.add(next), p.add(idx), tail_len); + self.set_len(len - removed_len); } ch }