From 932576d06e4d31160551d9bd43b4dd7acccfba46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 15 Dec 2023 17:00:31 +0100 Subject: [PATCH 01/19] Implement https://github.com/rust-embedded/heapless/pull/424 but with the additional `impl Unsize for Vec` --- src/lib.rs | 2 +- src/vec.rs | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 969 insertions(+), 37 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 82a358e86b..365abc3249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,7 +88,7 @@ pub use indexmap::{ pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter}; pub use linear_map::LinearMap; pub use string::String; -pub use vec::Vec; +pub use vec::{Vec, VecView}; #[macro_use] #[cfg(test)] diff --git a/src/vec.rs b/src/vec.rs index 20da22e092..2f72127f30 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -7,6 +7,34 @@ use core::{ ops, ptr, slice, }; +/// Workaround forbidden specialization of Drop +pub trait VecDrop { + fn drop_with_len(&mut self, len: usize); +} + +impl VecDrop for [MaybeUninit] { + fn drop_with_len(&mut self, _len: usize) { + // Case of a view, drop does nothing + } +} + +impl VecDrop for [MaybeUninit; N] { + fn drop_with_len(&mut self, len: usize) { + // NOTE(unsafe) avoid bound checks in the slicing operation + // &mut buffer[..self.len] + let mut_slice = unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T, len) }; + // We drop each element used in the vector by turning into a `&mut [T]`. + unsafe { + ptr::drop_in_place(mut_slice); + } + } +} + +pub struct VecInner { + len: usize, + buffer: B, +} + /// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). /// /// # Examples @@ -35,14 +63,706 @@ use core::{ /// } /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` -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, +pub type Vec = VecInner<[MaybeUninit; N]>; +/// TODO: doc +pub type VecView = VecInner<[MaybeUninit]>; + +impl VecView { + /// Returns a raw pointer to the vector’s buffer. + pub fn as_ptr(&self) -> *const T { + self.buffer.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 + } + + /// 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]); + /// ``` + 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) } + } + + /// 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(); + /// buffer[0] = 9; + /// assert_eq!(buffer.as_slice(), &[9, 2, 3, 5, 8]); + /// ``` + 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) } + } + + /// Returns the maximum number of elements the vector can hold. + pub const fn capacity(&self) -> usize { + self.buffer.len() + } + + /// Clears the vector, removing all values. + pub fn clear(&mut self) { + self.truncate(0); + } + + /// Extends the vec from an iterator. + /// + /// # Panic + /// + /// Panics if the vec cannot hold all elements of the iterator. + pub fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for elem in iter { + self.push(elem).ok().unwrap() + } + } + + /// 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)] + pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> + 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()); + } + } + Ok(()) + } + } + + /// Removes the last element from a vector and returns it, or `None` if it's empty + pub fn pop(&mut self) -> Option { + if self.len != 0 { + Some(unsafe { self.pop_unchecked() }) + } else { + None + } + } + + /// Appends an `item` to the back of the collection + /// + /// Returns back the `item` if the vector is full + pub fn push(&mut self, item: T) -> Result<(), T> { + if self.len < self.capacity() { + unsafe { self.push_unchecked(item) } + Ok(()) + } else { + Err(item) + } + } + + /// Removes the last element from a vector and returns it + /// + /// # Safety + /// + /// This assumes the vec to have at least one element. + pub unsafe fn pop_unchecked(&mut self) -> T { + debug_assert!(!self.is_empty()); + + self.len -= 1; + self.buffer.get_unchecked_mut(self.len).as_ptr().read() + } + + /// Appends an `item` to the back of the collection + /// + /// # Safety + /// + /// This assumes the vec is not full. + pub unsafe fn push_unchecked(&mut self, item: T) { + // NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We + // 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.len += 1; + } + + /// Shortens the vector, keeping the first `len` elements and dropping the rest. + pub fn truncate(&mut self, len: usize) { + // This is safe because: + // + // * the slice passed to `drop_in_place` is valid; the `len > self.len` + // case avoids creating an invalid slice, and + // * the `len` of the vector is shrunk before calling `drop_in_place`, + // such that no value will be dropped twice in case `drop_in_place` + // were to panic once (if it panics twice, the program aborts). + unsafe { + // Note: It's intentional that this is `>` and not `>=`. + // Changing it to `>=` has negative performance + // implications in some cases. See rust-lang/rust#78884 for more. + if len > self.len { + return; + } + let remaining_len = self.len - len; + let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); + self.len = len; + ptr::drop_in_place(s); + } + } + + /// 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)] + pub fn resize(&mut self, new_len: usize, value: T) -> Result<(), ()> + where + T: Clone, + { + if new_len > self.capacity() { + return Err(()); + } + + if new_len > self.len { + while self.len < new_len { + self.push(value.clone()).ok(); + } + } else { + self.truncate(new_len); + } + + Ok(()) + } + + /// 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)] + pub fn resize_default(&mut self, new_len: usize) -> Result<(), ()> + where + T: Clone + Default, + { + self.resize(new_len, T::default()) + } + + /// 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; + ///// use heapless::consts::*; + /// + /// 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"]); + /// ``` + pub fn swap_remove(&mut self, index: usize) -> T { + assert!(index < self.len); + unsafe { self.swap_remove_unchecked(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"]); + /// ``` + pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T { + let length = self.len(); + debug_assert!(index < length); + let value = ptr::read(self.as_ptr().add(index)); + let base_ptr = self.as_mut_ptr(); + ptr::copy(base_ptr.add(length - 1), base_ptr.add(index), 1); + self.len -= 1; + value + } + + /// 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]); + /// ``` + pub fn insert(&mut self, index: usize, element: T) -> Result<(), T> { + let len = self.len(); + if index > len { + panic!( + "insertion index (is {}) should be <= len (is {})", + index, len + ); + } + + // check there's space for the new element + if self.is_full() { + return Err(element); + } + + unsafe { + // infallible + // The spot to put the new value + { + let p = self.as_mut_ptr().add(index); + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + // Write it in, overwriting the first copy of the `index`th + // element. + ptr::write(p, element); + } + self.set_len(len + 1); + } + + Ok(()) + } + + /// 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]); + /// ``` + pub fn remove(&mut self, index: usize) -> T { + let len = self.len(); + if index >= len { + panic!("removal index (is {}) should be < len (is {})", index, len); + } + unsafe { + // infallible + let ret; + { + // the place we are taking from. + let ptr = self.as_mut_ptr().add(index); + // copy it out, unsafely having a copy of the value on + // the stack and in the vector at the same time. + ret = ptr::read(ptr); + + // Shift everything down to fill in that spot. + ptr::copy(ptr.offset(1), ptr, len - index - 1); + } + self.set_len(len - 1); + ret + } + } + + /// 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]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.retain_mut(|elem| f(elem)); + } + + /// 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]); + /// ``` + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let original_len = self.len(); + // Avoid double drop if the drop guard is not executed, + // since we may make some holes during the process. + unsafe { self.set_len(0) }; + + // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] + // |<- processed len ->| ^- next to check + // |<- deleted cnt ->| + // |<- original_len ->| + // Kept: Elements which predicate returns true on. + // Hole: Moved or dropped element slot. + // Unchecked: Unchecked valid elements. + // + // 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, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, T> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + // SAFETY: Trailing unchecked items must be valid since we never touch them. + 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, + ); + } + } + // SAFETY: After filling holes, all items are in contiguous memory. + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); + } + } + } + + let mut g = BackshiftOnDrop { + v: self, + processed_len: 0, + deleted_cnt: 0, + original_len, + }; + + fn process_loop( + original_len: usize, + f: &mut F, + g: &mut BackshiftOnDrop<'_, T>, + ) where + F: FnMut(&mut T) -> bool, + { + while g.processed_len != original_len { + let p = g.v.as_mut_ptr(); + // SAFETY: Unchecked element must be valid. + let cur = unsafe { &mut *p.add(g.processed_len) }; + if !f(cur) { + // Advance early to avoid double drop if `drop_in_place` panicked. + g.processed_len += 1; + g.deleted_cnt += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + // We already advanced the counter. + if DELETED { + continue; + } else { + break; + } + } + if DELETED { + // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. + // We use copy for move, and never touch this element again. + unsafe { + let hole_slot = p.add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; + } + } + + // Stage 1: Nothing was deleted. + process_loop::(original_len, &mut f, &mut g); - buffer: [MaybeUninit; N], + // Stage 2: Some elements were deleted. + process_loop::(original_len, &mut f, &mut g); + + // All item are processed. This can be optimized to `set_len` by LLVM. + drop(g); + } } impl Vec { @@ -146,14 +866,12 @@ impl Vec { new } - /// Returns a raw pointer to the vector’s buffer. - pub fn as_ptr(&self) -> *const T { - self.buffer.as_ptr() as *const T + pub const fn as_view(&self) -> &VecView { + self } - /// 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 + pub fn as_mut_view(&mut self) -> &mut VecView { + self } /// Extracts a slice containing the entire vector. @@ -168,9 +886,7 @@ impl Vec { /// 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) } + self.as_view().as_slice() } /// Returns the contents of the vector as an array of length `M` if the length @@ -212,9 +928,7 @@ impl Vec { /// assert_eq!(buffer.as_slice(), &[9, 2, 3, 5, 8]); /// ``` 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) } + self.as_mut_view().as_mut_slice() } /// Returns the maximum number of elements the vector can hold. @@ -224,7 +938,7 @@ impl Vec { /// Clears the vector, removing all values. pub fn clear(&mut self) { - self.truncate(0); + self.as_mut_view().clear() } /// Extends the vec from an iterator. @@ -236,9 +950,7 @@ impl Vec { where I: IntoIterator, { - for elem in iter { - self.push(elem).ok().unwrap() - } + self.as_mut_view().extend(iter) } /// Clones and appends all elements in a slice to the `Vec`. @@ -907,7 +1619,7 @@ impl Default for Vec { } } -impl fmt::Debug for Vec +impl fmt::Debug for VecView where T: fmt::Debug, { @@ -916,6 +1628,15 @@ where } } +impl fmt::Debug for Vec +where + T: fmt::Debug, +{ + 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()) { @@ -925,11 +1646,11 @@ impl fmt::Write 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 { - ptr::drop_in_place(self.as_mut_slice()); +impl fmt::Write for VecView { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.extend_from_slice(s.as_bytes()) { + Ok(()) => Ok(()), + Err(_) => Err(fmt::Error), } } } @@ -940,6 +1661,12 @@ impl From<[T; M]> for Vec { } } +impl Drop for VecInner { + fn drop(&mut self) { + self.buffer.drop_with_len(self.len) + } +} + impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { type Error = (); @@ -948,7 +1675,7 @@ impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec { } } -impl Extend for Vec { +impl Extend for VecView { fn extend(&mut self, iter: I) where I: IntoIterator, @@ -957,7 +1684,28 @@ impl Extend for Vec { } } +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 where T: 'a + Copy, { @@ -970,6 +1718,15 @@ 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 where T: core::hash::Hash, { @@ -982,6 +1739,15 @@ 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 { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter() } @@ -991,6 +1757,15 @@ 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 { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter_mut() } @@ -1076,12 +1851,49 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { + self.as_view().eq(other.as_view()) + } +} + +impl PartialEq> for VecView +where + A: PartialEq, +{ + fn eq(&self, other: &Vec) -> bool { + self.eq(other.as_view()) + } +} + +impl PartialEq> for Vec +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { + self.as_view().eq(other) + } +} + +impl PartialEq> for VecView +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { <[A]>::eq(self, &**other) } } // Vec == [B] impl PartialEq<[B]> for Vec +where + A: PartialEq, +{ + fn eq(&self, other: &[B]) -> bool { + self.as_view().eq(other) + } +} + +// VecView == [B] +impl PartialEq<[B]> for VecView where A: PartialEq, { @@ -1096,6 +1908,16 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { + other.as_view().eq(self) + } +} + +// [B] == VecView +impl PartialEq> for [B] +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { <[A]>::eq(other, self) } } @@ -1106,7 +1928,17 @@ where A: PartialEq, { fn eq(&self, other: &&[B]) -> bool { - <[A]>::eq(self, &other[..]) + self.as_view().eq(other) + } +} + +// VecView == &[B] +impl PartialEq<&[B]> for VecView +where + A: PartialEq, +{ + fn eq(&self, other: &&[B]) -> bool { + <[A]>::eq(self, *other) } } @@ -1116,12 +1948,32 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + other.as_view().eq(self) + } +} + +// &[B] == VecView +impl PartialEq> for &[B] +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { + <[A]>::eq(other, *self) } } // Vec == &mut [B] impl PartialEq<&mut [B]> for Vec +where + A: PartialEq, +{ + fn eq(&self, other: &&mut [B]) -> bool { + self.as_view().eq(other) + } +} + +// VecView == &mut [B] +impl PartialEq<&mut [B]> for VecView where A: PartialEq, { @@ -1136,6 +1988,16 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { + other.as_view().eq(self) + } +} + +// &mut [B] == VecView +impl PartialEq> for &mut [B] +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { <[A]>::eq(other, &self[..]) } } @@ -1147,7 +2009,18 @@ where A: PartialEq, { fn eq(&self, other: &[B; M]) -> bool { - <[A]>::eq(self, &other[..]) + self.as_view().eq(other) + } +} + +// VecView == [B; M] +// Equality does not require equal capacity +impl PartialEq<[B; M]> for VecView +where + A: PartialEq, +{ + fn eq(&self, other: &[B; M]) -> bool { + <[A]>::eq(self, other) } } @@ -1158,7 +2031,18 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + other.as_view().eq(self) + } +} + +// [B; M] == VecView +// Equality does not require equal capacity +impl PartialEq> for [B; M] +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { + <[A]>::eq(other, self) } } @@ -1169,7 +2053,18 @@ where A: PartialEq, { fn eq(&self, other: &&[B; M]) -> bool { - <[A]>::eq(self, &other[..]) + self.as_view().eq(other) + } +} + +// VecView == &[B; M] +// Equality does not require equal capacity +impl PartialEq<&[B; M]> for VecView +where + A: PartialEq, +{ + fn eq(&self, other: &&[B; M]) -> bool { + <[A]>::eq(self, *other) } } @@ -1180,18 +2075,41 @@ where A: PartialEq, { fn eq(&self, other: &Vec) -> bool { - <[A]>::eq(other, &self[..]) + other.as_view().eq(self) + } +} + +// &[B; M] == VecView +// Equality does not require equal capacity +impl PartialEq> for &[B; M] +where + A: PartialEq, +{ + fn eq(&self, other: &VecView) -> bool { + <[A]>::eq(other, *self) } } // Implements Eq if underlying data is Eq impl Eq for Vec where T: Eq {} +// Not sure about this one? Should two distinct capacities really be Eq? +// Anyways it derefs to &[u8] which implements Eq so I suppose it should +impl Eq for VecView where T: Eq {} impl PartialOrd> for Vec where T: PartialOrd, { fn partial_cmp(&self, other: &Vec) -> Option { + self.as_view().partial_cmp(other.as_view()) + } +} + +impl PartialOrd> for VecView +where + T: PartialOrd, +{ + fn partial_cmp(&self, other: &VecView) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } @@ -1220,6 +2138,20 @@ impl ops::DerefMut for Vec { } } +impl ops::Deref for VecView { + type Target = [T]; + + fn deref(&self) -> &[T] { + self.as_slice() + } +} + +impl ops::DerefMut for VecView { + fn deref_mut(&mut self) -> &mut [T] { + self.as_mut_slice() + } +} + impl AsRef> for Vec { #[inline] fn as_ref(&self) -> &Self { From 535921945da352f731d743dcc57c38912203b26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Dec 2023 13:29:46 +0100 Subject: [PATCH 02/19] Fix documentation issue --- src/lib.rs | 3 +++ src/vec.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 365abc3249..de9ef27d13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,9 @@ pub use indexmap::{ pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter}; pub use linear_map::LinearMap; pub use string::String; +#[cfg(doc)] +#[doc(hidden)] +pub use vec::VecInner as _; pub use vec::{Vec, VecView}; #[macro_use] diff --git a/src/vec.rs b/src/vec.rs index 2f72127f30..1445ddb38b 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -30,6 +30,7 @@ impl VecDrop for [MaybeUninit; N] { } } +///
This is private API and should not be used
pub struct VecInner { len: usize, buffer: B, @@ -866,10 +867,12 @@ impl Vec { new } + /// Get a reference to the Vec, erasing the `N` const-generic pub const fn as_view(&self) -> &VecView { self } + /// Get a `mut` reference to the Vec, erasing the `N` const-generic pub fn as_mut_view(&mut self) -> &mut VecView { self } From 805037be0d775f0f3eae8e9e7fe6df3d291fcaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Dec 2023 13:51:24 +0100 Subject: [PATCH 03/19] Add missing documentation --- src/vec.rs | 108 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 43 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 1445ddb38b..f586d84da7 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -65,7 +65,27 @@ pub struct VecInner { /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` pub type Vec = VecInner<[MaybeUninit; N]>; -/// TODO: doc +/// A Vec with dynamic capacity +/// +/// [`Vec`]() coerces to `VecView`. `VecView` is !Sized, meaning that it can only ever be used through pointer +/// +/// Unlike [`Vec`](), `VecView` does not have an `N` const-generic parameter. +/// This has the ergonomic advantages of making it possible to use functions without needing to know at +/// compile-time the size of the buffers used, for example for use in `dyn` traits. +/// +/// `VecView` is to `Vec` what `[T]` is to `[T; N]` +/// +/// ```rust +/// use heapless::{Vec, VecView}; +/// +/// let mut vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); +/// let view: &VecView<_> = &vec; +/// assert_eq!(view, &[1, 2, 3, 4]); +/// +/// let mut_view: &mut VecView<_> = &mut vec; +/// mut_view.push(5); +/// assert_eq!(vec, [1, 2, 3, 4, 5]); +/// ``` pub type VecView = VecInner<[MaybeUninit]>; impl VecView { @@ -86,8 +106,8 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; - /// let buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); + /// use heapless::{Vec, VecView}; + /// let buffer: &VecView = &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] { @@ -103,9 +123,10 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; - /// let mut buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); - /// buffer[0] = 9; + /// use heapless::{Vec, VecView}; + /// let mut buffer: &mut VecView = &mut 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]); /// ``` pub fn as_mut_slice(&mut self) -> &mut [T] { @@ -146,9 +167,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut vec = Vec::::new(); + /// let vec: &mut VecView = &mut Vec::::new(); /// vec.push(1).unwrap(); /// vec.extend_from_slice(&[2, 3, 4]).unwrap(); /// assert_eq!(*vec, [1, 2, 3, 4]); @@ -310,7 +331,7 @@ impl VecView { /// /// ```no_run /// # #![allow(dead_code)] - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// /// # // This is just a minimal skeleton for the doc example; /// # // don't use this as a starting point for a real library. @@ -327,6 +348,7 @@ 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. @@ -334,10 +356,10 @@ impl VecView { /// // which makes `set_len` safe to call. /// unsafe { /// // Make the FFI call... - /// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length); + /// let r = deflateGetDictionary(self.strm, dict_view.as_mut_ptr(), &mut dict_length); /// if r == Z_OK { /// // ...and update the length to what was initialized. - /// dict.set_len(dict_length); + /// dict_view.set_len(dict_length); /// Some(dict) /// } else { /// None @@ -352,7 +374,7 @@ impl VecView { /// /// ``` /// use core::iter::FromIterator; - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// /// let mut vec = Vec::, 3>::from_iter( /// [ @@ -367,7 +389,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.set_len(0); + /// vec.as_mut_view().set_len(0); /// } /// ``` /// @@ -392,20 +414,19 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; - ///// use heapless::consts::*; + /// use heapless::{Vec, VecView}; /// - /// let mut v: Vec<_, 8> = Vec::new(); + /// let v: &mut VecView<_> = &mut Vec::<_, 8>::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); @@ -425,19 +446,19 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut v: Vec<_, 8> = Vec::new(); + /// let mut v: &mut VecView<_> = &mut Vec::<_, 8>::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(); @@ -468,9 +489,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); + /// let v: &VecView<_> = &Vec::<_, 8>::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); @@ -491,9 +512,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let v: Vec<_, 8> = Vec::from_slice(b"abc").unwrap(); + /// let v: &VecView<_> = &Vec::<_, 8>::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); @@ -519,13 +540,13 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); + /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::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(); @@ -578,11 +599,11 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut v: Vec<_, 8> = Vec::from_slice(&[1, 2, 3]).unwrap(); + /// let mut v: &mut VecView<_> = &mut Vec::<_, 8>::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(); @@ -616,24 +637,24 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::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; + /// use heapless::{Vec, VecView}; /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4, 5]).unwrap(); + /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::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 @@ -651,9 +672,9 @@ impl VecView { /// # Examples /// /// ``` - /// use heapless::Vec; + /// use heapless::{Vec, VecView}; /// - /// let mut vec: Vec<_, 8> = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); + /// let mut vec: &mut VecView<_> = &mut Vec::<_, 8>::from_slice(&[1, 2, 3, 4]).unwrap(); /// vec.retain_mut(|x| { /// if *x <= 3 { /// *x += 1; @@ -662,7 +683,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 @@ -927,7 +948,8 @@ impl Vec { /// ``` /// use heapless::Vec; /// let mut buffer: Vec = Vec::from_slice(&[1, 2, 3, 5, 8]).unwrap(); - /// buffer[0] = 9; + /// let buffer_slice = buffer.as_mut_slice(); + /// buffer_slice[0] = 9; /// assert_eq!(buffer.as_slice(), &[9, 2, 3, 5, 8]); /// ``` pub fn as_mut_slice(&mut self) -> &mut [T] { From 0af5f171a3368bea1a027567acc59cf94facf1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Dec 2023 14:13:45 +0100 Subject: [PATCH 04/19] Forward missing implementations to the view --- src/vec.rs | 238 ++++------------------------------------------------- 1 file changed, 16 insertions(+), 222 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index f586d84da7..993f1521b3 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -998,38 +998,19 @@ impl Vec { 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()); - } - } - Ok(()) - } + self.as_mut_view().extend_from_slice(other) } /// Removes the last element from a vector and returns it, or `None` if it's empty pub fn pop(&mut self) -> Option { - if self.len != 0 { - Some(unsafe { self.pop_unchecked() }) - } else { - None - } + self.as_mut_view().pop() } /// Appends an `item` to the back of the collection /// /// Returns back the `item` if the vector is full pub fn push(&mut self, item: T) -> Result<(), T> { - if self.len < self.capacity() { - unsafe { self.push_unchecked(item) } - Ok(()) - } else { - Err(item) - } + self.as_mut_view().push(item) } /// Removes the last element from a vector and returns it @@ -1038,10 +1019,7 @@ impl Vec { /// /// This assumes the vec to have at least one element. pub unsafe fn pop_unchecked(&mut self) -> T { - debug_assert!(!self.is_empty()); - - self.len -= 1; - self.buffer.get_unchecked_mut(self.len).as_ptr().read() + self.as_mut_view().pop_unchecked() } /// Appends an `item` to the back of the collection @@ -1050,36 +1028,12 @@ impl Vec { /// /// This assumes the vec is not full. pub unsafe fn push_unchecked(&mut self, item: T) { - // NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We - // 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.len += 1; + self.as_mut_view().push_unchecked(item) } /// Shortens the vector, keeping the first `len` elements and dropping the rest. pub fn truncate(&mut self, len: usize) { - // This is safe because: - // - // * the slice passed to `drop_in_place` is valid; the `len > self.len` - // case avoids creating an invalid slice, and - // * the `len` of the vector is shrunk before calling `drop_in_place`, - // such that no value will be dropped twice in case `drop_in_place` - // were to panic once (if it panics twice, the program aborts). - unsafe { - // Note: It's intentional that this is `>` and not `>=`. - // Changing it to `>=` has negative performance - // implications in some cases. See rust-lang/rust#78884 for more. - if len > self.len { - return; - } - let remaining_len = self.len - len; - let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); - self.len = len; - ptr::drop_in_place(s); - } + self.as_mut_view().truncate(len) } /// Resizes the Vec in-place so that len is equal to new_len. @@ -1094,19 +1048,7 @@ impl Vec { where T: Clone, { - if new_len > self.capacity() { - return Err(()); - } - - if new_len > self.len { - while self.len < new_len { - self.push(value.clone()).ok(); - } - } else { - self.truncate(new_len); - } - - Ok(()) + self.as_mut_view().resize(new_len, value) } /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. @@ -1121,7 +1063,7 @@ impl Vec { where T: Clone + Default, { - self.resize(new_len, T::default()) + self.as_mut_view().resize_default(new_len) } /// Forces the length of the vector to `new_len`. @@ -1248,8 +1190,7 @@ impl Vec { /// assert_eq!(&*v, ["baz", "qux"]); /// ``` pub fn swap_remove(&mut self, index: usize) -> T { - assert!(index < self.len); - unsafe { self.swap_remove_unchecked(index) } + self.as_mut_view().swap_remove(index) } /// Removes an element from the vector and returns it. @@ -1280,13 +1221,7 @@ impl Vec { /// assert_eq!(&*v, ["baz", "qux"]); /// ``` pub unsafe fn swap_remove_unchecked(&mut self, index: usize) -> T { - let length = self.len(); - debug_assert!(index < length); - let value = ptr::read(self.as_ptr().add(index)); - let base_ptr = self.as_mut_ptr(); - ptr::copy(base_ptr.add(length - 1), base_ptr.add(index), 1); - self.len -= 1; - value + self.as_mut_view().swap_remove_unchecked(index) } /// Returns true if the vec is full @@ -1368,35 +1303,7 @@ impl Vec { /// assert_eq!(vec, [1, 4, 2, 3, 5]); /// ``` pub fn insert(&mut self, index: usize, element: T) -> Result<(), T> { - let len = self.len(); - if index > len { - panic!( - "insertion index (is {}) should be <= len (is {})", - index, len - ); - } - - // check there's space for the new element - if self.is_full() { - return Err(element); - } - - unsafe { - // infallible - // The spot to put the new value - { - let p = self.as_mut_ptr().add(index); - // Shift everything over to make space. (Duplicating the - // `index`th element into two consecutive places.) - ptr::copy(p, p.offset(1), len - index); - // Write it in, overwriting the first copy of the `index`th - // element. - ptr::write(p, element); - } - self.set_len(len + 1); - } - - Ok(()) + self.as_mut_view().insert(index, element) } /// Removes and returns the element at position `index` within the vector, @@ -1425,26 +1332,7 @@ impl Vec { /// assert_eq!(v, [1, 3]); /// ``` pub fn remove(&mut self, index: usize) -> T { - let len = self.len(); - if index >= len { - panic!("removal index (is {}) should be < len (is {})", index, len); - } - unsafe { - // infallible - let ret; - { - // the place we are taking from. - let ptr = self.as_mut_ptr().add(index); - // copy it out, unsafely having a copy of the value on - // the stack and in the vector at the same time. - ret = ptr::read(ptr); - - // Shift everything down to fill in that spot. - ptr::copy(ptr.offset(1), ptr, len - index - 1); - } - self.set_len(len - 1); - ret - } + self.as_mut_view().remove(index) } /// Retains only the elements specified by the predicate. @@ -1475,11 +1363,11 @@ impl Vec { /// vec.retain(|_| *iter.next().unwrap()); /// assert_eq!(vec, [2, 3, 5]); /// ``` - pub fn retain(&mut self, mut f: F) + pub fn retain(&mut self, f: F) where F: FnMut(&T) -> bool, { - self.retain_mut(|elem| f(elem)); + self.as_mut_view().retain(f) } /// Retains only the elements specified by the predicate, passing a mutable reference to it. @@ -1504,105 +1392,11 @@ impl Vec { /// }); /// assert_eq!(vec, [2, 3, 4]); /// ``` - pub fn retain_mut(&mut self, mut f: F) + pub fn retain_mut(&mut self, f: F) where F: FnMut(&mut T) -> bool, { - let original_len = self.len(); - // Avoid double drop if the drop guard is not executed, - // since we may make some holes during the process. - unsafe { self.set_len(0) }; - - // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] - // |<- processed len ->| ^- next to check - // |<- deleted cnt ->| - // |<- original_len ->| - // Kept: Elements which predicate returns true on. - // Hole: Moved or dropped element slot. - // Unchecked: Unchecked valid elements. - // - // 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, - processed_len: usize, - deleted_cnt: usize, - original_len: usize, - } - - impl Drop for BackshiftOnDrop<'_, T, N> { - fn drop(&mut self) { - if self.deleted_cnt > 0 { - // SAFETY: Trailing unchecked items must be valid since we never touch them. - 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, - ); - } - } - // SAFETY: After filling holes, all items are in contiguous memory. - unsafe { - self.v.set_len(self.original_len - self.deleted_cnt); - } - } - } - - let mut g = BackshiftOnDrop { - v: self, - processed_len: 0, - deleted_cnt: 0, - original_len, - }; - - fn process_loop( - original_len: usize, - f: &mut F, - g: &mut BackshiftOnDrop<'_, T, N>, - ) where - F: FnMut(&mut T) -> bool, - { - while g.processed_len != original_len { - let p = g.v.as_mut_ptr(); - // SAFETY: Unchecked element must be valid. - let cur = unsafe { &mut *p.add(g.processed_len) }; - if !f(cur) { - // Advance early to avoid double drop if `drop_in_place` panicked. - g.processed_len += 1; - g.deleted_cnt += 1; - // SAFETY: We never touch this element again after dropped. - unsafe { ptr::drop_in_place(cur) }; - // We already advanced the counter. - if DELETED { - continue; - } else { - break; - } - } - if DELETED { - // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. - // We use copy for move, and never touch this element again. - unsafe { - let hole_slot = p.add(g.processed_len - g.deleted_cnt); - ptr::copy_nonoverlapping(cur, hole_slot, 1); - } - } - g.processed_len += 1; - } - } - - // Stage 1: Nothing was deleted. - process_loop::(original_len, &mut f, &mut g); - - // Stage 2: Some elements were deleted. - process_loop::(original_len, &mut f, &mut g); - - // All item are processed. This can be optimized to `set_len` by LLVM. - drop(g); + self.as_mut_view().retain_mut(f) } /// Returns the remaining spare capacity of the vector as a slice of `MaybeUninit`. From add12d72a153a52df850b13e6e9b6203702a653f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 18 Dec 2023 12:06:40 +0100 Subject: [PATCH 05/19] Improve docs --- src/vec.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index 993f1521b3..89453943e2 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -64,10 +64,20 @@ pub struct VecInner { /// } /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` +/// +/// In some cases, the const-generic might be cumbersome. `Vec` can coerce into a [`VecView`][] to remove the need for the const-generic: +/// +/// ```rust +/// use heapless::{Vec, VecView}; +/// +/// let vec: Vec = Vec::from_slice(&[1, 2, 3, 4]).unwrap(); +/// let view: &VecView<_> = &vec; +/// ``` pub type Vec = VecInner<[MaybeUninit; N]>; + /// A Vec with dynamic capacity /// -/// [`Vec`]() coerces to `VecView`. `VecView` is !Sized, meaning that it can only ever be used through pointer +/// [`Vec`]() coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer /// /// Unlike [`Vec`](), `VecView` does not have an `N` const-generic parameter. /// This has the ergonomic advantages of making it possible to use functions without needing to know at @@ -889,11 +899,29 @@ impl Vec { } /// Get a reference to the Vec, erasing the `N` const-generic + /// + /// This can also be used 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; + /// ``` pub const fn as_view(&self) -> &VecView { self } /// Get a `mut` reference to the Vec, erasing the `N` const-generic + /// + /// This can also be used 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; + /// ``` pub fn as_mut_view(&mut self) -> &mut VecView { self } From de72f43eb3228a53bc197426762a1380c4971656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 18 Dec 2023 12:09:17 +0100 Subject: [PATCH 06/19] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a04a468db8..77a35644c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `Vec::spare_capacity_mut`. - Added `Extend` impls for `Deque`. - Added `Deque::make_contiguous`. +- Added `VecView`, the `!Sized` version of `Vec` ### Changed From 113c3cc568d1b3429180e8594059ac3ca7ddf10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 18 Dec 2023 14:33:01 +0100 Subject: [PATCH 07/19] Fix docs --- src/vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 89453943e2..868355aed6 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -65,7 +65,7 @@ pub struct VecInner { /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` /// -/// In some cases, the const-generic might be cumbersome. `Vec` can coerce into a [`VecView`][] to remove the need for the const-generic: +/// In some cases, the const-generic might be cumbersome. `Vec` can coerce into a [`VecView`](VecView) to remove the need for the const-generic: /// /// ```rust /// use heapless::{Vec, VecView}; @@ -77,9 +77,9 @@ pub type Vec = VecInner<[MaybeUninit; N]>; /// A Vec with dynamic capacity /// -/// [`Vec`]() coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer +/// [`Vec`](Vec) coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer /// -/// Unlike [`Vec`](), `VecView` does not have an `N` const-generic parameter. +/// Unlike [`Vec`](Vec), `VecView` does not have an `N` const-generic parameter. /// This has the ergonomic advantages of making it possible to use functions without needing to know at /// compile-time the size of the buffers used, for example for use in `dyn` traits. /// From 2fe9669b916d5aac12d3fda443aeefca5f64b7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 19 Dec 2023 15:39:29 +0100 Subject: [PATCH 08/19] Add link --- src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index 868355aed6..990830e0ac 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -75,7 +75,7 @@ pub struct VecInner { /// ``` pub type Vec = VecInner<[MaybeUninit; N]>; -/// A Vec with dynamic capacity +/// A [`Vec`](Vec) with dynamic capacity /// /// [`Vec`](Vec) coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer /// From af8cf129f6b90bba7af9ea19039d00dfbf1e91bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 19 Dec 2023 15:51:36 +0100 Subject: [PATCH 09/19] Fix cfail tests --- cfail/ui/not-send.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cfail/ui/not-send.stderr b/cfail/ui/not-send.stderr index 40645b7a6d..058e28e8f5 100644 --- a/cfail/ui/not-send.stderr +++ b/cfail/ui/not-send.stderr @@ -72,7 +72,7 @@ error[E0277]: `*const ()` cannot be sent between threads safely 22 | is_send::>(); | ^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely | - = help: within `heapless::Vec, 4>`, the trait `Send` is not implemented for `*const ()` + = help: within `heapless::vec::VecInner<[MaybeUninit>; 4]>`, the trait `Send` is not implemented for `*const ()` note: required because it appears within the type `PhantomData<*const ()>` --> $RUST/core/src/marker.rs note: required because it appears within the type `ManuallyDrop>` @@ -80,11 +80,11 @@ 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 `Vec, 4>` +note: required because it appears within the type `VecInner<[MaybeUninit>; 4]>` --> $HEAPLESS/src/vec.rs | - | pub struct Vec { - | ^^^ + | pub struct VecInner { + | ^^^^^^^^ note: required by a bound in `is_send` --> ui/not-send.rs:14:8 | From 15ba0a79a3f69c066c2d750d52991069d1f19d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 21 Dec 2023 10:58:35 +0100 Subject: [PATCH 10/19] Fix doc warnings --- src/vec.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 990830e0ac..855be84bdc 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -65,7 +65,7 @@ pub struct VecInner { /// assert_eq!(*vec, [7, 1, 2, 3]); /// ``` /// -/// In some cases, the const-generic might be cumbersome. `Vec` can coerce into a [`VecView`](VecView) to remove the need for the const-generic: +/// In some cases, the const-generic might be cumbersome. `Vec` can coerce into a [`VecView`] to remove the need for the const-generic: /// /// ```rust /// use heapless::{Vec, VecView}; @@ -75,11 +75,11 @@ pub struct VecInner { /// ``` pub type Vec = VecInner<[MaybeUninit; N]>; -/// A [`Vec`](Vec) with dynamic capacity +/// A [`Vec`] with dynamic capacity /// -/// [`Vec`](Vec) coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer +/// [`Vec`] coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer /// -/// Unlike [`Vec`](Vec), `VecView` does not have an `N` const-generic parameter. +/// Unlike [`Vec`], `VecView` does not have an `N` const-generic parameter. /// This has the ergonomic advantages of making it possible to use functions without needing to know at /// compile-time the size of the buffers used, for example for use in `dyn` traits. /// From 5cb9feacf89d5ac787984d543c7eda8dade4f621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 2 Jan 2024 09:19:56 +0100 Subject: [PATCH 11/19] Fix docs reference to removed module --- src/vec.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index 855be84bdc..4a6adf26a5 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1203,7 +1203,6 @@ impl Vec { /// /// ``` /// use heapless::Vec; - ///// use heapless::consts::*; /// /// let mut v: Vec<_, 8> = Vec::new(); /// v.push("foo").unwrap(); From b95e1d2dea3a7c33dd5758647face53b6a3fb231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sun, 21 Jan 2024 13:52:48 +0100 Subject: [PATCH 12/19] VecView: Add spare_capacity_mut --- src/vec.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index 4a6adf26a5..036a4381ac 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -795,6 +795,37 @@ impl VecView { // All item are processed. This can be optimized to `set_len` by LLVM. drop(g); } + + /// 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, VecView}; + /// + /// // 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(); + /// 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); + /// } + /// + /// assert_eq!(view, &[0, 1, 2]); + /// ``` + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buffer[self.len..] + } } impl Vec { @@ -1453,7 +1484,7 @@ impl Vec { /// assert_eq!(&v, &[0, 1, 2]); /// ``` pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { - &mut self.buffer[self.len..] + self.as_mut_view().spare_capacity_mut() } } From 2408e716389b2dd2fd39c5d2c644b595917ce8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 19:16:03 +0100 Subject: [PATCH 13/19] Make drop_with_len unsafe --- src/vec.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 036a4381ac..03d768a02e 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -9,17 +9,17 @@ use core::{ /// Workaround forbidden specialization of Drop pub trait VecDrop { - fn drop_with_len(&mut self, len: usize); + unsafe fn drop_with_len(&mut self, len: usize); } impl VecDrop for [MaybeUninit] { - fn drop_with_len(&mut self, _len: usize) { + unsafe fn drop_with_len(&mut self, _len: usize) { // Case of a view, drop does nothing } } impl VecDrop for [MaybeUninit; N] { - fn drop_with_len(&mut self, len: usize) { + unsafe fn drop_with_len(&mut self, len: usize) { // NOTE(unsafe) avoid bound checks in the slicing operation // &mut buffer[..self.len] let mut_slice = unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T, len) }; @@ -1540,7 +1540,7 @@ impl From<[T; M]> for Vec { impl Drop for VecInner { fn drop(&mut self) { - self.buffer.drop_with_len(self.len) + unsafe { self.buffer.drop_with_len(self.len) } } } From 71d857ad17b860ab37ab586f5bce681c574eb68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 20:25:38 +0100 Subject: [PATCH 14/19] Document uses of unsafe in VecDrop --- src/vec.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 03d768a02e..844e841056 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -9,6 +9,10 @@ use core::{ /// Workaround forbidden specialization of Drop pub trait VecDrop { + // SAFETY: drop_with_len will be called to call drop in place the first `len` elements of the buffer. + // Only the Owned buffer (`[MaybeUninit; N]`) must drop the items + // and the view (`[MaybeUninit]`) drops nothing. + // `drop_with_len `assumes that the buffer can contain `len` elements. unsafe fn drop_with_len(&mut self, len: usize); } @@ -21,12 +25,11 @@ impl VecDrop for [MaybeUninit] { impl VecDrop for [MaybeUninit; N] { unsafe fn drop_with_len(&mut self, len: usize) { // NOTE(unsafe) avoid bound checks in the slicing operation - // &mut buffer[..self.len] - let mut_slice = unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T, len) }; + // &mut buffer[..len] + // SAFETY: buffer[..len] must be valid to drop given the safety requirement of the trait definition. + let mut_slice = slice::from_raw_parts_mut(self.as_mut_ptr() as *mut T, len); // We drop each element used in the vector by turning into a `&mut [T]`. - unsafe { - ptr::drop_in_place(mut_slice); - } + ptr::drop_in_place(mut_slice); } } @@ -1540,6 +1543,7 @@ impl From<[T; M]> for Vec { impl Drop for VecInner { fn drop(&mut self) { + // SAFETY: the buffer contains initialized data for the range 0..self.len unsafe { self.buffer.drop_with_len(self.len) } } } From bc1853eeba244670be2127dd2103f0c79a7ea742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 20:30:14 +0100 Subject: [PATCH 15/19] Document rustdoc issue workaround --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index de9ef27d13..baaef35d96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,10 @@ 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 _; From 1c399dbdbf0af4aa17e2a5e96639529ef941fe53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 20:31:21 +0100 Subject: [PATCH 16/19] Remove comment questionnig Eq implementation --- src/vec.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 844e841056..67afb4fd51 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1973,8 +1973,6 @@ where // Implements Eq if underlying data is Eq impl Eq for Vec where T: Eq {} -// Not sure about this one? Should two distinct capacities really be Eq? -// Anyways it derefs to &[u8] which implements Eq so I suppose it should impl Eq for VecView where T: Eq {} impl PartialOrd> for Vec From 24fedd3b8cfa1cea44e741eb61485247a949b756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 20:33:27 +0100 Subject: [PATCH 17/19] Fix typos --- CHANGELOG.md | 2 +- src/vec.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77a35644c8..ff4ee28f26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `Vec::spare_capacity_mut`. - Added `Extend` impls for `Deque`. - Added `Deque::make_contiguous`. -- Added `VecView`, the `!Sized` version of `Vec` +- Added `VecView`, the `!Sized` version of `Vec`. ### Changed diff --git a/src/vec.rs b/src/vec.rs index 67afb4fd51..8621d4c674 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -80,13 +80,13 @@ pub type Vec = VecInner<[MaybeUninit; N]>; /// A [`Vec`] with dynamic capacity /// -/// [`Vec`] coerces to `VecView`. `VecView` is `!Sized`, meaning that it can only ever be used through pointer +/// [`Vec`] coerces to `VecView`. `VecView` is `!Sized`, meaning it can only ever be used by reference. /// /// Unlike [`Vec`], `VecView` does not have an `N` const-generic parameter. -/// This has the ergonomic advantages of making it possible to use functions without needing to know at +/// This has the ergonomic advantage of making it possible to use functions without needing to know at /// compile-time the size of the buffers used, for example for use in `dyn` traits. /// -/// `VecView` is to `Vec` what `[T]` is to `[T; N]` +/// `VecView` is to `Vec` what `[T]` is to `[T; N]`. /// /// ```rust /// use heapless::{Vec, VecView}; From 0010f40143f10ffde12758c28ab280cbcffc6d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 23 Jan 2024 22:30:20 +0100 Subject: [PATCH 18/19] Remove nonsense documentation line --- src/vec.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index 8621d4c674..7d3f0fd916 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -848,7 +848,6 @@ impl Vec { /// // allocate the vector in a static variable /// static mut X: Vec = Vec::new(); /// ``` - /// `Vec` `const` constructor; wrap the returned value in [`Vec`]. pub const fn new() -> Self { Self { len: 0, From cdfe3080556316e69c20d2a3dbac6be2b4f672da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 24 Jan 2024 09:48:40 +0100 Subject: [PATCH 19/19] Fix documentation of as_(mut_)view --- src/vec.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/vec.rs b/src/vec.rs index 7d3f0fd916..be7aaf30a9 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -931,29 +931,40 @@ impl Vec { new } - /// Get a reference to the Vec, erasing the `N` const-generic + /// Get a reference to the `Vec`, erasing the `N` const-generic. /// - /// This can also be used through type coerction, since `Vec` implements `Unsize>`: /// /// ```rust - /// use heapless::{Vec, VecView}; + /// # 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; + /// let view: &VecView = &vec; /// ``` pub const fn as_view(&self) -> &VecView { self } - /// Get a `mut` reference to the Vec, erasing the `N` const-generic - /// - /// This can also be used through type coerction, since `Vec` implements `Unsize>`: + /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. /// /// ```rust - /// use heapless::{Vec, VecView}; + /// # 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; + /// let view: &mut VecView = &mut vec; /// ``` pub fn as_mut_view(&mut self) -> &mut VecView { self