From e9f8bac7ec4641c5ff8a7170e3d535c0e0e3b17a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 27 Jun 2024 20:34:43 +0200 Subject: [PATCH 1/4] vec: remove code duplication due to VecView. --- src/lib.rs | 10 +- src/storage.rs | 35 ++ src/vec.rs | 1434 ++++++++++++++---------------------------------- 3 files changed, 443 insertions(+), 1036 deletions(-) create mode 100644 src/storage.rs diff --git a/src/lib.rs b/src/lib.rs index b5238c672c..9d51d40cc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,13 +96,6 @@ pub use indexmap::{ pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter}; pub use linear_map::LinearMap; pub use string::String; - -// Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented. -// cfg(doc) prevents `VecInner` being part of the public API. -// doc(hidden) prevents the `pub use vec::VecInner` from being visible in the documentation. -#[cfg(doc)] -#[doc(hidden)] -pub use vec::VecInner as _; pub use vec::{Vec, VecView}; #[macro_use] @@ -114,8 +107,9 @@ mod histbuf; mod indexmap; mod indexset; mod linear_map; +pub mod storage; pub mod string; -mod vec; +pub mod vec; #[cfg(feature = "serde")] mod de; diff --git a/src/storage.rs b/src/storage.rs new file mode 100644 index 0000000000..6d19aed511 --- /dev/null +++ b/src/storage.rs @@ -0,0 +1,35 @@ +//! `Storage` trait defining how data is stored in a container. + +use core::borrow::{Borrow, BorrowMut}; + +pub(crate) trait SealedStorage { + type Buffer: ?Sized + Borrow<[T]> + BorrowMut<[T]>; +} + +/// Trait defining how data for a container is stored. +/// +/// There's two implementations available: +/// +/// - [`OwnedStorage`]: stores the data in an array `[T; N]` whose size is known at compile time. +/// - [`ViewStorage`]: stores the data in an unsized `[T]`. +/// +/// This allows containers to be generic over either sized or unsized storage. +/// +/// This trait is sealed, so you cannot implement it for your own types. You can only use +/// the implementations provided by this crate. +#[allow(private_bounds)] +pub trait Storage: SealedStorage {} + +/// Implementation of [`Storage`] that stores the data in an array `[T; N]` whose size is known at compile time. +pub enum OwnedStorage {} +impl Storage for OwnedStorage {} +impl SealedStorage for OwnedStorage { + type Buffer = [T; N]; +} + +/// Implementation of [`Storage`] that stores the data in an unsized `[T]`. +pub enum ViewStorage {} +impl Storage for ViewStorage {} +impl SealedStorage for ViewStorage { + type Buffer = [T]; +} diff --git a/src/vec.rs b/src/vec.rs index 1db505bb8f..2297087fbb 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,43 +1,22 @@ +//! A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). + use core::{ + borrow::{Borrow, BorrowMut}, cmp::Ordering, - fmt, hash, mem, - mem::{ManuallyDrop, MaybeUninit}, + fmt, hash, + mem::{self, ManuallyDrop, MaybeUninit}, ops, ptr, slice, }; -pub trait VecBuffer { - type T; - - fn as_vecview(vec: &VecInner) -> &VecView; - fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView; -} - -impl VecBuffer for [MaybeUninit; N] { - type T = T; - - fn as_vecview(vec: &VecInner) -> &VecView { - vec - } - fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView { - vec - } -} - -impl VecBuffer for [MaybeUninit] { - type T = T; - - fn as_vecview(vec: &VecInner) -> &VecView { - vec - } - fn as_mut_vecview(vec: &mut VecInner) -> &mut VecView { - vec - } -} +use crate::storage::{OwnedStorage, Storage, ViewStorage}; -///
This is private API and should not be used
-pub struct VecInner { +/// Base struct for [`Vec`] and [`VecView`], generic over the [`Storage`]. +/// +/// In most cases you should use [`Vec`] or [`VecView`] directly. Only use this +/// struct if you want to write code that's generic over both. +pub struct VecInner { len: usize, - buffer: B, + buffer: S::Buffer>, } /// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). @@ -77,7 +56,7 @@ pub struct VecInner { /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); /// let view: &VecView<_> = &vec; /// ``` -pub type Vec = VecInner<[MaybeUninit; N]>; +pub type Vec = VecInner>; /// A [`Vec`] with dynamic capacity /// @@ -100,17 +79,184 @@ pub type Vec = VecInner<[MaybeUninit; N]>; /// mut_view.push(5); /// assert_eq!(vec, [1, 2, 3, 4, 5]); /// ``` -pub type VecView = VecInner<[MaybeUninit]>; +pub type VecView = VecInner; + +impl Vec { + const ELEM: MaybeUninit = MaybeUninit::uninit(); + const INIT: [MaybeUninit; N] = [Self::ELEM; N]; // important for optimization of `new` + + /// Constructs a new, empty vector with a fixed capacity of `N` + /// + /// # Examples + /// + /// ``` + /// use heapless::Vec; + /// + /// // allocate the vector on the stack + /// let mut x: Vec = Vec::new(); + /// + /// // allocate the vector in a static variable + /// static mut X: Vec = Vec::new(); + /// ``` + pub const fn new() -> Self { + Self { + len: 0, + buffer: Self::INIT, + } + } + + /// Constructs a new vector with a fixed capacity of `N` and fills it + /// with the provided slice. + /// + /// This is equivalent to the following code: + /// + /// ``` + /// use heapless::Vec; + /// + /// let mut v: Vec = Vec::new(); + /// v.extend_from_slice(&[1, 2, 3]).unwrap(); + /// ``` + #[allow(clippy::result_unit_err)] + pub fn from_slice(other: &[T]) -> Result + where + T: Clone, + { + let mut v = Vec::new(); + v.extend_from_slice(other)?; + Ok(v) + } + + /// Constructs a new vector with a fixed capacity of `N`, initializing + /// it with the provided array. + /// + /// The length of the provided array, `M` may be equal to _or_ less than + /// the capacity of the vector, `N`. + /// + /// If the length of the provided array is greater than the capacity of the + /// vector a compile-time error will be produced. + pub fn from_array(src: [T; M]) -> Self { + // Const assert M >= 0 + crate::sealed::greater_than_eq_0::(); + // Const assert N >= M + crate::sealed::greater_than_eq::(); + + // We've got to copy `src`, but we're functionally moving it. Don't run + // any Drop code for T. + let src = ManuallyDrop::new(src); + + if N == M { + Self { + len: N, + // NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit; N] + // have the same layout when N == M. + buffer: unsafe { mem::transmute_copy(&src) }, + } + } else { + let mut v = Vec::::new(); + + 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. + dst_elem.write(unsafe { ptr::read(src_elem) }); + } + + v.len = M; + v + } + } + + /// Returns the contents of the vector as an array of length `M` if the length + /// of the vector is exactly `M`, otherwise returns `Err(self)`. + /// + /// # Examples + /// + /// ``` + /// use heapless::Vec; + /// let buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); + /// let array: [u8; 5] = buffer.into_array().unwrap(); + /// assert_eq!(array, [1, 2, 3, 5, 8]); + /// ``` + 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() }; + + // We don't want `self`'s destructor to be called because that would drop all the + // items in the array + core::mem::forget(self); + + Ok(array) + } else { + Err(self) + } + } -impl VecView { + /// Clones a vec into a new vec + pub(crate) fn clone(&self) -> Self + where + T: Clone, + { + let mut new = Self::new(); + // avoid `extend_from_slice` as that introduces a runtime check/panicking branch + for elem in self { + unsafe { + new.push_unchecked(elem.clone()); + } + } + new + } + + /// Get a reference to the `Vec`, erasing the `N` const-generic. + /// + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &VecView = vec.as_view(); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &VecView = &vec; + /// ``` + #[inline] + pub const fn as_view(&self) -> &VecView { + self + } + + /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &mut VecView = vec.as_mut_view(); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{Vec, VecView}; + /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let view: &mut VecView = &mut vec; + /// ``` + #[inline] + pub fn as_mut_view(&mut self) -> &mut VecView { + self + } +} + +impl VecInner { /// 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.borrow().as_ptr() as *const T } /// 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.borrow_mut().as_mut_ptr() as *mut T } /// Extracts a slice containing the entire vector. @@ -120,15 +266,14 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; - /// - /// let buffer: &VecView = &Vec::::from_slice(&[1, 2, 3, 5, 8]).unwrap(); + /// use heapless::Vec; + /// let buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); /// assert_eq!(buffer.as_slice(), &[1, 2, 3, 5, 8]); /// ``` 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.buffer.borrow().as_ptr() as *const T, self.len) } } /// Extracts a mutable slice containing the entire vector. @@ -138,8 +283,8 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; - /// let mut buffer: &mut VecView = &mut Vec::::from_slice(&[1, 2, 3, 5, 8]).unwrap(); + /// use heapless::Vec; + /// let mut buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); /// let buffer_slice = buffer.as_mut_slice(); /// buffer_slice[0] = 9; /// assert_eq!(buffer.as_slice(), &[9, 2, 3, 5, 8]); @@ -147,12 +292,14 @@ impl VecView { 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.buffer.borrow_mut().as_mut_ptr() as *mut T, self.len) + } } /// Returns the maximum number of elements the vector can hold. - pub const fn capacity(&self) -> usize { - self.buffer.len() + pub fn capacity(&self) -> usize { + self.buffer.borrow().len() } /// Clears the vector, removing all values. @@ -182,9 +329,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let vec: &mut VecView = &mut Vec::::new(); + /// let mut vec = Vec::::new(); /// vec.push(1).unwrap(); /// vec.extend_from_slice(&[2, 3, 4]).unwrap(); /// assert_eq!(*vec, [1, 2, 3, 4]); @@ -237,7 +384,11 @@ impl VecView { debug_assert!(!self.is_empty()); self.len -= 1; - self.buffer.get_unchecked_mut(self.len).as_ptr().read() + self.buffer + .borrow_mut() + .get_unchecked_mut(self.len) + .as_ptr() + .read() } /// Appends an `item` to the back of the collection @@ -250,7 +401,7 @@ impl VecView { // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory debug_assert!(!self.is_full()); - *self.buffer.get_unchecked_mut(self.len) = MaybeUninit::new(item); + *self.buffer.borrow_mut().get_unchecked_mut(self.len) = MaybeUninit::new(item); self.len += 1; } @@ -346,7 +497,7 @@ impl VecView { /// /// ```no_run /// # #![allow(dead_code)] - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// /// # // This is just a minimal skeleton for the doc example; /// # // don't use this as a starting point for a real library. @@ -363,7 +514,6 @@ impl VecView { /// pub fn get_dictionary(&self) -> Option> { /// // Per the FFI method's docs, "32768 bytes is always enough". /// let mut dict = Vec::new(); - /// let mut dict_view: &mut VecView<_> = &mut dict; /// let mut dict_length = 0; /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that: /// // 1. `dict_length` elements were initialized. @@ -371,10 +521,10 @@ impl VecView { /// // which makes `set_len` safe to call. /// unsafe { /// // Make the FFI call... - /// let r = deflateGetDictionary(self.strm, dict_view.as_mut_ptr(), &mut dict_length); + /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); /// if r == Z_OK { /// // ...and update the length to what was initialized. - /// dict_view.set_len(dict_length); + /// dict.set_len(dict_length); /// Some(dict) /// } else { /// None @@ -389,7 +539,7 @@ impl VecView { /// /// ``` /// use core::iter::FromIterator; - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// /// let mut vec = Vec::, 3>::from_iter( /// [ @@ -404,7 +554,7 @@ impl VecView { /// // 1. `old_len..0` is empty so no elements need to be initialized. /// // 2. `0 <= capacity` always holds whatever `capacity` is. /// unsafe { - /// vec.as_mut_view().set_len(0); + /// vec.set_len(0); /// } /// ``` /// @@ -429,19 +579,19 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let v: &mut VecView<_> = &mut Vec::<_, 8>::new(); + /// let mut v: Vec<_, 8> = Vec::new(); /// v.push("foo").unwrap(); /// v.push("bar").unwrap(); /// v.push("baz").unwrap(); /// v.push("qux").unwrap(); /// /// assert_eq!(v.swap_remove(1), "bar"); - /// assert_eq!(v, &["foo", "qux", "baz"]); + /// assert_eq!(&*v, ["foo", "qux", "baz"]); /// /// assert_eq!(v.swap_remove(0), "foo"); - /// assert_eq!(v, &["baz", "qux"]); + /// assert_eq!(&*v, ["baz", "qux"]); /// ``` pub fn swap_remove(&mut self, index: usize) -> T { assert!(index < self.len); @@ -461,19 +611,19 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut v: &mut VecView<_> = &mut Vec::<_, 8>::new(); + /// let mut v: Vec<_, 8> = Vec::new(); /// v.push("foo").unwrap(); /// v.push("bar").unwrap(); /// v.push("baz").unwrap(); /// v.push("qux").unwrap(); /// /// assert_eq!(unsafe { v.swap_remove_unchecked(1) }, "bar"); - /// assert_eq!(v, &["foo", "qux", "baz"]); + /// assert_eq!(&*v, ["foo", "qux", "baz"]); /// /// assert_eq!(unsafe { v.swap_remove_unchecked(0) }, "foo"); - /// assert_eq!(v, &["baz", "qux"]); + /// assert_eq!(&*v, ["baz", "qux"]); /// ``` pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T { let length = self.len(); @@ -486,13 +636,11 @@ impl VecView { } /// Returns true if the vec is full - #[inline] pub fn is_full(&self) -> bool { self.len == self.capacity() } /// Returns true if the vec is empty - #[inline] pub fn is_empty(&self) -> bool { self.len == 0 } @@ -504,14 +652,13 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let v: &VecView<_> = &Vec::<_, 8>::from_slice(b"abc").unwrap(); + /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); /// assert_eq!(v.starts_with(b""), true); /// assert_eq!(v.starts_with(b"ab"), true); /// assert_eq!(v.starts_with(b"bc"), false); /// ``` - #[inline] pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq, @@ -527,14 +674,13 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let v: &VecView<_> = &Vec::<_, 8>::from_slice(b"abc").unwrap(); + /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); /// assert_eq!(v.ends_with(b""), true); /// assert_eq!(v.ends_with(b"ab"), false); /// assert_eq!(v.ends_with(b"bc"), true); /// ``` - #[inline] pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq, @@ -555,13 +701,13 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3]).unwrap(); + /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); /// vec.insert(1, 4); - /// assert_eq!(vec, &[1, 4, 2, 3]); + /// assert_eq!(vec, [1, 4, 2, 3]); /// vec.insert(4, 5); - /// assert_eq!(vec, &[1, 4, 2, 3, 5]); + /// assert_eq!(vec, [1, 4, 2, 3, 5]); /// ``` pub fn insert(&mut self, index: usize, element: T) -> Result<(), T> { let len = self.len(); @@ -614,11 +760,11 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut v: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3]).unwrap(); + /// let mut v: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); /// assert_eq!(v.remove(1), 2); - /// assert_eq!(v, &[1, 3]); + /// assert_eq!(v, [1, 3]); /// ``` pub fn remove(&mut self, index: usize) -> T { let len = self.len(); @@ -652,24 +798,24 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); /// vec.retain(|&x| x % 2 == 0); - /// assert_eq!(vec, &[2, 4]); + /// assert_eq!(vec, [2, 4]); /// ``` /// /// Because the elements are visited exactly once in the original order, /// external state may be used to decide which elements to keep. /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3, 4, 5]).unwrap(); + /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4, 5]).unwrap(); /// let keep = [false, true, true, false, true]; /// let mut iter = keep.iter(); /// vec.retain(|_| *iter.next().unwrap()); - /// assert_eq!(vec, &[2, 3, 5]); + /// assert_eq!(vec, [2, 3, 5]); /// ``` pub fn retain(&mut self, mut f: F) where @@ -687,9 +833,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// - /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); /// vec.retain_mut(|x| { /// if *x <= 3 { /// *x += 1; @@ -698,7 +844,7 @@ impl VecView { /// false /// } /// }); - /// assert_eq!(vec, &[2, 3, 4]); + /// assert_eq!(vec, [2, 3, 4]); /// ``` pub fn retain_mut(&mut self, mut f: F) where @@ -720,14 +866,14 @@ impl VecView { // 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> { - v: &'a mut VecView, + struct BackshiftOnDrop<'a, T, S: Storage> { + v: &'a mut VecInner, processed_len: usize, deleted_cnt: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, T> { + impl<'a, T, S: Storage> Drop for BackshiftOnDrop<'a, T, S> { fn drop(&mut self) { if self.deleted_cnt > 0 { // SAFETY: Trailing unchecked items must be valid since we never touch them. @@ -755,10 +901,10 @@ impl VecView { original_len, }; - fn process_loop( + fn process_loop( original_len: usize, f: &mut F, - g: &mut BackshiftOnDrop<'_, T>, + g: &mut BackshiftOnDrop<'_, T, S>, ) where F: FnMut(&mut T) -> bool, { @@ -792,10 +938,10 @@ impl VecView { } // 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); @@ -809,722 +955,31 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::{Vec, VecView}; + /// use heapless::Vec; /// /// // Allocate vector big enough for 10 elements. /// let mut v: Vec<_, 10> = Vec::new(); - /// let view: &mut VecView<_> = &mut v; /// /// // Fill in the first 3 elements. - /// let uninit = view.spare_capacity_mut(); + /// let uninit = v.spare_capacity_mut(); /// uninit[0].write(0); /// uninit[1].write(1); /// uninit[2].write(2); /// /// // Mark the first 3 elements of the vector as being initialized. /// unsafe { - /// view.set_len(3); + /// v.set_len(3); /// } /// - /// assert_eq!(view, &[0, 1, 2]); + /// assert_eq!(&v, &[0, 1, 2]); /// ``` + #[inline] pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { - &mut self.buffer[self.len..] + &mut self.buffer.borrow_mut()[self.len..] } } -impl Vec { - const ELEM: MaybeUninit = MaybeUninit::uninit(); - const INIT: [MaybeUninit; N] = [Self::ELEM; N]; // important for optimization of `new` - - /// Constructs a new, empty vector with a fixed capacity of `N` - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// // allocate the vector on the stack - /// let mut x: Vec = Vec::new(); - /// - /// // allocate the vector in a static variable - /// static mut X: Vec = Vec::new(); - /// ``` - pub const fn new() -> Self { - Self { - len: 0, - buffer: Self::INIT, - } - } - - /// Constructs a new vector with a fixed capacity of `N` and fills it - /// with the provided slice. - /// - /// This is equivalent to the following code: - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut v: Vec = Vec::new(); - /// v.extend_from_slice(&[1, 2, 3]).unwrap(); - /// ``` - #[inline] - #[allow(clippy::result_unit_err)] - pub fn from_slice(other: &[T]) -> Result - where - T: Clone, - { - let mut v = Vec::new(); - v.extend_from_slice(other)?; - Ok(v) - } - - /// Constructs a new vector with a fixed capacity of `N`, initializing - /// it with the provided array. - /// - /// The length of the provided array, `M` may be equal to _or_ less than - /// the capacity of the vector, `N`. - /// - /// If the length of the provided array is greater than the capacity of the - /// vector a compile-time error will be produced. - pub fn from_array(src: [T; M]) -> Self { - // Const assert M >= 0 - crate::sealed::greater_than_eq_0::(); - // Const assert N >= M - crate::sealed::greater_than_eq::(); - - // We've got to copy `src`, but we're functionally moving it. Don't run - // any Drop code for T. - let src = ManuallyDrop::new(src); - - if N == M { - Self { - len: N, - // NOTE(unsafe) ManuallyDrop<[T; M]> and [MaybeUninit; N] - // have the same layout when N == M. - buffer: unsafe { mem::transmute_copy(&src) }, - } - } else { - let mut v = Vec::::new(); - - 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. - dst_elem.write(unsafe { ptr::read(src_elem) }); - } - - v.len = M; - v - } - } - - /// Clones a vec into a new vec - pub(crate) fn clone(&self) -> Self - where - T: Clone, - { - let mut new = Self::new(); - // avoid `extend_from_slice` as that introduces a runtime check/panicking branch - for elem in self { - unsafe { - new.push_unchecked(elem.clone()); - } - } - new - } - - /// Get a reference to the `Vec`, erasing the `N` const-generic. - /// - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &VecView = vec.as_view(); - /// ``` - /// - /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &VecView = &vec; - /// ``` - #[inline] - pub const fn as_view(&self) -> &VecView { - self - } - - /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &mut VecView = vec.as_mut_view(); - /// ``` - /// - /// It is often preferable to do the same through type coerction, since `Vec` implements `Unsize>`: - /// - /// ```rust - /// # use heapless::{Vec, VecView}; - /// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// let view: &mut VecView = &mut vec; - /// ``` - #[inline] - pub fn as_mut_view(&mut self) -> &mut VecView { - self - } - - /// Extracts a slice containing the entire vector. - /// - /// Equivalent to `&s[..]`. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// let buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); - /// assert_eq!(buffer.as_slice(), &[1, 2, 3, 5, 8]); - /// ``` - #[inline] - pub fn as_slice(&self) -> &[T] { - self.as_view().as_slice() - } - - /// Returns the contents of the vector as an array of length `M` if the length - /// of the vector is exactly `M`, otherwise returns `Err(self)`. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// let buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); - /// let array: [u8; 5] = buffer.into_array().unwrap(); - /// assert_eq!(array, [1, 2, 3, 5, 8]); - /// ``` - 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() }; - - // We don't want `self`'s destructor to be called because that would drop all the - // items in the array - core::mem::forget(self); - - Ok(array) - } else { - Err(self) - } - } - - /// Extracts a mutable slice containing the entire vector. - /// - /// Equivalent to `&mut s[..]`. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// let mut buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); - /// let buffer_slice = buffer.as_mut_slice(); - /// buffer_slice[0] = 9; - /// assert_eq!(buffer.as_slice(), &[9, 2, 3, 5, 8]); - /// ``` - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [T] { - self.as_mut_view().as_mut_slice() - } - - /// Returns the maximum number of elements the vector can hold. - pub const fn capacity(&self) -> usize { - N - } - - /// Clears the vector, removing all values. - #[inline] - pub fn clear(&mut self) { - self.as_mut_view().clear() - } - - /// Extends the vec from an iterator. - /// - /// # Panic - /// - /// Panics if the vec cannot hold all elements of the iterator. - #[inline] - pub fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - self.as_mut_view().extend(iter) - } - - /// Clones and appends all elements in a slice to the `Vec`. - /// - /// Iterates over the slice `other`, clones each element, and then appends - /// it to this `Vec`. The `other` vector is traversed in-order. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut vec = Vec::::new(); - /// vec.push(1).unwrap(); - /// vec.extend_from_slice(&[2, 3, 4]).unwrap(); - /// assert_eq!(*vec, [1, 2, 3, 4]); - /// ``` - #[allow(clippy::result_unit_err)] - #[inline] - pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> - where - T: Clone, - { - self.as_mut_view().extend_from_slice(other) - } - - /// Removes the last element from a vector and returns it, or `None` if it's empty - #[inline] - pub fn pop(&mut self) -> Option { - self.as_mut_view().pop() - } - - /// Appends an `item` to the back of the collection - /// - /// Returns back the `item` if the vector is full. - #[inline] - pub fn push(&mut self, item: T) -> Result<(), T> { - self.as_mut_view().push(item) - } - - /// Removes the last element from a vector and returns it - /// - /// # Safety - /// - /// This assumes the vec to have at least one element. - #[inline] - pub unsafe fn pop_unchecked(&mut self) -> T { - self.as_mut_view().pop_unchecked() - } - - /// Appends an `item` to the back of the collection - /// - /// # Safety - /// - /// This assumes the vec is not full. - #[inline] - pub unsafe fn push_unchecked(&mut self, item: T) { - self.as_mut_view().push_unchecked(item) - } - - /// Shortens the vector, keeping the first `len` elements and dropping the rest. - #[inline] - pub fn truncate(&mut self, len: usize) { - self.as_mut_view().truncate(len) - } - - /// Resizes the Vec in-place so that len is equal to new_len. - /// - /// If new_len is greater than len, the Vec is extended by the - /// difference, with each additional slot filled with value. If - /// new_len is less than len, the Vec is simply truncated. - /// - /// See also [`resize_default`](Self::resize_default). - #[allow(clippy::result_unit_err)] - #[inline] - pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), ()> - where - T: Clone, - { - self.as_mut_view().resize(new_len, value) - } - - /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. - /// - /// If `new_len` is greater than `len`, the `Vec` is extended by the - /// difference, with each additional slot filled with `Default::default()`. - /// If `new_len` is less than `len`, the `Vec` is simply truncated. - /// - /// See also [`resize`](Self::resize). - #[allow(clippy::result_unit_err)] - #[inline] - pub fn resize_default(&mut self, new_len: usize) -> Result<(), ()> - where - T: Clone + Default, - { - self.as_mut_view().resize_default(new_len) - } - - /// Forces the length of the vector to `new_len`. - /// - /// This is a low-level operation that maintains none of the normal - /// invariants of the type. Normally changing the length of a vector - /// is done using one of the safe operations instead, such as - /// [`truncate`], [`resize`], [`extend`], or [`clear`]. - /// - /// [`truncate`]: Self::truncate - /// [`resize`]: Self::resize - /// [`extend`]: core::iter::Extend - /// [`clear`]: Self::clear - /// - /// # Safety - /// - /// - `new_len` must be less than or equal to [`capacity()`]. - /// - The elements at `old_len..new_len` must be initialized. - /// - /// [`capacity()`]: Self::capacity - /// - /// # Examples - /// - /// This method can be useful for situations in which the vector - /// is serving as a buffer for other code, particularly over FFI: - /// - /// ```no_run - /// # #![allow(dead_code)] - /// use heapless::Vec; - /// - /// # // This is just a minimal skeleton for the doc example; - /// # // don't use this as a starting point for a real library. - /// # pub struct StreamWrapper { strm: *mut core::ffi::c_void } - /// # const Z_OK: i32 = 0; - /// # extern "C" { - /// # fn deflateGetDictionary( - /// # strm: *mut core::ffi::c_void, - /// # dictionary: *mut u8, - /// # dictLength: *mut usize, - /// # ) -> i32; - /// # } - /// # impl StreamWrapper { - /// pub fn get_dictionary(&self) -> Option> { - /// // Per the FFI method's docs, "32768 bytes is always enough". - /// let mut dict = Vec::new(); - /// let mut dict_length = 0; - /// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that: - /// // 1. `dict_length` elements were initialized. - /// // 2. `dict_length` <= the capacity (32_768) - /// // which makes `set_len` safe to call. - /// unsafe { - /// // Make the FFI call... - /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); - /// if r == Z_OK { - /// // ...and update the length to what was initialized. - /// dict.set_len(dict_length); - /// Some(dict) - /// } else { - /// None - /// } - /// } - /// } - /// # } - /// ``` - /// - /// While the following example is sound, there is a memory leak since - /// the inner vectors were not freed prior to the `set_len` call: - /// - /// ``` - /// use core::iter::FromIterator; - /// use heapless::Vec; - /// - /// let mut vec = Vec::, 3>::from_iter( - /// [ - /// Vec::from_iter([1, 0, 0].iter().cloned()), - /// Vec::from_iter([0, 1, 0].iter().cloned()), - /// Vec::from_iter([0, 0, 1].iter().cloned()), - /// ] - /// .iter() - /// .cloned(), - /// ); - /// // SAFETY: - /// // 1. `old_len..0` is empty so no elements need to be initialized. - /// // 2. `0 <= capacity` always holds whatever `capacity` is. - /// unsafe { - /// vec.set_len(0); - /// } - /// ``` - /// - /// Normally, here, one would use [`clear`] instead to correctly drop - /// the contents and thus not leak memory. - pub unsafe fn set_len(&mut self, new_len: usize) { - debug_assert!(new_len <= self.capacity()); - - self.len = new_len - } - - /// Removes an element from the vector and returns it. - /// - /// The removed element is replaced by the last element of the vector. - /// - /// This does not preserve ordering, but is *O*(1). - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut v: Vec<_, 8> = Vec::new(); - /// v.push("foo").unwrap(); - /// v.push("bar").unwrap(); - /// v.push("baz").unwrap(); - /// v.push("qux").unwrap(); - /// - /// assert_eq!(v.swap_remove(1), "bar"); - /// assert_eq!(&*v, ["foo", "qux", "baz"]); - /// - /// assert_eq!(v.swap_remove(0), "foo"); - /// assert_eq!(&*v, ["baz", "qux"]); - /// ``` - #[inline] - pub fn swap_remove(&mut self, index: usize) -> T { - self.as_mut_view().swap_remove(index) - } - - /// Removes an element from the vector and returns it. - /// - /// The removed element is replaced by the last element of the vector. - /// - /// This does not preserve ordering, but is *O*(1). - /// - /// # Safety - /// - /// Assumes `index` within bounds. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut v: Vec<_, 8> = Vec::new(); - /// v.push("foo").unwrap(); - /// v.push("bar").unwrap(); - /// v.push("baz").unwrap(); - /// v.push("qux").unwrap(); - /// - /// assert_eq!(unsafe { v.swap_remove_unchecked(1) }, "bar"); - /// assert_eq!(&*v, ["foo", "qux", "baz"]); - /// - /// assert_eq!(unsafe { v.swap_remove_unchecked(0) }, "foo"); - /// assert_eq!(&*v, ["baz", "qux"]); - /// ``` - #[inline] - pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T { - self.as_mut_view().swap_remove_unchecked(index) - } - - /// Returns true if the vec is full - #[inline] - pub fn is_full(&self) -> bool { - self.len == self.capacity() - } - - /// Returns true if the vec is empty - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Returns `true` if `needle` is a prefix of the Vec. - /// - /// Always returns `true` if `needle` is an empty slice. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); - /// assert_eq!(v.starts_with(b""), true); - /// assert_eq!(v.starts_with(b"ab"), true); - /// assert_eq!(v.starts_with(b"bc"), false); - /// ``` - #[inline] - pub fn starts_with(&self, needle: &[T]) -> bool - where - T: PartialEq, - { - let n = needle.len(); - self.len >= n && needle == &self[..n] - } - - /// Returns `true` if `needle` is a suffix of the Vec. - /// - /// Always returns `true` if `needle` is an empty slice. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); - /// assert_eq!(v.ends_with(b""), true); - /// assert_eq!(v.ends_with(b"ab"), false); - /// assert_eq!(v.ends_with(b"bc"), true); - /// ``` - #[inline] - pub fn ends_with(&self, needle: &[T]) -> bool - where - T: PartialEq, - { - let (v, n) = (self.len(), needle.len()); - v >= n && needle == &self[v - n..] - } - - /// Inserts an element at position `index` within the vector, shifting all - /// elements after it to the right. - /// - /// Returns back the `element` if the vector is full. - /// - /// # Panics - /// - /// Panics if `index > len`. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); - /// vec.insert(1, 4); - /// assert_eq!(vec, [1, 4, 2, 3]); - /// vec.insert(4, 5); - /// assert_eq!(vec, [1, 4, 2, 3, 5]); - /// ``` - #[inline] - pub fn insert(&mut self, index: usize, element: T) -> Result<(), T> { - self.as_mut_view().insert(index, element) - } - - /// Removes and returns the element at position `index` within the vector, - /// shifting all elements after it to the left. - /// - /// Note: Because this shifts over the remaining elements, it has a - /// worst-case performance of *O*(n). If you don't need the order of - /// elements to be preserved, use [`swap_remove`] instead. If you'd like to - /// remove elements from the beginning of the `Vec`, consider using - /// [`Deque::pop_front`] instead. - /// - /// [`swap_remove`]: Vec::swap_remove - /// [`Deque::pop_front`]: crate::Deque::pop_front - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut v: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); - /// assert_eq!(v.remove(1), 2); - /// assert_eq!(v, [1, 3]); - /// ``` - #[inline] - pub fn remove(&mut self, index: usize) -> T { - self.as_mut_view().remove(index) - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` for which `f(&e)` returns `false`. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// vec.retain(|&x| x % 2 == 0); - /// assert_eq!(vec, [2, 4]); - /// ``` - /// - /// Because the elements are visited exactly once in the original order, - /// external state may be used to decide which elements to keep. - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4, 5]).unwrap(); - /// let keep = [false, true, true, false, true]; - /// let mut iter = keep.iter(); - /// vec.retain(|_| *iter.next().unwrap()); - /// assert_eq!(vec, [2, 3, 5]); - /// ``` - #[inline] - pub fn retain(&mut self, f: F) - where - F: FnMut(&T) -> bool, - { - self.as_mut_view().retain(f) - } - - /// Retains only the elements specified by the predicate, passing a mutable reference to it. - /// - /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. - /// This method operates in place, visiting each element exactly once in the - /// original order, and preserves the order of the retained elements. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); - /// vec.retain_mut(|x| { - /// if *x <= 3 { - /// *x += 1; - /// true - /// } else { - /// false - /// } - /// }); - /// assert_eq!(vec, [2, 3, 4]); - /// ``` - #[inline] - pub fn retain_mut(&mut self, f: F) - where - F: FnMut(&mut T) -> bool, - { - self.as_mut_view().retain_mut(f) - } - - /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit`. - /// - /// The returned slice can be used to fill the vector with data before marking the data as - /// initialized using the `set_len` method. - /// - /// # Examples - /// - /// ``` - /// use heapless::Vec; - /// - /// // Allocate vector big enough for 10 elements. - /// let mut v: Vec<_, 10> = Vec::new(); - /// - /// // Fill in the first 3 elements. - /// let uninit = v.spare_capacity_mut(); - /// uninit[0].write(0); - /// uninit[1].write(1); - /// uninit[2].write(2); - /// - /// // Mark the first 3 elements of the vector as being initialized. - /// unsafe { - /// v.set_len(3); - /// } - /// - /// assert_eq!(&v, &[0, 1, 2]); - /// ``` - #[inline] - pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { - self.as_mut_view().spare_capacity_mut() - } -} - -// Trait implementations +// Trait implementations impl Default for Vec { fn default() -> Self { @@ -1532,7 +987,7 @@ impl Default for Vec { } } -impl fmt::Debug for VecView +impl fmt::Debug for VecInner where T: fmt::Debug, { @@ -1541,26 +996,7 @@ where } } -impl fmt::Debug for Vec -where - T: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.as_view().fmt(f) - } -} - -impl fmt::Write for Vec { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.extend_from_slice(s.as_bytes()) { - Ok(()) => Ok(()), - Err(_) => Err(fmt::Error), - } - } -} - -impl fmt::Write for VecView { +impl fmt::Write for VecInner { fn write_str(&mut self, s: &str) -> fmt::Result { match self.extend_from_slice(s.as_bytes()) { Ok(()) => Ok(()), @@ -1575,9 +1011,9 @@ impl From<[T; M]> for Vec { } } -impl Drop for VecInner { +impl Drop for VecInner { fn drop(&mut self) { - let mut_slice = VecBuffer::as_mut_vecview(self).as_mut_slice(); + let mut_slice = self.as_mut_slice(); // We drop each element used in the vector by turning into a `&mut [T]`. // SAFETY: the buffer contains initialized data for the range 0..self.len unsafe { ptr::drop_in_place(mut_slice) } @@ -1592,7 +1028,7 @@ impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { } } -impl Extend for VecView { +impl Extend for VecInner { fn extend(&mut self, iter: I) where I: IntoIterator, @@ -1601,28 +1037,7 @@ impl Extend for VecView { } } -impl Extend for Vec { - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - self.as_mut_view().extend(iter) - } -} - -impl<'a, T, const N: usize> Extend<&'a T> for Vec -where - T: 'a + Copy, -{ - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - self.as_mut_view().extend(iter.into_iter().cloned()) - } -} - -impl<'a, T> Extend<&'a T> for VecView +impl<'a, T, S: Storage> Extend<&'a T> for VecInner where T: 'a + Copy, { @@ -1634,16 +1049,7 @@ where } } -impl hash::Hash for Vec -where - T: core::hash::Hash, -{ - fn hash(&self, state: &mut H) { - self.as_view().hash(state) - } -} - -impl hash::Hash for VecView +impl hash::Hash for VecInner where T: core::hash::Hash, { @@ -1652,16 +1058,7 @@ where } } -impl<'a, T, const N: usize> IntoIterator for &'a Vec { - type Item = &'a T; - type IntoIter = slice::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_view().iter() - } -} - -impl<'a, T> IntoIterator for &'a VecView { +impl<'a, T, S: Storage> IntoIterator for &'a VecInner { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -1670,16 +1067,7 @@ impl<'a, T> IntoIterator for &'a VecView { } } -impl<'a, T, const N: usize> IntoIterator for &'a mut Vec { - type Item = &'a mut T; - type IntoIter = slice::IterMut<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_mut_view().iter_mut() - } -} - -impl<'a, T> IntoIterator for &'a mut VecView { +impl<'a, T, S: Storage> IntoIterator for &'a mut VecInner { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -1763,185 +1151,173 @@ impl IntoIterator for Vec { } } -macro_rules! impl_cmp_traits { - ($Ty:ident<$T:ident $(, const $M:ident : usize, const $N:ident : usize)?>) => { - impl PartialEq> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &Vec) -> bool { - self.as_slice().eq(other.as_slice()) - } - } +impl PartialEq> for VecInner +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + self.as_slice().eq(other.as_slice()) + } +} - impl PartialEq> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &VecView) -> bool { - self.as_slice().eq(other.as_slice()) - } - } +impl PartialEq> for [A; M] +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + self.eq(other.as_slice()) + } +} - impl PartialEq<$Ty> for [A; M] - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &$Ty) -> bool { - self.eq(other.as_slice()) - } - } +impl PartialEq> for &[A; M] +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + (*self).eq(other) + } +} - impl PartialEq<$Ty> for &[A; M] - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &$Ty) -> bool { - (*self).eq(other) - } - } +impl PartialEq> for [A] +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + self.eq(other.as_slice()) + } +} - impl PartialEq<$Ty> for [A] - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &$Ty) -> bool { - self.eq(other.as_slice()) - } - } +impl PartialEq> for &[A] +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + (*self).eq(other) + } +} - impl PartialEq<$Ty> for &[A] - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &$Ty) -> bool { - (*self).eq(other) - } - } +impl PartialEq> for &mut [A] +where + A: PartialEq, +{ + fn eq(&self, other: &VecInner) -> bool { + (**self).eq(other) + } +} - impl PartialEq<[B; N]> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &[B; N]) -> bool { - self.as_slice().eq(other.as_slice()) - } - } +impl PartialEq<[B; N]> for VecInner +where + A: PartialEq, +{ + #[inline] + fn eq(&self, other: &[B; N]) -> bool { + self.as_slice().eq(other.as_slice()) + } +} - impl PartialEq<&[B; N]> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &&[B; N]) -> bool { - self.as_slice().eq(other.as_slice()) - } - } +impl PartialEq<&[B; N]> for VecInner +where + A: PartialEq, +{ + #[inline] + fn eq(&self, other: &&[B; N]) -> bool { + self.as_slice().eq(other.as_slice()) + } +} - impl PartialEq<[B]> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &[B]) -> bool { - self.as_slice().eq(other) - } - } +impl PartialEq<[B]> for VecInner +where + A: PartialEq, +{ + #[inline] + fn eq(&self, other: &[B]) -> bool { + self.as_slice().eq(other) + } +} - impl PartialEq<&[B]> for $Ty - where - A: PartialEq, - { - #[inline] - fn eq(&self, other: &&[B]) -> bool { - self.as_slice().eq(*other) - } - } +impl PartialEq<&[B]> for VecInner +where + A: PartialEq, +{ + #[inline] + fn eq(&self, other: &&[B]) -> bool { + self.as_slice().eq(*other) + } +} - impl Eq for $Ty where T: Eq {} +impl PartialEq<&mut [B]> for VecInner +where + A: PartialEq, +{ + #[inline] + fn eq(&self, other: &&mut [B]) -> bool { + self.as_slice().eq(*other) + } +} - impl PartialOrd<$Ty> for $Ty - where - T: PartialOrd - { - #[inline] - fn partial_cmp(&self, other: &$Ty) -> Option { - self.as_slice().partial_cmp(other.as_slice()) - } - } +// Implements Eq if underlying data is Eq +impl Eq for VecInner where T: Eq {} - impl Ord for $Ty - where - T: Ord - { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.as_slice().cmp(other.as_slice()) - } - } +impl PartialOrd> for VecInner +where + T: PartialOrd, +{ + fn partial_cmp(&self, other: &VecInner) -> Option { + self.as_slice().partial_cmp(other.as_slice()) } } -impl_cmp_traits!(VecView); -impl_cmp_traits!(Vec); - -macro_rules! impl_ref_traits { - ($Ty:ident<$T:ident $(, const $N:ident : usize)?>) => { - impl ops::Deref for $Ty { - type Target = [T]; +impl Ord for VecInner +where + T: Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.as_slice().cmp(other.as_slice()) + } +} - #[inline] - fn deref(&self) -> &Self::Target { - self.as_slice() - } - } +impl ops::Deref for VecInner { + type Target = [T]; - impl ops::DerefMut for $Ty { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut_slice() - } - } + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} - impl AsRef<$Ty> for $Ty { - #[inline] - fn as_ref(&self) -> &Self { - self - } - } +impl ops::DerefMut for VecInner { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} - impl AsMut<$Ty> for $Ty { - #[inline] - fn as_mut(&mut self) -> &mut Self { - self - } - } +impl AsRef> for VecInner { + #[inline] + fn as_ref(&self) -> &Self { + self + } +} - impl AsRef<[T]> for $Ty { - #[inline] - fn as_ref(&self) -> &[T] { - self - } - } +impl AsMut> for VecInner { + #[inline] + fn as_mut(&mut self) -> &mut Self { + self + } +} - impl AsMut<[T]> for $Ty { - #[inline] - fn as_mut(&mut self) -> &mut [T] { - self - } - } - }; +impl AsRef<[T]> for VecInner { + #[inline] + fn as_ref(&self) -> &[T] { + self + } } -impl_ref_traits!(VecView); -impl_ref_traits!(Vec); +impl AsMut<[T]> for VecInner { + #[inline] + fn as_mut(&mut self) -> &mut [T] { + self + } +} impl Clone for Vec where @@ -2025,7 +1401,8 @@ mod tests { { let v: Vec = Vec::new(); - let mut v: Box> = Box::new(v); + let v: Box> = Box::new(v); + let mut v: Box> = v; v.push(Droppable::new()).ok().unwrap(); v.push(Droppable::new()).ok().unwrap(); assert_eq!(Droppable::count(), 2); @@ -2037,7 +1414,8 @@ mod tests { { let v: Vec = Vec::new(); - let mut v: Box> = Box::new(v); + let v: Box> = Box::new(v); + let mut v: Box> = v; v.push(Droppable::new()).ok().unwrap(); v.push(Droppable::new()).ok().unwrap(); assert_eq!(Droppable::count(), 2); From 400732b1b12295a7764d95865eee57836d1e7ae1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 28 Jun 2024 03:31:24 +0200 Subject: [PATCH 2/4] vec: optimize for size a bit by preventing monomorphizing extend_from_slice. --- src/vec.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 2297087fbb..0378fc608b 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -341,17 +341,27 @@ impl VecInner { where T: Clone, { - if self.len + other.len() > self.capacity() { - // won't fit in the `Vec`; don't modify anything and return an error - Err(()) - } else { - for elem in other { - unsafe { - self.push_unchecked(elem.clone()); + pub fn extend_from_slice_inner( + len: &mut usize, + buf: &mut [MaybeUninit], + other: &[T], + ) -> Result<(), ()> + where + T: Clone, + { + if *len + other.len() > buf.len() { + // won't fit in the `Vec`; don't modify anything and return an error + Err(()) + } else { + for elem in other { + unsafe { *buf.get_unchecked_mut(*len) = MaybeUninit::new(elem.clone()) } + *len += 1; } + Ok(()) } - Ok(()) } + + extend_from_slice_inner(&mut self.len, self.buffer.borrow_mut(), other) } /// Removes the last element from a vector and returns it, or `None` if it's empty From 1a08c7ac27634e5d405acaa2f35bd31e746c96da Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 29 Jun 2024 00:56:00 +0200 Subject: [PATCH 3/4] vec: generalize defmt, ufmt, ser impls to cover VecView. --- src/defmt.rs | 4 ++-- src/ser.rs | 6 +++--- src/ufmt.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/defmt.rs b/src/defmt.rs index 7caa999205..c50963c007 100644 --- a/src/defmt.rs +++ b/src/defmt.rs @@ -1,9 +1,9 @@ //! Defmt implementations for heapless types -use crate::Vec; +use crate::{storage::Storage, vec::VecInner}; use defmt::Formatter; -impl defmt::Format for Vec +impl defmt::Format for VecInner where T: defmt::Format, { diff --git a/src/ser.rs b/src/ser.rs index f929ba8b12..052313195f 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,8 +1,8 @@ use core::hash::{BuildHasher, Hash}; use crate::{ - binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, IndexMap, IndexSet, LinearMap, String, - Vec, + binary_heap::Kind as BinaryHeapKind, storage::Storage, vec::VecInner, BinaryHeap, Deque, + IndexMap, IndexSet, LinearMap, String, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; @@ -42,7 +42,7 @@ where } } -impl Serialize for Vec +impl Serialize for VecInner where T: Serialize, { diff --git a/src/ufmt.rs b/src/ufmt.rs index 30da99acd4..fd0b276c40 100644 --- a/src/ufmt.rs +++ b/src/ufmt.rs @@ -1,4 +1,4 @@ -use crate::{string::String, vec::Vec}; +use crate::{storage::Storage, string::String, vec::VecInner}; use ufmt_write::uWrite; impl uWrite for String { @@ -8,7 +8,7 @@ impl uWrite for String { } } -impl uWrite for Vec { +impl uWrite for VecInner { type Error = (); fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.extend_from_slice(s.as_bytes()) @@ -17,7 +17,7 @@ impl uWrite for Vec { #[cfg(test)] mod tests { - use super::*; + use crate::{String, Vec}; use ufmt::{derive::uDebug, uwrite}; From bd030359e9e48917767cd29de4ae238dfe26b85b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 29 Jun 2024 01:09:55 +0200 Subject: [PATCH 4/4] storage: expand docs for trait with an example of where it's used. --- src/storage.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/storage.rs b/src/storage.rs index 6d19aed511..b4e9269cef 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -13,7 +13,15 @@ pub(crate) trait SealedStorage { /// - [`OwnedStorage`]: stores the data in an array `[T; N]` whose size is known at compile time. /// - [`ViewStorage`]: stores the data in an unsized `[T]`. /// -/// This allows containers to be generic over either sized or unsized storage. +/// This allows containers to be generic over either sized or unsized storage. For example, +/// the [`vec`](crate::vec) module contains a [`VecInner`](crate::vec::VecInner) struct +/// that's generic on [`Storage`], and two type aliases for convenience: +/// +/// - [`Vec`](crate::vec::Vec) = `VecInner>` +/// - [`VecView`](crate::vec::VecView) = `VecInner` +/// +/// `Vec` can be unsized into `VecView`, either by unsizing coercions such as `&mut Vec -> &mut VecView` or +/// `Box -> Box`, or explicitly with [`.as_view()`](crate::vec::Vec::as_view) or [`.as_mut_view()`](crate::vec::Vec::as_mut_view). /// /// This trait is sealed, so you cannot implement it for your own types. You can only use /// the implementations provided by this crate.