diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65b6c535..ccbf4234 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/benches/arraystring.rs b/benches/arraystring.rs index 5b986fa2..fabb8cd8 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 ba33a932..7aad2c70 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/ci/miri.sh b/ci/miri.sh deleted file mode 100755 index 272995ca..00000000 --- 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 diff --git a/src/array_string.rs b/src/array_string.rs index c4712a0c..393a037b 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'); @@ -369,13 +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 } @@ -419,8 +433,7 @@ impl ArrayString } } -impl Deref for ArrayString -{ +impl Deref for ArrayString { type Target = str; #[inline] fn deref(&self) -> &str { @@ -431,8 +444,7 @@ impl Deref for ArrayString } } -impl DerefMut for ArrayString -{ +impl DerefMut for ArrayString { #[inline] fn deref_mut(&mut self) -> &mut str { unsafe { @@ -443,60 +455,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 +516,7 @@ impl fmt::Write for ArrayString } } -impl Clone for ArrayString -{ +impl Clone for ArrayString { fn clone(&self) -> ArrayString { *self } @@ -518,48 +527,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 +595,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 +626,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 +647,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 +657,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 e69e60c1..1fdab0b4 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -1,4 +1,5 @@ - +use core::convert::TryInto; +use core::ptr::NonNull; use std::cmp; use std::iter; use std::mem; @@ -8,22 +9,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 +56,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 +87,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 +105,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 +121,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 +135,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 +148,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 +162,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 +272,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 +331,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 +387,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 +433,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 +474,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 @@ -476,12 +494,13 @@ 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), - self.original_len - self.processed_len + p.add(self.processed_len), + p.add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len, ); } } @@ -491,41 +510,57 @@ 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>( + 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); + g: &mut BackshiftOnDrop<'_, T, CAP>, + ) 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); } @@ -562,7 +597,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 +634,8 @@ impl ArrayVec { /// assert_eq!(&v2[..], &[1, 2]); /// ``` pub fn drain(&mut self, range: R) -> Drain - where R: RangeBounds + where + R: RangeBounds, { // Memory safety // @@ -614,33 +651,50 @@ 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, }; self.drain_range(start, end) } - fn drain_range(&mut self, start: usize, end: usize) -> Drain - { - let len = self.len(); - + fn drain_range(&mut self, start: usize, end: usize) -> Drain { // 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, } } } @@ -677,7 +731,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 +760,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 +793,6 @@ impl DerefMut for ArrayVec { } } - /// Create an `ArrayVec` from an array. /// /// ``` @@ -760,7 +815,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 +827,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 +843,6 @@ impl std::convert::TryFrom<&[T]> for ArrayVec } } - /// Iterate the `ArrayVec` with references to each element. /// /// ``` @@ -803,7 +857,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 +876,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 +896,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 +941,7 @@ impl DoubleEndedIterator for IntoIter { } } -impl ExactSizeIterator for IntoIter { } +impl ExactSizeIterator for IntoIter {} impl Drop for IntoIter { fn drop(&mut self) { @@ -893,16 +950,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,21 +972,35 @@ 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() } } +// 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> {} @@ -940,26 +1010,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> -{ +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() }, + ) + } } } @@ -969,26 +1070,38 @@ 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; } } } } struct ScopeExitGuard - where F: FnMut(&Data, &mut T) +where + F: FnMut(&Data, &mut T), { value: T, data: Data, @@ -996,26 +1109,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,12 +1143,13 @@ 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(); - 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 @@ -1048,54 +1159,53 @@ 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(); } - 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; /// 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()); } } } -/// 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. 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 +1213,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 +1236,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 +1245,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 +1254,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 +1304,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 +1329,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 +1349,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 +1387,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 6c09834a..ae4772fa 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 939b6b47..77df3110 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 7ca3ebc4..19e479e2 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 5dc0273a..68fcb11e 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 b8e5ddb3..b425a51d 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 f02c693a..58630f56 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 2f8a5ef5..2aeba141 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,19 +1,20 @@ 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; - +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; #[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 +30,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 +44,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 +55,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 +71,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 +114,7 @@ fn test_drop() { } { - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(Bump(flag)); array.push(Bump(flag)); } @@ -123,7 +124,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 +143,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 +157,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 +172,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 +226,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 +239,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 +258,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 +282,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 +290,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 +298,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 +306,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 +339,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 +355,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(..); @@ -371,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]); @@ -388,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() { @@ -407,7 +502,7 @@ fn test_drop_panic() { } } - let mut array = ArrayVec::::new(); + let mut array = ArrayVec::::new(); array.push(DropPanic); } @@ -422,7 +517,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 +527,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 +556,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 +566,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 +594,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 +615,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 +652,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 +699,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 +711,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 +744,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 +759,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 +784,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 +809,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 +833,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 +878,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 +}