diff --git a/CHANGELOG.md b/CHANGELOG.md index 903ef58..a24aeb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Recent Changes (arrayvec) ========================= +## 0.7.3 + +- Add `.maybe_uninit_tail_mut()` and unsafe `.into_inner_zeroed_tail()` to `ArrayVec` by @JohnScience +- Small code cleanup by @JohnScience + ## 0.7.2 - Add `.as_mut_str()` to `ArrayString` by @clarfonthey diff --git a/Cargo.toml b/Cargo.toml index ea04113..f92b4f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayvec" -version = "0.7.2" +version = "0.7.3" authors = ["bluss"] license = "MIT OR Apache-2.0" edition = "2018" 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..9d97874 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 @@ -389,11 +402,13 @@ impl ArrayString /// Set the strings’s length. /// - /// This function is `unsafe` because it changes the notion of the - /// number of “valid” bytes in the string. Use with care. - /// /// This method uses *debug assertions* to check the validity of `length` /// and may use other debug assertions. + /// + /// # Safety + /// + /// This function is `unsafe` because it changes the notion of the + /// number of “valid” bytes in the string. Use with care. pub unsafe fn set_len(&mut self, length: usize) { // type invariant that capacity always fits in LenUint debug_assert!(length <= self.capacity()); @@ -419,8 +434,7 @@ impl ArrayString } } -impl Deref for ArrayString -{ +impl Deref for ArrayString { type Target = str; #[inline] fn deref(&self) -> &str { @@ -431,8 +445,7 @@ impl Deref for ArrayString } } -impl DerefMut for ArrayString -{ +impl DerefMut for ArrayString { #[inline] fn deref_mut(&mut self) -> &mut str { unsafe { @@ -443,60 +456,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 +517,7 @@ impl fmt::Write for ArrayString } } -impl Clone for ArrayString -{ +impl Clone for ArrayString { fn clone(&self) -> ArrayString { *self } @@ -518,48 +528,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 +596,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 +627,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 +648,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,14 +658,13 @@ 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 { use fmt::Write; let mut v = Self::new(); - v.write_fmt(f).map_err(|e| CapacityError::new(e))?; + v.write_fmt(f).map_err(CapacityError::new)?; Ok(v) } } diff --git a/src/arrayvec.rs b/src/arrayvec.rs index e69e60c..9936c7f 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`. /// @@ -204,11 +223,13 @@ impl ArrayVec { /// Push `element` to the end of the vector without checking the capacity. /// + /// This method uses *debug assertions* to check that the arrayvec is not full. + /// + /// # Safety + /// /// It is up to the caller to ensure the capacity of the vector is /// sufficiently large. /// - /// This method uses *debug assertions* to check that the arrayvec is not full. - /// /// ``` /// use arrayvec::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 @@ -480,8 +498,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 +511,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 }) { @@ -532,11 +557,14 @@ impl ArrayVec { /// Set the vector’s length without dropping or moving out elements /// - /// This method is `unsafe` because it changes the notion of the - /// number of “valid” elements in the vector. Use with care. - /// /// This method uses *debug assertions* to check that `length` is /// not greater than the capacity. + /// + /// # Safety + /// + /// This method is `unsafe` because it changes the notion of the + /// number of “valid” elements in the vector. Use with care. + pub unsafe fn set_len(&mut self, length: usize) { // type invariant that capacity always fits in LenUint debug_assert!(length <= self.capacity()); @@ -562,7 +590,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 +627,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 +654,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!) @@ -657,15 +686,93 @@ impl ArrayVec { } } + /// Return the possibly uninitialized tail of the vector. + /// + /// If the length of the of the [ArrayVec] equals to the capacity, + /// return zero-length slice. + pub fn maybe_uninit_tail_mut(&mut self) -> &mut [MaybeUninit] { + let len = self.len(); + let inner_slice = self.xs.as_mut_slice(); + + debug_assert!(len <= CAP); + + // in order to avoid possible bounds checking, we do the arithmetics + let maybe_uninit_start_idx = match len { + // idx is the index after the index of the last element that is + // guaranteed to be initialized, i.e. idx equals to the length + // as long as it is less than the capacity + idx if core::cmp::min(len, CAP) < CAP => idx, + // this is safe because len < CAP + _ if core::cmp::min(len, CAP) > CAP => { + #[cfg(debug_assertions)] + unreachable!(); + #[cfg(not(debug_assertions))] + unsafe { + core::hint::unreachable_unchecked() + } + } + // since length equals to the capacity + _ => return &mut [], + }; + + // the range is not inclusive because `CAP`th zero-based index goes out of bounds + // for a CAP-sized buffer + let maybe_uninit_idx_range = maybe_uninit_start_idx..CAP; + + // this is safe because the range is by construction within bounds: + // its right index is strictly less than the capacity and its left index is + // constrained by the right index. + unsafe { inner_slice.get_unchecked_mut(maybe_uninit_idx_range) } + } + + /// Return the inner fixed size array, zeroing out the possibly uninitialized tail. + /// + /// Internally, even padding bytes of the tail get zeroed, unlike when using [core::mem::zeroed]. + /// + /// # Safety + /// + /// Zeroed byte pattern should represent a valid value of type `T`. Similarly to [core::mem::zeroed], + /// the function call may result in undefine behavior if `T` is + /// * a reference type, + /// * a function pointer, + /// * one of non-zero types from [core::num] or [std::num], + /// * or any other type whose byte-pattern can't be all zeroes. + pub unsafe fn into_inner_zeroed_tail(mut self) -> [T; CAP] { + let maybe_uninit_tail = match self.maybe_uninit_tail_mut() { + // this is safe because self.maybe_uninit_tail_mut() returns None only when length equals capacity + empty_tail if empty_tail.is_empty() => return unsafe { self.into_inner_unchecked() }, + nonempty_tail => nonempty_tail, + }; + + let (dst, count) = (maybe_uninit_tail.as_mut_ptr(), maybe_uninit_tail.len()); + + // `dst` is properly aligned by construction + // `dst` is valid for writes of `count` * size_of::() bytes because + // that's exactly the byte length of the mutable slice into the contiguous buffer + // of the `ArrayVec` + unsafe { core::ptr::write_bytes(dst, 0u8, count) }; + + // now even the tail is initialized, so we can set length to the capacity + // it is needed in order to bypass debug assertions + #[cfg(debug_assertions)] + unsafe { + self.set_len(self.capacity()) + }; + + // This is safe because the tail that could be not initialized + // has been zeroed and it is assumed to be a valid initialization + unsafe { self.into_inner_unchecked() } + } + /// Return the inner fixed size array. /// - /// Safety: + /// # Safety + /// /// This operation is safe if and only if length equals capacity. pub unsafe fn into_inner_unchecked(self) -> [T; CAP] { debug_assert_eq!(self.len(), self.capacity()); let self_ = ManuallyDrop::new(self); - let array = ptr::read(self_.as_ptr() as *const [T; CAP]); - array + ptr::read::<[T; CAP]>(self_.as_ptr() as *const [T; CAP]) } /// Returns the ArrayVec, replacing the original with a new empty ArrayVec. @@ -677,7 +784,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 +813,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 +846,6 @@ impl DerefMut for ArrayVec { } } - /// Create an `ArrayVec` from an array. /// /// ``` @@ -760,7 +868,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 +880,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 +896,6 @@ impl std::convert::TryFrom<&[T]> for ArrayVec } } - /// Iterate the `ArrayVec` with references to each element. /// /// ``` @@ -803,7 +910,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 +929,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 +949,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 +994,7 @@ impl DoubleEndedIterator for IntoIter { } } -impl ExactSizeIterator for IntoIter { } +impl ExactSizeIterator for IntoIter {} impl Drop for IntoIter { fn drop(&mut self) { @@ -893,16 +1003,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 +1025,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 +1047,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 +1057,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 +1072,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() { } + for _ in self.by_ref() {} if self.tail_len > 0 { unsafe { @@ -988,7 +1090,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 +1099,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 +1133,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 +1149,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 +1170,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 +1197,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 +1211,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 +1234,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 +1243,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 +1252,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 +1302,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 +1327,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 +1347,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 +1385,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..d661e13 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 } } /// Extract the overflowing element @@ -29,9 +27,9 @@ impl CapacityError { } } -const CAPERROR: &'static str = "insufficient capacity"; +const CAPERROR: &str = "insufficient capacity"; -#[cfg(feature="std")] +#[cfg(feature = "std")] /// Requires `features="std"`. impl Error for CapacityError {} @@ -43,7 +41,6 @@ impl fmt::Display for CapacityError { impl fmt::Debug for CapacityError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}: {}", "CapacityError", CAPERROR) + 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..d69cf5b 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,53 @@ 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 +} + +#[test] +fn test_maybe_uninit_tail_mut() { + let mut vec: ArrayVec, 5> = ArrayVec::new(); + + vec.push(vec![1, 2, 3, 4]); + vec.push(vec![10]); + vec.push(vec![-1, 13, -2]); + + let uninit_tail = vec.maybe_uninit_tail_mut(); + assert_eq!(uninit_tail.len(), 2); + + uninit_tail[0] = std::mem::MaybeUninit::new(vec![1, 2, 3, 4]); + drop(uninit_tail); + + assert!(vec.len() + 1 <= vec.capacity()); + unsafe { vec.set_len(vec.len() + 1) }; + + assert!(vec.last().unwrap() == &vec![1, 2, 3, 4]); + assert_eq!(vec.maybe_uninit_tail_mut().len(), 1); + + vec.push(vec![-1, 13, -2]); + assert_eq!(vec.maybe_uninit_tail_mut().len(), 0); +} + +#[test] +fn test_into_inner_zeroed_tail() { + use std::mem::MaybeUninit; + + let mut vec: ArrayVec = ArrayVec::new(); + vec.maybe_uninit_tail_mut()[0] = MaybeUninit::new(1); + vec.maybe_uninit_tail_mut()[1] = MaybeUninit::new(2); + vec.maybe_uninit_tail_mut()[2] = MaybeUninit::new(2); + vec.maybe_uninit_tail_mut()[3] = MaybeUninit::new(3); + + assert_eq!( + unsafe { vec.get_unchecked(0..vec.capacity()) }, + &[1, 2, 2, 3] + ); + + // This is safe for integers + let arr = unsafe { vec.into_inner_zeroed_tail() }; + assert_eq!(arr, [0, 0, 0, 0]); +}