diff --git a/CHANGELOG.md b/CHANGELOG.md index 848a81a507..63d43becb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `format` macro. - Added `String::from_utf16`. - Added `is_full`, `recent_index`, `oldest`, and `oldest_index` to `HistoryBuffer` +- Added an optional generic parameter to `Vec` to specify the alignment of the backing array. - Added infallible conversions from arrays to `Vec`. ### Changed diff --git a/cfail/ui/not-send.stderr b/cfail/ui/not-send.stderr index 40645b7a6d..c1820775c5 100644 --- a/cfail/ui/not-send.stderr +++ b/cfail/ui/not-send.stderr @@ -80,10 +80,15 @@ note: required because it appears within the type `ManuallyDrop>` --> $RUST/core/src/mem/maybe_uninit.rs = note: required because it appears within the type `[MaybeUninit>; 4]` +note: required because it appears within the type `VecBuf, 4, u8>` + --> $HEAPLESS/src/vec.rs + | + | struct VecBuf { + | ^^^^^^ note: required because it appears within the type `Vec, 4>` --> $HEAPLESS/src/vec.rs | - | pub struct Vec { + | pub struct Vec { | ^^^ note: required by a bound in `is_send` --> ui/not-send.rs:14:8 diff --git a/src/vec.rs b/src/vec.rs index 2df7d86c1c..34bdab5727 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -7,6 +7,12 @@ use core::{ ops, ptr, slice, }; +#[repr(C)] +struct VecBuf { + alignment_field: [A; 0], + buffer: [MaybeUninit; N], +} + /// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). /// /// # Examples @@ -35,20 +41,52 @@ use core::{ /// } /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` -pub struct Vec { +pub struct Vec { // NOTE order is important for optimizations. the `len` first layout lets the compiler optimize // `new` to: reserve stack space and zero the first word. With the fields in the reverse order // the compiler optimizes `new` to `memclr`-ing the *entire* stack space, including the `buffer` // field which should be left uninitialized. Optimizations were last checked with Rust 1.60 len: usize, - buffer: [MaybeUninit; N], + // self.buffer.buffer access is greatly discouraged. Use the respective methods instead. + buffer: VecBuf, } -impl Vec { +impl VecBuf { const ELEM: MaybeUninit = MaybeUninit::uninit(); const INIT: [MaybeUninit; N] = [Self::ELEM; N]; // important for optimization of `new` + const fn new() -> Self { + Self { + alignment_field: [], + buffer: Self::INIT, + } + } + + const fn as_ptr(&self) -> *const T { + self.buffer.as_ptr() as *const T + } + + fn as_mut_ptr(&mut self) -> *mut T { + self.buffer.as_mut_ptr() as *mut T + } +} + +impl ops::Deref for VecBuf { + type Target = [MaybeUninit; N]; + + fn deref(&self) -> &[MaybeUninit; N] { + &self.buffer + } +} + +impl ops::DerefMut for VecBuf { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer + } +} + +impl Vec { /// Constructs a new, empty vector with a fixed capacity of `N` /// /// # Examples @@ -66,7 +104,7 @@ impl Vec { pub const fn new() -> Self { Self { len: 0, - buffer: Self::INIT, + buffer: VecBuf::new(), } } @@ -118,8 +156,10 @@ impl Vec { buffer: unsafe { mem::transmute_copy(&src) }, } } else { - let mut v = Vec::::new(); + let mut v = Vec::::new(); + // `for` is not allowed in a `const fn` + // see issue #87575 for more information. for (src_elem, dst_elem) in src.iter().zip(v.buffer.iter_mut()) { // NOTE(unsafe) src element is not going to drop as src itself // is wrapped in a ManuallyDrop. @@ -148,12 +188,12 @@ impl Vec { /// Returns a raw pointer to the vector’s buffer. pub fn as_ptr(&self) -> *const T { - self.buffer.as_ptr() as *const T + self.buffer.as_ptr() } /// Returns a raw pointer to the vector’s buffer, which may be mutated through. pub fn as_mut_ptr(&mut self) -> *mut T { - self.buffer.as_mut_ptr() as *mut T + self.buffer.as_mut_ptr() } /// Extracts a slice containing the entire vector. @@ -170,7 +210,7 @@ impl Vec { pub fn as_slice(&self) -> &[T] { // NOTE(unsafe) avoid bound checks in the slicing operation // &buffer[..self.len] - unsafe { slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.len) } + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } } /// Returns the contents of the vector as an array of length `M` if the length @@ -187,7 +227,7 @@ impl Vec { pub fn into_array(self) -> Result<[T; M], Self> { if self.len() == M { // This is how the unstable `MaybeUninit::array_assume_init` method does it - let array = unsafe { (&self.buffer as *const _ as *const [T; M]).read() }; + let array = unsafe { (self.as_ptr() as *const [T; M]).read() }; // We don't want `self`'s destructor to be called because that would drop all the // items in the array @@ -214,7 +254,7 @@ impl Vec { pub fn as_mut_slice(&mut self) -> &mut [T] { // NOTE(unsafe) avoid bound checks in the slicing operation // &mut buffer[..self.len] - unsafe { slice::from_raw_parts_mut(self.buffer.as_mut_ptr() as *mut T, self.len) } + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } /// Returns the maximum number of elements the vector can hold. @@ -787,14 +827,14 @@ impl Vec { // This drop guard will be invoked when predicate or `drop` of element panicked. // It shifts unchecked elements to cover holes and `set_len` to the correct length. // In cases when predicate and `drop` never panick, it will be optimized out. - struct BackshiftOnDrop<'a, T, const N: usize> { - v: &'a mut Vec, + struct BackshiftOnDrop<'a, T, const N: usize, A> { + v: &'a mut Vec, processed_len: usize, deleted_cnt: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, T, N> { + impl Drop for BackshiftOnDrop<'_, T, N, A> { fn drop(&mut self) { if self.deleted_cnt > 0 { // SAFETY: Trailing unchecked items must be valid since we never touch them. @@ -822,10 +862,10 @@ impl Vec { original_len, }; - fn process_loop( + fn process_loop( original_len: usize, f: &mut F, - g: &mut BackshiftOnDrop<'_, T, N>, + g: &mut BackshiftOnDrop<'_, T, N, A>, ) where F: FnMut(&mut T) -> bool, { @@ -859,10 +899,10 @@ impl Vec { } // Stage 1: Nothing was deleted. - process_loop::(original_len, &mut f, &mut g); + process_loop::(original_len, &mut f, &mut g); // Stage 2: Some elements were deleted. - process_loop::(original_len, &mut f, &mut g); + process_loop::(original_len, &mut f, &mut g); // All item are processed. This can be optimized to `set_len` by LLVM. drop(g); @@ -871,13 +911,13 @@ impl Vec { // Trait implementations -impl Default for Vec { +impl Default for Vec { fn default() -> Self { Self::new() } } -impl fmt::Debug for Vec +impl fmt::Debug for Vec where T: fmt::Debug, { @@ -895,7 +935,7 @@ impl fmt::Write for Vec { } } -impl Drop for Vec { +impl Drop for Vec { fn drop(&mut self) { // We drop each element used in the vector by turning into a `&mut [T]`. unsafe { @@ -904,13 +944,13 @@ impl Drop for Vec { } } -impl From<[T; M]> for Vec { +impl From<[T; M]> for Vec { fn from(array: [T; M]) -> Self { Self::from_array(array) } } -impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { +impl<'a, T: Clone, const N: usize, A> TryFrom<&'a [T]> for Vec { type Error = (); fn try_from(slice: &'a [T]) -> Result { @@ -918,7 +958,7 @@ impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { } } -impl Extend for Vec { +impl Extend for Vec { fn extend(&mut self, iter: I) where I: IntoIterator, @@ -927,7 +967,7 @@ impl Extend for Vec { } } -impl<'a, T, const N: usize> Extend<&'a T> for Vec +impl<'a, T, const N: usize, A> Extend<&'a T> for Vec where T: 'a + Copy, { @@ -939,7 +979,7 @@ where } } -impl hash::Hash for Vec +impl hash::Hash for Vec where T: core::hash::Hash, { @@ -948,7 +988,7 @@ where } } -impl<'a, T, const N: usize> IntoIterator for &'a Vec { +impl<'a, T, const N: usize, A> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -957,7 +997,7 @@ impl<'a, T, const N: usize> IntoIterator for &'a Vec { } } -impl<'a, T, const N: usize> IntoIterator for &'a mut Vec { +impl<'a, T, const N: usize, A> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -966,7 +1006,7 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut Vec { } } -impl FromIterator for Vec { +impl FromIterator for Vec { fn from_iter(iter: I) -> Self where I: IntoIterator, @@ -982,12 +1022,12 @@ impl FromIterator for Vec { /// An iterator that moves out of an [`Vec`][`Vec`]. /// /// This struct is created by calling the `into_iter` method on [`Vec`][`Vec`]. -pub struct IntoIter { - vec: Vec, +pub struct IntoIter { + vec: Vec, next: usize, } -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { if self.next < self.vec.len() { @@ -1000,7 +1040,7 @@ impl Iterator for IntoIter { } } -impl Clone for IntoIter +impl Clone for IntoIter where T: Clone, { @@ -1010,7 +1050,7 @@ where if self.next < self.vec.len() { let s = unsafe { slice::from_raw_parts( - (self.vec.buffer.as_ptr() as *const T).add(self.next), + (self.vec.buffer.as_ptr()).add(self.next), self.vec.len() - self.next, ) }; @@ -1021,7 +1061,7 @@ where } } -impl Drop for IntoIter { +impl Drop for IntoIter { fn drop(&mut self) { unsafe { // Drop all the elements that have not been moved out of vec @@ -1032,141 +1072,142 @@ impl Drop for IntoIter { } } -impl IntoIterator for Vec { +impl IntoIterator for Vec { type Item = T; - type IntoIter = IntoIter; + type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { vec: self, next: 0 } } } -impl PartialEq> for Vec +impl PartialEq> + for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(self, &**other) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(self, &**other) } } // Vec == [B] -impl PartialEq<[B]> for Vec +impl PartialEq<[T2]> for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &[B]) -> bool { - <[A]>::eq(self, other) + fn eq(&self, other: &[T2]) -> bool { + <[T1]>::eq(self, other) } } // [B] == Vec -impl PartialEq> for [B] +impl PartialEq> for [T2] where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, self) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(other, self) } } // Vec == &[B] -impl PartialEq<&[B]> for Vec +impl PartialEq<&[T2]> for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &&[B]) -> bool { - <[A]>::eq(self, &other[..]) + fn eq(&self, other: &&[T2]) -> bool { + <[T1]>::eq(self, &other[..]) } } // &[B] == Vec -impl PartialEq> for &[B] +impl PartialEq> for &[T2] where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(other, &self[..]) } } // Vec == &mut [B] -impl PartialEq<&mut [B]> for Vec +impl PartialEq<&mut [T2]> for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &&mut [B]) -> bool { - <[A]>::eq(self, &other[..]) + fn eq(&self, other: &&mut [T2]) -> bool { + <[T1]>::eq(self, &other[..]) } } // &mut [B] == Vec -impl PartialEq> for &mut [B] +impl PartialEq> for &mut [T2] where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(other, &self[..]) } } // Vec == [B; M] // Equality does not require equal capacity -impl PartialEq<[B; M]> for Vec +impl PartialEq<[T2; M]> for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &[B; M]) -> bool { - <[A]>::eq(self, &other[..]) + fn eq(&self, other: &[T2; M]) -> bool { + <[T1]>::eq(self, &other[..]) } } // [B; M] == Vec // Equality does not require equal capacity -impl PartialEq> for [B; M] +impl PartialEq> for [T2; M] where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(other, &self[..]) } } // Vec == &[B; M] // Equality does not require equal capacity -impl PartialEq<&[B; M]> for Vec +impl PartialEq<&[T2; M]> for Vec where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &&[B; M]) -> bool { - <[A]>::eq(self, &other[..]) + fn eq(&self, other: &&[T2; M]) -> bool { + <[T1]>::eq(self, &other[..]) } } // &[B; M] == Vec // Equality does not require equal capacity -impl PartialEq> for &[B; M] +impl PartialEq> for &[T2; M] where - A: PartialEq, + T1: PartialEq, { - fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + fn eq(&self, other: &Vec) -> bool { + <[T1]>::eq(other, &self[..]) } } // Implements Eq if underlying data is Eq -impl Eq for Vec where T: Eq {} +impl Eq for Vec where T: Eq {} -impl PartialOrd> for Vec +impl PartialOrd> for Vec where T: PartialOrd, { - fn partial_cmp(&self, other: &Vec) -> Option { + fn partial_cmp(&self, other: &Vec) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } -impl Ord for Vec +impl Ord for Vec where T: Ord, { @@ -1176,7 +1217,7 @@ where } } -impl ops::Deref for Vec { +impl ops::Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { @@ -1184,41 +1225,41 @@ impl ops::Deref for Vec { } } -impl ops::DerefMut for Vec { +impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } -impl AsRef> for Vec { +impl AsRef> for Vec { #[inline] fn as_ref(&self) -> &Self { self } } -impl AsMut> for Vec { +impl AsMut> for Vec { #[inline] fn as_mut(&mut self) -> &mut Self { self } } -impl AsRef<[T]> for Vec { +impl AsRef<[T]> for Vec { #[inline] fn as_ref(&self) -> &[T] { self } } -impl AsMut<[T]> for Vec { +impl AsMut<[T]> for Vec { #[inline] fn as_mut(&mut self) -> &mut [T] { self } } -impl Clone for Vec +impl Clone for Vec where T: Clone, {