From 8378b2670882afe476b7726e14fba6c849b47ada Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Sun, 23 Aug 2026 19:10:42 +0200 Subject: [PATCH 01/15] feat: added rustfmt.toml --- rustfmt.toml | 4 + src/lib.rs | 266 ++++++++++++++++++++++++++++++--------------------- src/tests.rs | 35 +++---- 3 files changed, 181 insertions(+), 124 deletions(-) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..5171db1 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +wrap_comments = true +imports_granularity = "Preserve" +group_imports = "One" +format_code_in_doc_comments = true \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f7b1bba..576bcc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Small vectors in various sizes. These store a certain number of elements inline, and fall back -//! to the heap for larger allocations. This can be a useful optimization for improving cache -//! locality and reducing allocator traffic for workloads that fit within the inline buffer. +//! Small vectors in various sizes. These store a certain number of elements +//! inline, and fall back to the heap for larger allocations. This can be a +//! useful optimization for improving cache locality and reducing allocator +//! traffic for workloads that fit within the inline buffer. //! //! ## `no_std` support //! @@ -27,25 +28,27 @@ //! //! ### `serde` //! -//! When this optional dependency is enabled, `SmallVec` implements the `serde::Serialize` and -//! `serde::Deserialize` traits. +//! When this optional dependency is enabled, `SmallVec` implements the +//! `serde::Serialize` and `serde::Deserialize` traits. //! //! ### `specialization` //! -//! **This feature is unstable and requires a nightly build of the Rust toolchain.** +//! **This feature is unstable and requires a nightly build of the Rust +//! toolchain.** //! -//! When this feature is enabled, `SmallVec::from(slice)` has improved performance for slices -//! of `Copy` types. (Without this feature, you can use `SmallVec::from_slice` to get optimal -//! performance for `Copy` types.) +//! When this feature is enabled, `SmallVec::from(slice)` has improved +//! performance for slices of `Copy` types. (Without this feature, you can use +//! `SmallVec::from_slice` to get optimal performance for `Copy` types.) //! //! Tracking issue: [rust-lang/rust#31844](https://github.com/rust-lang/rust/issues/31844) //! //! ### `may_dangle` //! -//! **This feature is unstable and requires a nightly build of the Rust toolchain.** +//! **This feature is unstable and requires a nightly build of the Rust +//! toolchain.** //! -//! This feature makes the Rust compiler less strict about use of vectors that contain borrowed -//! references. For details, see the +//! This feature makes the Rust compiler less strict about use of vectors that +//! contain borrowed references. For details, see the //! [Rustonomicon](https://doc.rust-lang.org/1.42.0/nomicon/dropck.html#an-escape-hatch). //! //! Tracking issue: [rust-lang/rust#34761](https://github.com/rust-lang/rust/issues/34761) @@ -66,11 +69,12 @@ mod rawsmallvec; #[cfg(test)] mod tests; +use alloc::alloc::Layout; use alloc::boxed::Box; use alloc::vec; use alloc::vec::Vec; - -use alloc::alloc::Layout; +#[cfg(feature = "bytes")] +use bytes::{buf::UninitSlice, BufMut}; use core::borrow::Borrow; use core::borrow::BorrowMut; use core::fmt::Debug; @@ -83,11 +87,12 @@ use core::mem::MaybeUninit; use core::ptr::copy; use core::ptr::copy_nonoverlapping; use core::ptr::NonNull; - -#[cfg(feature = "bytes")] -use bytes::{buf::UninitSlice, BufMut}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; +#[cfg(feature = "internals")] +pub use rawsmallvec::RawSmallVec; +#[cfg(not(feature = "internals"))] +use rawsmallvec::RawSmallVec; #[cfg(feature = "serde")] use serde_core::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, @@ -96,11 +101,6 @@ use serde_core::{ #[cfg(feature = "std")] use std::io; -#[cfg(feature = "internals")] -pub use rawsmallvec::RawSmallVec; -#[cfg(not(feature = "internals"))] -use rawsmallvec::RawSmallVec; - /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum CollectionAllocErr { @@ -264,8 +264,8 @@ impl RawSmallVec { Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); // SAFETY: ptr was allocated with this allocator - // old_layout is the same as the layout used to allocate the previous memory block - // new_layout.size() is greater than zero + // old_layout is the same as the layout used to allocate the previous memory + // block new_layout.size() is greater than zero // does not overflow when rounded up to alignment. since it was constructed // with Layout::array let new_ptr = realloc(ptr as *mut u8, old_layout, new_layout.size()) as *mut T; @@ -276,17 +276,20 @@ impl RawSmallVec { } } -/// Vec guarantees that its length is always less than [`isize::MAX`] in *bytes*. +/// Vec guarantees that its length is always less than [`isize::MAX`] in +/// *bytes*. /// -/// For a non ZST, this means that the length is less than `isize::MAX` objects, which implies we -/// have at least one free bit we can use. We use the least significant bit for the tag. And store -/// the length in the `usize::BITS - 1` most significant bits. +/// For a non ZST, this means that the length is less than `isize::MAX` objects, +/// which implies we have at least one free bit we can use. We use the least +/// significant bit for the tag. And store the length in the `usize::BITS - 1` +/// most significant bits. /// /// For a ZST, we never use the heap, so we just store the length directly. #[repr(transparent)] struct TaggedLen(usize, PhantomData); -// Clone and Copy must be manually implemented because the generic interferes with the derive attribute implementations. +// Clone and Copy must be manually implemented because the generic interferes +// with the derive attribute implementations. impl Clone for TaggedLen { #[inline] fn clone(&self) -> Self { @@ -351,7 +354,8 @@ impl Default for SmallVec { } } -/// An iterator that removes the items from a `SmallVec` and yields them by value. +/// An iterator that removes the items from a `SmallVec` and yields them by +/// value. /// /// Returned from [`SmallVec::drain`][1]. /// @@ -375,8 +379,8 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { #[inline] fn next(&mut self) -> Option { - // SAFETY: we shrunk the length of the vector so it no longer owns these items, and we can - // take ownership of them. + // SAFETY: we shrunk the length of the vector so it no longer owns these items, + // and we can take ownership of them. self.iter .next() .map(|reference| unsafe { core::ptr::read(reference) }) @@ -438,8 +442,9 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { let mut vec = self.vec; if SmallVec::::IS_ZST { - // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. - // this can be achieved by manipulating the Vec length instead of moving values out from `iter`. + // ZSTs have no identity, so we don't need to move them around, we only need to + // drop the correct amount. this can be achieved by manipulating the + // Vec length instead of moving values out from `iter`. unsafe { let vec = vec.as_mut(); let old_len = vec.len(); @@ -450,7 +455,8 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { return; } - // ensure elements are moved back into their appropriate places, even when drop_in_place panics + // ensure elements are moved back into their appropriate places, even when + // drop_in_place panics let _guard = DropGuard(self); if drop_len == 0 { @@ -459,15 +465,16 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { // as_slice() must only be called when iter.len() is > 0 because // it also gets touched by vec::Splice which may turn it into a dangling pointer - // which would make it and the vec pointer point to different allocations which would - // lead to invalid pointer arithmetic below. + // which would make it and the vec pointer point to different allocations which + // would lead to invalid pointer arithmetic below. let drop_ptr = iter.as_slice().as_ptr(); unsafe { - // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place - // a pointer with mutable provenance is necessary. Therefore we must reconstruct - // it from the original vec but also avoid creating a &mut to the front since that could - // invalidate raw pointers to it which some unsafe code might rely on. + // drop_ptr comes from a slice::Iter which only gives us a &[T] but for + // drop_in_place a pointer with mutable provenance is necessary. + // Therefore we must reconstruct it from the original vec but also + // avoid creating a &mut to the front since that could invalidate + // raw pointers to it which some unsafe code might rely on. let vec_ptr = vec.as_mut().as_mut_ptr(); // May be replaced with the line below later, once this crate's MSRV is >= 1.87. //let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr); @@ -486,8 +493,9 @@ impl Drain<'_, T, N> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. - /// Fill that range as much as possible with new elements from the `replace_with` iterator. - /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) + /// Fill that range as much as possible with new elements from the + /// `replace_with` iterator. Returns `true` if we filled the entire + /// range. (`replace_with.next()` didn’t return `None`.) unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { let vec = unsafe { self.vec.as_mut() }; let range_start = vec.len(); @@ -532,7 +540,8 @@ impl Drain<'_, T, N> { } } -/// An iterator which uses a closure to determine if an element should be removed. +/// An iterator which uses a closure to determine if an element should be +/// removed. /// /// Returned from [`SmallVec::extract_if`][1]. /// @@ -544,7 +553,8 @@ where vec: &'a mut SmallVec, /// The index of the item that will be inspected by the next call to `next`. idx: usize, - /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`. + /// Elements at and beyond this point will be retained. Must be equal or + /// smaller than `old_len`. end: usize, /// The number of items that have been drained (removed) thus far. del: usize, @@ -665,9 +675,9 @@ impl Drop for Splice<'_, I, N> { self.drain.by_ref().for_each(drop); // At this point draining is done and the only remaining tasks are splicing // and moving things into the final place. - // Which means we can replace the slice::Iter with pointers that won't point to deallocated - // memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break - // the ptr.sub_ptr contract. + // Which means we can replace the slice::Iter with pointers that won't point to + // deallocated memory, so that Drain::drop is still allowed to call + // iter.len(), otherwise it would break the ptr.sub_ptr contract. self.drain.iter = [].iter(); unsafe { @@ -705,7 +715,8 @@ impl Drop for Splice<'_, I, N> { debug_assert_eq!(collected.len(), 0); } } - // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + // Let `Drain::drop` move the tail back if necessary and restore + // `vec.len`. } } @@ -726,8 +737,8 @@ pub struct IntoIter { _marker: PhantomData, } -// SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) an `IntoIter` -// is equivalent to sending (or sharing) a `SmallVec`. +// SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) +// an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. unsafe impl Send for IntoIter where T: Send {} unsafe impl Sync for IntoIter where T: Sync {} @@ -847,7 +858,8 @@ impl SmallVec { } // Although we create a new buffer, since S and N are known at compile time, - // even with `-C opt-level=1`, it gets optimized as best as it could be. (Checked with ) + // even with `-C opt-level=1`, it gets optimized as best as it could be. + // (Checked with ) let mut buf: MaybeUninit<[T; N]> = MaybeUninit::uninit(); // SAFETY: buf and elements do not overlap, are aligned and have space @@ -879,7 +891,8 @@ impl SmallVec { }; // Deallocate the remaining elements so no memory is leaked. unsafe { - // SAFETY: both the input and output pointers are in range of the stack allocation + // SAFETY: both the input and output pointers are in range of the stack + // allocation let remainder_ptr = vec.raw.as_mut_ptr_inline().add(len); let remainder_len = N - len; @@ -893,7 +906,9 @@ impl SmallVec { vec } - /// Constructs a new `SmallVec` on the stack from an A without copying elements. Also sets the length. The user is responsible for ensuring that `len <= A::size()`. + /// Constructs a new `SmallVec` on the stack from an A without copying + /// elements. Also sets the length. The user is responsible for ensuring + /// that `len <= A::size()`. /// /// # Examples /// @@ -902,9 +917,7 @@ impl SmallVec { /// use std::mem::MaybeUninit; /// /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; - /// let small_vec = unsafe { - /// SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5) - /// }; + /// let small_vec = unsafe { SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5) }; /// /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` @@ -935,8 +948,8 @@ impl SmallVec { if Self::IS_ZST { // "Move" elements to stack buffer. They're ZST so we don't actually have to do // anything. Just make sure they're not dropped. - // We don't wrap the vector in ManuallyDrop so that when it's dropped, the memory is - // deallocated, if it needs to be. + // We don't wrap the vector in ManuallyDrop so that when it's dropped, the + // memory is deallocated, if it needs to be. let mut vec = vec; let len = vec.len(); @@ -986,13 +999,14 @@ impl SmallVec { /// Sets the length of a vector. /// - /// This will explicitly set the size of the vector, without actually modifying its buffers, so - /// it is up to the caller to ensure that the vector is actually the specified size. + /// This will explicitly set the size of the vector, without actually + /// modifying its buffers, so it is up to the caller to ensure that the + /// vector is actually the specified size. /// /// # Safety /// - /// `new_len <= self.capacity()` must be true, and all the elements in the range `..self.len` - /// must be initialized. + /// `new_len <= self.capacity()` must be true, and all the elements in the + /// range `..self.len` must be initialized. #[inline] pub unsafe fn set_len(&mut self, new_len: usize) { debug_assert!(new_len <= self.capacity()); @@ -1043,9 +1057,11 @@ impl SmallVec { /// /// - If you want to take ownership of the entire contents and capacity of /// the vector, see [`core::mem::take`] or [`core::mem::replace`]. - /// - If you don't need the returned vector at all, see [`SmallVec::truncate`]. + /// - If you don't need the returned vector at all, see + /// [`SmallVec::truncate`]. /// - If you want to take ownership of an arbitrary subslice, or you don't - /// necessarily want to store the removed items in a vector, see [`SmallVec::drain`]. + /// necessarily want to store the removed items in a vector, see + /// [`SmallVec::drain`]. /// /// # Panics /// @@ -1096,25 +1112,29 @@ impl SmallVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - // Since self is a &mut, passing it to a function would invalidate the slice iterator. + // Since self is a &mut, passing it to a function would invalidate the slice + // iterator. vec: core::ptr::NonNull::new_unchecked(self as *mut _), //vec: core::ptr::NonNull::from(self), } } } - /// Creates an iterator which uses a closure to determine if element in the range should be removed. + /// Creates an iterator which uses a closure to determine if element in the + /// range should be removed. /// /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the vector and will not be yielded - /// by the iterator. + /// If the closure returns false, the element will remain in the vector and + /// will not be yielded by the iterator. /// - /// Only elements that fall in the provided range are considered for extraction, but any elements - /// after the range will still have to be moved if any element has been extracted. + /// Only elements that fall in the provided range are considered for + /// extraction, but any elements after the range will still have to be + /// moved if any element has been extracted. /// - /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating - /// or the iteration short-circuits, then the remaining elements will be retained. - /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped + /// without iterating or the iteration short-circuits, then the + /// remaining elements will be retained. Use [`retain`] with a negated + /// predicate if you do not need the returned iterator. /// /// [`retain`]: SmallVec::retain /// @@ -1141,8 +1161,9 @@ impl SmallVec { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, - /// regardless of whether you choose to keep or remove them. + /// Note that `extract_if` also lets you mutate the elements passed to the + /// filter closure, regardless of whether you choose to keep or remove + /// them. /// /// # Panics /// @@ -1154,13 +1175,19 @@ impl SmallVec { /// /// ``` /// # use smallvec::SmallVec; - /// let mut numbers: SmallVec = SmallVec::from(&[1i32, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); + /// let mut numbers: SmallVec = + /// SmallVec::from(&[1i32, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); /// - /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::>(); + /// let evens = numbers + /// .extract_if(.., |x| *x % 2 == 0) + /// .collect::>(); /// let odds = numbers; /// /// assert_eq!(evens, SmallVec::::from(&[2i32, 4, 6, 8, 14])); - /// assert_eq!(odds, SmallVec::::from(&[1i32, 3, 5, 9, 11, 13, 15])); + /// assert_eq!( + /// odds, + /// SmallVec::::from(&[1i32, 3, 5, 9, 11, 13, 15]) + /// ); /// ``` /// /// Using the range argument to only process a part of the vector: @@ -1168,8 +1195,13 @@ impl SmallVec { /// ``` /// # use smallvec::SmallVec; /// let mut items: SmallVec = SmallVec::from(&[0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]); - /// let ones = items.extract_if(7.., |x| *x == 1).collect::>(); - /// assert_eq!(items, SmallVec::::from(&[0, 0, 0, 0, 0, 0, 0, 2, 2, 2])); + /// let ones = items + /// .extract_if(7.., |x| *x == 1) + /// .collect::>(); + /// assert_eq!( + /// items, + /// SmallVec::::from(&[0, 0, 0, 0, 0, 0, 0, 2, 2, 2]) + /// ); /// assert_eq!(ones.len(), 3); /// ``` pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, N, F> @@ -1214,8 +1246,8 @@ impl SmallVec { } // SAFETY: both the input and output are within the allocation let ptr = unsafe { self.as_mut_ptr().add(len) }; - // SAFETY: we allocated enough space in case it wasn't enough, so the address is valid for - // writes. + // SAFETY: we allocated enough space in case it wasn't enough, so the address is + // valid for writes. unsafe { ptr.write(value) }; unsafe { self.set_len(len + 1) } } @@ -1226,10 +1258,11 @@ impl SmallVec { None } else { let len = self.len() - 1; - // SAFETY: len < old_len since this can't overflow, because the old length is non zero + // SAFETY: len < old_len since this can't overflow, because the old length is + // non zero unsafe { self.set_len(len) }; - // SAFETY: this element was initialized and we just gave up ownership of it, so we can - // give it away + // SAFETY: this element was initialized and we just gave up ownership of it, so + // we can give it away let value = unsafe { self.as_mut_ptr().add(len).read() }; Some(value) } @@ -1247,7 +1280,8 @@ impl SmallVec { #[inline] pub fn append(&mut self, other: &mut SmallVec) { - // can't overflow since both are smaller than isize::MAX and 2 * isize::MAX < usize::MAX + // can't overflow since both are smaller than isize::MAX and 2 * isize::MAX < + // usize::MAX let len = self.len(); let other_len = other.len(); let total_len = len + other_len; @@ -1258,8 +1292,8 @@ impl SmallVec { // SAFETY: see `Self::push` let ptr = unsafe { self.as_mut_ptr().add(len) }; unsafe { other.set_len(0) } - // SAFETY: we have a mutable reference to each vector and each uniquely owns its memory. - // so the ranges can't overlap + // SAFETY: we have a mutable reference to each vector and each uniquely owns its + // memory. so the ranges can't overlap unsafe { copy_nonoverlapping(other.as_ptr(), ptr, other_len) }; unsafe { self.set_len(total_len) } } @@ -1557,8 +1591,8 @@ impl SmallVec { if !self.spilled() { let mut vec = Vec::with_capacity(len); let this = ManuallyDrop::new(self); - // SAFETY: we create a new vector with sufficient capacity, copy our elements into it - // to transfer ownership and then set the length + // SAFETY: we create a new vector with sufficient capacity, copy our elements + // into it to transfer ownership and then set the length // we don't drop the elements we previously held unsafe { copy_nonoverlapping(this.raw.as_ptr_inline(), vec.as_mut_ptr(), len); @@ -1719,27 +1753,39 @@ impl SmallVec { } } - /// Creates a `SmallVec` directly from the raw components of another `SmallVec`. + /// Creates a `SmallVec` directly from the raw components of another + /// `SmallVec`. /// /// # Safety /// - /// This is highly unsafe, due to the number of invariants that aren’t checked: + /// This is highly unsafe, due to the number of invariants that aren’t + /// checked: /// - /// - `ptr` needs to have been previously allocated via `SmallVec` from its spilled storage (at least, it’s highly likely to be incorrect if it wasn’t). - /// - `ptr`’s `A::Item` type needs to be the same size and alignment that it was allocated with + /// - `ptr` needs to have been previously allocated via `SmallVec` from its + /// spilled storage (at least, it’s highly likely to be incorrect if it + /// wasn’t). + /// - `ptr`’s `A::Item` type needs to be the same size and alignment that it + /// was allocated with /// - `length` needs to be less than or equal to `capacity`. - /// - `capacity` needs to be the capacity that the pointer was allocated with. + /// - `capacity` needs to be the capacity that the pointer was allocated + /// with. /// - /// Violating these may cause problems like corrupting the allocator’s internal data structures. + /// Violating these may cause problems like corrupting the allocator’s + /// internal data structures. /// - /// Additionally, `capacity` must be greater than the amount of inline storage `A` has; that is, the new `SmallVec` must need to spill over into heap allocated storage. This condition is asserted against. + /// Additionally, `capacity` must be greater than the amount of inline + /// storage `A` has; that is, the new `SmallVec` must need to spill over + /// into heap allocated storage. This condition is asserted against. /// - /// The ownership of `ptr` is effectively transferred to the `SmallVec` which may then deallocate, reallocate or change the contents of memory pointed to by the pointer at will. Ensure that nothing else uses the pointer after calling this function. + /// The ownership of `ptr` is effectively transferred to the `SmallVec` + /// which may then deallocate, reallocate or change the contents of memory + /// pointed to by the pointer at will. Ensure that nothing else uses the + /// pointer after calling this function. /// /// # Examples /// /// ``` - /// use smallvec::{SmallVec, smallvec}; + /// use smallvec::{smallvec, SmallVec}; /// /// let mut v: SmallVec<_, 1> = smallvec![1, 2, 3]; /// @@ -1949,8 +1995,8 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { let on_heap = self.spilled(); let len = self.len(); let ptr = self.as_mut_ptr(); - // SAFETY: we first drop the elements, then `_drop_dealloc` is dropped, releasing memory we - // used to own + // SAFETY: we first drop the elements, then `_drop_dealloc` is dropped, + // releasing memory we used to own unsafe { let _drop_dealloc = if on_heap { let capacity = self.capacity(); @@ -2102,7 +2148,8 @@ mod spec_traits { } } - /// A trait for specializing the implementations of [`Extend`] and [`extend_from_slice`]. + /// A trait for specializing the implementations of [`Extend`] and + /// [`extend_from_slice`]. /// /// [`extend_from_slice`]: crate::SmallVec::extend_from_slice pub(crate) trait SpecExtend { @@ -2222,7 +2269,8 @@ mod spec_traits { /// # Safety /// /// * The length of the vector is larger than or equal to `src.len()`. - /// * The spare capacity of the vector is larger than or equal to `src.len()`. + /// * The spare capacity of the vector is larger than or equal to + /// `src.len()`. /// /// [`extend_from_within`]: SmallVec::extend_from_within unsafe fn spec_extend_from_within(&mut self, src: core::ops::Range); @@ -2362,7 +2410,8 @@ mod spec_traits { } /// Fallback functions for various specialized methods. These are kept in -/// a separate implementation block for easy access whenever specialization is disabled. +/// a separate implementation block for easy access whenever specialization is +/// disabled. impl SmallVec { /// Creates a `Smallvec` value where `elem` is repeated `n` times. /// This will use the inline storage, not the heap. @@ -2418,7 +2467,8 @@ impl SmallVec { /// # Safety /// /// * The length of the vector is larger than or equal to `src.len()`. - /// * The spare capacity of the vector is larger than or equal to `src.len()`. + /// * The spare capacity of the vector is larger than or equal to + /// `src.len()`. /// /// [`extend_from_within`]: SmallVec::extend_from_within unsafe fn extend_from_within_fallback(&mut self, src: core::ops::Range) @@ -2690,8 +2740,8 @@ impl IntoIterator for SmallVec { type IntoIter = IntoIter; type Item = T; fn into_iter(self) -> Self::IntoIter { - // SAFETY: we move out of this.raw by reading the value at its address, which is fine since - // we don't drop it + // SAFETY: we move out of this.raw by reading the value at its address, which is + // fine since we don't drop it unsafe { // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements let this = ManuallyDrop::new(self); diff --git a/src/tests.rs b/src/tests.rs index cfd801b..74f732f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,12 +1,10 @@ use crate::{smallvec, SmallVec}; - -use core::hash::Hasher; -use core::iter::FromIterator; - use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::{vec, vec::Vec}; +use core::hash::Hasher; +use core::iter::FromIterator; #[test] pub fn test_zero() { @@ -17,7 +15,8 @@ pub fn test_zero() { assert_eq!(&*v, &[0]); } -// We heap allocate all these strings so that double frees will show up under valgrind. +// We heap allocate all these strings so that double frees will show up under +// valgrind. #[test] pub fn test_inline() { @@ -614,8 +613,8 @@ fn test_into_iter_as_slice() { #[test] fn test_into_iter_clone() { - // Test that the cloned iterator yields identical elements and that it owns its own copy - // (i.e. no use after move errors). + // Test that the cloned iterator yields identical elements and that it owns its + // own copy (i.e. no use after move errors). let mut iter = SmallVec::::from_iter(0..3).into_iter(); let mut clone_iter = iter.clone(); while let Some(x) = iter.next() { @@ -626,7 +625,8 @@ fn test_into_iter_clone() { #[test] fn test_into_iter_clone_partially_consumed_iterator() { - // Test that the cloned iterator only contains the remaining elements of the original iterator. + // Test that the cloned iterator only contains the remaining elements of the + // original iterator. let mut iter = SmallVec::::from_iter(0..3).into_iter().skip(1); let mut clone_iter = iter.clone(); while let Some(x) = iter.next() { @@ -942,11 +942,13 @@ fn test_extract_if() { assert_eq!(b, SmallVec::::from(&[3u8, 6])); } -/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments -/// given to SmallVec. Draining and extending the allocation are fairly well-tested earlier, but -/// `smallvec.insert(usize::MAX, val)` once slipped by! +/// This assortment of tests, in combination with miri, verifies we handle UB on +/// fishy arguments given to SmallVec. Draining and extending the allocation are +/// fairly well-tested earlier, but `smallvec.insert(usize::MAX, val)` once +/// slipped by! /// -/// All code that indexes into SmallVecs should be tested with such "trivially wrong" args. +/// All code that indexes into SmallVecs should be tested with such "trivially +/// wrong" args. #[test] fn max_dont_panic() { let mut sv: SmallVec = smallvec![0]; @@ -986,12 +988,13 @@ fn collect_from_iter() { self.0.next() } - // no implementation of size_hint means it returns (0, None) - which forces from_iter to - // grow the allocated space iteratively. + // no implementation of size_hint means it returns (0, None) - which forces + // from_iter to grow the allocated space iteratively. } - // A length of 3 is fine to trigger this bug under valgrind, but making the vector 1 million - // elements makes it crash - which is much easier to detect. + // A length of 3 is fine to trigger this bug under valgrind, but making the + // vector 1 million elements makes it crash - which is much easier to + // detect. let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); let _y: SmallVec = SmallVec::from_iter(iter); From e66df4d07b644bf2c4d4442a54cc96d75ff617db Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Sun, 23 Aug 2026 23:05:50 +0200 Subject: [PATCH 02/15] feat: added bytes, serde, std, taggedlen files --- src/allocationerror.rs | 23 +++ src/bytes.rs | 69 +++++++ src/lib.rs | 403 +++-------------------------------------- src/rawsmallvec.rs | 112 ++++++++++++ src/serde.rs | 58 ++++++ src/std.rs | 25 +++ src/taggedlen.rs | 62 +++++++ src/tests.rs | 2 + 8 files changed, 379 insertions(+), 375 deletions(-) create mode 100644 src/allocationerror.rs create mode 100644 src/bytes.rs create mode 100644 src/serde.rs create mode 100644 src/std.rs create mode 100644 src/taggedlen.rs diff --git a/src/allocationerror.rs b/src/allocationerror.rs new file mode 100644 index 0000000..a0ea22b --- /dev/null +++ b/src/allocationerror.rs @@ -0,0 +1,23 @@ +use alloc::alloc::Layout; +use core::error::Error; +use core::fmt::{Display, Formatter, Result as Format}; + +/// Error type for APIs with fallible heap allocation +#[derive(Debug)] +pub enum AllocationError { + /// Overflow `usize::MAX` or other error during size computation + CapacityOverflow, + /// The allocator return an error + Failure { + /// The layout that was passed to the allocator + layout: Layout, + }, +} + +impl Display for AllocationError { + fn fmt(&self, f: &mut Formatter) -> Format { + write!(f, "Allocation error: {:?}", self) + } +} + +impl Error for AllocationError {} diff --git a/src/bytes.rs b/src/bytes.rs new file mode 100644 index 0000000..dbf5b8e --- /dev/null +++ b/src/bytes.rs @@ -0,0 +1,69 @@ +use bytes::{buf::UninitSlice, BufMut}; +use super::SmallVec; + +unsafe impl BufMut for SmallVec { + #[inline] + fn remaining_mut(&self) -> usize { + // A vector can never have more than isize::MAX bytes + isize::MAX as usize - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let len = self.len(); + let remaining = self.capacity() - len; + + if remaining < cnt { + panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); + } + + // Addition will not overflow since the sum is at most the capacity. + self.set_len(len + cnt); + } + + #[inline] + fn chunk_mut(&mut self) -> &mut UninitSlice { + if self.capacity() == self.len() { + self.reserve(64); // Grow the smallvec + } + + let cap = self.capacity(); + let len = self.len(); + + let ptr = self.as_mut_ptr(); + // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be + // valid for `cap - len` bytes. The subtraction will not underflow since + // `len <= cap`. + unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } + } + + // Specialize these methods so they can skip checking `remaining_mut` + // and `advance_mut`. + #[inline] + fn put(&mut self, mut src: T) + where + Self: Sized, + { + // In case the src isn't contiguous, reserve upfront. + self.reserve(src.remaining()); + + while src.has_remaining() { + let s = src.chunk(); + let l = s.len(); + self.extend_from_slice(s); + src.advance(l); + } + } + + #[inline] + fn put_slice(&mut self, src: &[u8]) { + self.extend_from_slice(src); + } + + #[inline] + fn put_bytes(&mut self, val: u8, cnt: usize) { + // If the addition overflows, then the `resize` will fail. + let new_len = self.len().saturating_add(cnt); + self.resize(new_len, val); + } +} diff --git a/src/lib.rs b/src/lib.rs index 576bcc5..810a76a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,3 @@ -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Small vectors in various sizes. These store a certain number of elements //! inline, and fall back to the heap for larger allocations. This can be a //! useful optimization for improving cache locality and reducing allocator @@ -22,7 +16,6 @@ //! When this feature is enabled, traits available from `std` are implemented: //! //! * `SmallVec` implements the [`std::io::Write`] trait. -//! * [`CollectionAllocErr`] implements [`std::error::Error`]. //! //! This feature is not compatible with `#![no_std]` programs. //! @@ -54,7 +47,6 @@ //! Tracking issue: [rust-lang/rust#34761](https://github.com/rust-lang/rust/issues/34761) #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(feature = "specialization", allow(incomplete_features))] #![cfg_attr(feature = "specialization", feature(specialization, trusted_len))] #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] @@ -62,10 +54,15 @@ #[doc(hidden)] pub extern crate alloc; -#[cfg(any(test, feature = "std"))] -extern crate std; - +mod allocationerror; +#[cfg(feature = "bytes")] +mod bytes; mod rawsmallvec; +#[cfg(feature = "serde")] +mod serde; +#[cfg(feature = "std")] +mod std; +mod taggedlen; #[cfg(test)] mod tests; @@ -73,8 +70,7 @@ use alloc::alloc::Layout; use alloc::boxed::Box; use alloc::vec; use alloc::vec::Vec; -#[cfg(feature = "bytes")] -use bytes::{buf::UninitSlice, BufMut}; +use allocationerror::AllocationError; use core::borrow::Borrow; use core::borrow::BorrowMut; use core::fmt::Debug; @@ -90,51 +86,25 @@ use core::ptr::NonNull; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "internals")] -pub use rawsmallvec::RawSmallVec; +pub use { + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen +}; #[cfg(not(feature = "internals"))] -use rawsmallvec::RawSmallVec; -#[cfg(feature = "serde")] -use serde_core::{ - de::{Deserialize, Deserializer, SeqAccess, Visitor}, - ser::{Serialize, SerializeSeq, Serializer}, +use { + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen }; -#[cfg(feature = "std")] -use std::io; - -/// Error type for APIs with fallible heap allocation -#[derive(Debug)] -pub enum CollectionAllocErr { - /// Overflow `usize::MAX` or other error during size computation - CapacityOverflow, - /// The allocator return an error - AllocErr { - /// The layout that was passed to the allocator - layout: Layout, - }, -} -impl core::fmt::Display for CollectionAllocErr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Allocation error: {:?}", self) - } -} - -impl core::error::Error for CollectionAllocErr {} #[inline] -fn infallible(result: Result) -> T { +fn infallible(result: Result) -> T { match result { Ok(x) => x, - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr { layout }) => alloc::alloc::handle_alloc_error(layout), + Err(AllocationError::CapacityOverflow) => panic!("capacity overflow"), + Err(AllocationError::Failure { layout }) => alloc::alloc::handle_alloc_error(layout), } } -/// Helper function to check if a type is a ZST. -#[inline] -const fn is_zst() -> bool { - const { size_of::() == 0 } -} - #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -170,173 +140,6 @@ where core::ops::Range { start, end } } -impl RawSmallVec { - const IS_ZST: bool = is_zst::(); - - #[inline] - const fn new() -> Self { - Self::new_inline(MaybeUninit::uninit()) - } - #[inline] - const fn new_inline(inline: MaybeUninit<[T; N]>) -> Self { - Self { - inline: ManuallyDrop::new(inline), - } - } - #[inline] - const fn new_heap(ptr: NonNull, capacity: usize) -> Self { - Self { - heap: (ptr, capacity), - } - } - - #[inline] - const fn as_ptr_inline(&self) -> *const T { - // SAFETY: it is safe because we aren't reading the value, just getting a - // reference to it. reading it would be UB potentially, but for that downstream - // unsafe is required - (unsafe { &raw const self.inline }) as *mut T - } - - #[inline] - const fn as_mut_ptr_inline(&mut self) -> *mut T { - // SAFETY: same as above - (unsafe { &raw mut self.inline }) as *mut T - } - - /// # Safety - /// - /// The vector must be on the heap - #[inline] - const unsafe fn as_ptr_heap(&self) -> *const T { - self.heap.0.as_ptr() - } - - /// # Safety - /// - /// The vector must be on the heap - #[inline] - const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { - self.heap.0.as_ptr() - } - - /// # Safety - /// - /// `new_capacity` must be non zero, and greater or equal to the length. - /// T must not be a ZST. - unsafe fn try_grow_raw( - &mut self, - len: TaggedLen, - new_capacity: usize, - ) -> Result<(), CollectionAllocErr> { - use alloc::alloc::{alloc, realloc}; - debug_assert!(!Self::IS_ZST); - debug_assert!(new_capacity > 0); - debug_assert!(new_capacity >= len.value()); - - let was_on_heap = len.on_heap(); - let ptr = if was_on_heap { - self.as_mut_ptr_heap() - } else { - self.as_mut_ptr_inline() - }; - let len = len.value(); - - let new_layout = - Layout::array::(new_capacity).map_err(|_| CollectionAllocErr::CapacityOverflow)?; - if new_layout.size() > isize::MAX as usize { - return Err(CollectionAllocErr::CapacityOverflow); - } - - let new_ptr = if len == 0 || !was_on_heap { - // get a fresh allocation - let new_ptr = alloc(new_layout) as *mut T; // `new_layout` has nonzero size. - let new_ptr = - NonNull::new(new_ptr).ok_or(CollectionAllocErr::AllocErr { layout: new_layout })?; - copy_nonoverlapping(ptr, new_ptr.as_ptr(), len); - new_ptr - } else { - // use realloc - - // this can't overflow since we already constructed an equivalent layout during - // the previous allocation - let old_layout = - Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); - - // SAFETY: ptr was allocated with this allocator - // old_layout is the same as the layout used to allocate the previous memory - // block new_layout.size() is greater than zero - // does not overflow when rounded up to alignment. since it was constructed - // with Layout::array - let new_ptr = realloc(ptr as *mut u8, old_layout, new_layout.size()) as *mut T; - NonNull::new(new_ptr).ok_or(CollectionAllocErr::AllocErr { layout: new_layout })? - }; - *self = Self::new_heap(new_ptr, new_capacity); - Ok(()) - } -} - -/// Vec guarantees that its length is always less than [`isize::MAX`] in -/// *bytes*. -/// -/// For a non ZST, this means that the length is less than `isize::MAX` objects, -/// which implies we have at least one free bit we can use. We use the least -/// significant bit for the tag. And store the length in the `usize::BITS - 1` -/// most significant bits. -/// -/// For a ZST, we never use the heap, so we just store the length directly. -#[repr(transparent)] -struct TaggedLen(usize, PhantomData); - -// Clone and Copy must be manually implemented because the generic interferes -// with the derive attribute implementations. -impl Clone for TaggedLen { - #[inline] - fn clone(&self) -> Self { - Self(self.0, PhantomData) - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - self.0 = source.0; - } -} - -impl Copy for TaggedLen {} - -impl TaggedLen { - const IS_ZST: bool = is_zst::(); - #[inline] - pub const fn new(len: usize, on_heap: bool) -> Self { - if Self::IS_ZST { - debug_assert!(!on_heap); - Self(len, PhantomData) - } else { - debug_assert!(len < isize::MAX as usize); - Self((len << 1) | on_heap as usize, PhantomData) - } - } - - #[inline] - #[must_use] - pub const fn on_heap(self) -> bool { - if Self::IS_ZST { - false - } else { - (self.0 & 1_usize) == 1 - } - } - - #[inline] - pub const fn value(self) -> usize { - if Self::IS_ZST { - self.0 - } else { - self.0 >> 1 - } - } -} - #[repr(C)] pub struct SmallVec { len: TaggedLen, @@ -937,7 +740,7 @@ impl SmallVec { } impl SmallVec { - const IS_ZST: bool = is_zst::(); + const IS_ZST: bool = size_of::() == 0; #[inline] pub fn from_vec(vec: Vec) -> Self { @@ -1304,7 +1107,7 @@ impl SmallVec { } #[cold] - pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), CollectionAllocErr> { + pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), AllocationError> { if Self::IS_ZST { return Ok(()); } @@ -1352,20 +1155,20 @@ impl SmallVec { self.len() .checked_add(additional) .and_then(usize::checked_next_power_of_two) - .ok_or(CollectionAllocErr::CapacityOverflow), + .ok_or(AllocationError::CapacityOverflow), ); self.grow(new_capacity); } } #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), AllocationError> { if additional > self.capacity() - self.len() { let new_capacity = self .len() .checked_add(additional) .and_then(usize::checked_next_power_of_two) - .ok_or(CollectionAllocErr::CapacityOverflow)?; + .ok_or(AllocationError::CapacityOverflow)?; self.try_grow(new_capacity) } else { Ok(()) @@ -1379,19 +1182,19 @@ impl SmallVec { let new_capacity = infallible( self.len() .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow), + .ok_or(AllocationError::CapacityOverflow), ); self.grow(new_capacity); } } #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), AllocationError> { if additional > self.capacity() - self.len() { let new_capacity = self .len() .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow)?; + .ok_or(AllocationError::CapacityOverflow)?; self.try_grow(new_capacity) } else { Ok(()) @@ -2904,67 +2707,6 @@ impl Debug for Drain<'_, T, N> { } } -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl Serialize for SmallVec -where - T: Serialize, -{ - fn serialize(&self, serializer: S) -> Result { - let mut state = serializer.serialize_seq(Some(self.len()))?; - for item in self { - state.serialize_element(item)?; - } - state.end() - } -} - -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl<'de, T, const N: usize> Deserialize<'de> for SmallVec -where - T: Deserialize<'de>, -{ - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_seq(SmallVecVisitor { - phantom: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -struct SmallVecVisitor { - phantom: PhantomData, -} - -#[cfg(feature = "serde")] -impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor -where - T: Deserialize<'de>, -{ - type Value = SmallVec; - - fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: B) -> Result - where - B: SeqAccess<'de>, - { - use serde_core::de::Error; - let len = seq.size_hint().unwrap_or(0); - let mut values = SmallVec::new(); - values.try_reserve(len).map_err(B::Error::custom)?; - - while let Some(value) = seq.next_element()? { - values.push(value); - } - - Ok(values) - } -} - #[cfg(feature = "malloc_size_of")] impl MallocShallowSizeOf for SmallVec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { @@ -2985,93 +2727,4 @@ impl MallocSizeOf for SmallVec { } n } -} - -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl io::Write for SmallVec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[cfg(feature = "bytes")] -unsafe impl BufMut for SmallVec { - #[inline] - fn remaining_mut(&self) -> usize { - // A vector can never have more than isize::MAX bytes - isize::MAX as usize - self.len() - } - - #[inline] - unsafe fn advance_mut(&mut self, cnt: usize) { - let len = self.len(); - let remaining = self.capacity() - len; - - if remaining < cnt { - panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); - } - - // Addition will not overflow since the sum is at most the capacity. - self.set_len(len + cnt); - } - - #[inline] - fn chunk_mut(&mut self) -> &mut UninitSlice { - if self.capacity() == self.len() { - self.reserve(64); // Grow the smallvec - } - - let cap = self.capacity(); - let len = self.len(); - - let ptr = self.as_mut_ptr(); - // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be - // valid for `cap - len` bytes. The subtraction will not underflow since - // `len <= cap`. - unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } - } - - // Specialize these methods so they can skip checking `remaining_mut` - // and `advance_mut`. - #[inline] - fn put(&mut self, mut src: T) - where - Self: Sized, - { - // In case the src isn't contiguous, reserve upfront. - self.reserve(src.remaining()); - - while src.has_remaining() { - let s = src.chunk(); - let l = s.len(); - self.extend_from_slice(s); - src.advance(l); - } - } - - #[inline] - fn put_slice(&mut self, src: &[u8]) { - self.extend_from_slice(src); - } - - #[inline] - fn put_bytes(&mut self, val: u8, cnt: usize) { - // If the addition overflows, then the `resize` will fail. - let new_len = self.len().saturating_add(cnt); - self.resize(new_len, val); - } -} +} \ No newline at end of file diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index dadbf95..5776803 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,5 +1,9 @@ use core::mem::{ManuallyDrop, MaybeUninit}; use core::ptr::NonNull; +use super::TaggedLen; +use super::allocationerror::AllocationError; +use core::ptr::copy_nonoverlapping; +use alloc::alloc::Layout; /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. @@ -11,3 +15,111 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize), } + +impl RawSmallVec { + pub const IS_ZST: bool = size_of::() == 0; + + #[inline] + pub const fn new() -> Self { + Self::new_inline(MaybeUninit::uninit()) + } + #[inline] + pub const fn new_inline(inline: MaybeUninit<[T; N]>) -> Self { + Self { + inline: ManuallyDrop::new(inline), + } + } + #[inline] + pub const fn new_heap(ptr: NonNull, capacity: usize) -> Self { + Self { + heap: (ptr, capacity), + } + } + + #[inline] + pub const fn as_ptr_inline(&self) -> *const T { + // SAFETY: it is safe because we aren't reading the value, just getting a + // reference to it. reading it would be UB potentially, but for that downstream + // unsafe is required + #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] + (unsafe { &raw const self.inline }).cast::() + } + + #[inline] + pub const fn as_mut_ptr_inline(&mut self) -> *mut T { + // SAFETY: same as above + #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] + (unsafe { &raw mut self.inline }).cast::() + } + + /// # Safety + /// + /// The vector must be on the heap + #[inline] + pub const unsafe fn as_ptr_heap(&self) -> *const T { + self.heap.0.as_ptr() + } + + /// # Safety + /// + /// The vector must be on the heap + #[inline] + pub const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { + self.heap.0.as_ptr() + } + + /// # Safety + /// + /// `new_capacity` must be non zero, and greater or equal to the length. + /// T must not be a ZST. + pub unsafe fn try_grow_raw( + &mut self, + len: TaggedLen, + new_capacity: usize, + ) -> Result<(), AllocationError> { + use alloc::alloc::{alloc, realloc}; + debug_assert!(!Self::IS_ZST); + debug_assert!(new_capacity > 0); + debug_assert!(new_capacity >= len.value()); + + let was_on_heap = len.on_heap(); + let ptr = if was_on_heap { + self.as_mut_ptr_heap() + } else { + self.as_mut_ptr_inline() + }; + let len = len.value(); + + let new_layout = + Layout::array::(new_capacity).map_err(|_| AllocationError::CapacityOverflow)?; + if new_layout.size() > isize::MAX as usize { + return Err(AllocationError::CapacityOverflow); + } + + let new_ptr = if len == 0 || !was_on_heap { + // get a fresh allocation + let new_ptr = alloc(new_layout) as *mut T; // `new_layout` has nonzero size. + let new_ptr = + NonNull::new(new_ptr).ok_or(AllocationError::Failure { layout: new_layout })?; + copy_nonoverlapping(ptr, new_ptr.as_ptr(), len); + new_ptr + } else { + // use realloc + + // this can't overflow since we already constructed an equivalent layout during + // the previous allocation + let old_layout = + Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); + + // SAFETY: ptr was allocated with this allocator + // old_layout is the same as the layout used to allocate the previous memory + // block new_layout.size() is greater than zero + // does not overflow when rounded up to alignment. since it was constructed + // with Layout::array + let new_ptr = realloc(ptr as *mut u8, old_layout, new_layout.size()) as *mut T; + NonNull::new(new_ptr).ok_or(AllocationError::Failure { layout: new_layout })? + }; + *self = Self::new_heap(new_ptr, new_capacity); + Ok(()) + } +} \ No newline at end of file diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 0000000..7d72f00 --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,58 @@ +use serde_core::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, SeqAccess}, ser::SerializeSeq}; +use super::SmallVec; +use core::marker::PhantomData; + +impl Serialize for SmallVec +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result { + let mut state = serializer.serialize_seq(Some(self.len()))?; + for item in self { + state.serialize_element(item)?; + } + state.end() + } +} + +impl<'de, T, const N: usize> Deserialize<'de> for SmallVec +where + T: Deserialize<'de>, +{ + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_seq(SmallVecVisitor { + phantom: PhantomData, + }) + } +} + +struct SmallVecVisitor { + phantom: PhantomData, +} + +impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor +where + T: Deserialize<'de>, +{ + type Value = SmallVec; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: B) -> Result + where + B: SeqAccess<'de>, + { + use serde_core::de::Error; + let len = seq.size_hint().unwrap_or(0); + let mut values = SmallVec::new(); + values.try_reserve(len).map_err(B::Error::custom)?; + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } +} \ No newline at end of file diff --git a/src/std.rs b/src/std.rs new file mode 100644 index 0000000..8468f58 --- /dev/null +++ b/src/std.rs @@ -0,0 +1,25 @@ +extern crate std; + +use super::SmallVec; +use std::io; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl io::Write for SmallVec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} \ No newline at end of file diff --git a/src/taggedlen.rs b/src/taggedlen.rs new file mode 100644 index 0000000..4acb32c --- /dev/null +++ b/src/taggedlen.rs @@ -0,0 +1,62 @@ +use core::marker::PhantomData; + +/// Vec guarantees that its length is always less than [`isize::MAX`] in +/// *bytes*. +/// +/// For a non ZST, this means that the length is less than `isize::MAX` objects, +/// which implies we have at least one free bit we can use. We use the least +/// significant bit for the tag. And store the length in the `usize::BITS - 1` +/// most significant bits. +/// +/// For a ZST, we never use the heap, so we just store the length directly. +#[repr(transparent)] +pub struct TaggedLen(usize, PhantomData); + +// Clone and Copy must be manually implemented because the generic interferes +// with the derive attribute implementations. +impl Clone for TaggedLen { + #[inline] + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.0 = source.0; + } +} + +impl Copy for TaggedLen {} + +impl TaggedLen { + const IS_ZST: bool = size_of::() == 0; + #[inline] + pub const fn new(len: usize, on_heap: bool) -> Self { + if Self::IS_ZST { + debug_assert!(!on_heap); + Self(len, PhantomData) + } else { + debug_assert!(len < isize::MAX as usize); + Self((len << 1) | on_heap as usize, PhantomData) + } + } + + #[inline] + #[must_use] + pub const fn on_heap(self) -> bool { + if Self::IS_ZST { + false + } else { + (self.0 & 1_usize) == 1 + } + } + + #[inline] + pub const fn value(self) -> usize { + if Self::IS_ZST { + self.0 + } else { + self.0 >> 1 + } + } +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 74f732f..0442e24 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,3 +1,5 @@ +extern crate std; + use crate::{smallvec, SmallVec}; use alloc::borrow::ToOwned; use alloc::boxed::Box; From b27e3857c914f3627c43090b76983e5e3e10bd63 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Sun, 23 Aug 2026 23:23:23 +0200 Subject: [PATCH 03/15] fix: style checked --- src/bytes.rs | 2 +- src/lib.rs | 12 +++--------- src/rawsmallvec.rs | 10 +++++----- src/serde.rs | 8 ++++++-- src/std.rs | 2 +- src/taggedlen.rs | 2 +- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index dbf5b8e..441a5e6 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1,5 +1,5 @@ -use bytes::{buf::UninitSlice, BufMut}; use super::SmallVec; +use bytes::{buf::UninitSlice, BufMut}; unsafe impl BufMut for SmallVec { #[inline] diff --git a/src/lib.rs b/src/lib.rs index 810a76a..e2e298f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,15 +86,9 @@ use core::ptr::NonNull; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "internals")] -pub use { - rawsmallvec::RawSmallVec, - taggedlen::TaggedLen -}; +pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[cfg(not(feature = "internals"))] -use { - rawsmallvec::RawSmallVec, - taggedlen::TaggedLen -}; +use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[inline] fn infallible(result: Result) -> T { @@ -2727,4 +2721,4 @@ impl MallocSizeOf for SmallVec { } n } -} \ No newline at end of file +} diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 5776803..58dbd64 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,9 +1,9 @@ -use core::mem::{ManuallyDrop, MaybeUninit}; -use core::ptr::NonNull; -use super::TaggedLen; use super::allocationerror::AllocationError; -use core::ptr::copy_nonoverlapping; +use super::TaggedLen; use alloc::alloc::Layout; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ptr::copy_nonoverlapping; +use core::ptr::NonNull; /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. @@ -122,4 +122,4 @@ impl RawSmallVec { *self = Self::new_heap(new_ptr, new_capacity); Ok(()) } -} \ No newline at end of file +} diff --git a/src/serde.rs b/src/serde.rs index 7d72f00..6f32365 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -1,6 +1,10 @@ -use serde_core::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, SeqAccess}, ser::SerializeSeq}; use super::SmallVec; use core::marker::PhantomData; +use serde_core::{ + de::{SeqAccess, Visitor}, + ser::SerializeSeq, + Deserialize, Deserializer, Serialize, Serializer, +}; impl Serialize for SmallVec where @@ -55,4 +59,4 @@ where Ok(values) } -} \ No newline at end of file +} diff --git a/src/std.rs b/src/std.rs index 8468f58..6a59b90 100644 --- a/src/std.rs +++ b/src/std.rs @@ -22,4 +22,4 @@ impl io::Write for SmallVec { fn flush(&mut self) -> io::Result<()> { Ok(()) } -} \ No newline at end of file +} diff --git a/src/taggedlen.rs b/src/taggedlen.rs index 4acb32c..99025d2 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -59,4 +59,4 @@ impl TaggedLen { self.0 >> 1 } } -} \ No newline at end of file +} From 38ea7bac6587637360712f03601760d46ef536c9 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 00:11:38 +0200 Subject: [PATCH 04/15] feat: added references file --- src/lib.rs | 46 +--------------------------------------------- src/references.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 45 deletions(-) create mode 100644 src/references.rs diff --git a/src/lib.rs b/src/lib.rs index e2e298f..6f02ae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ mod allocationerror; #[cfg(feature = "bytes")] mod bytes; mod rawsmallvec; +mod references; #[cfg(feature = "serde")] mod serde; #[cfg(feature = "std")] @@ -71,8 +72,6 @@ use alloc::boxed::Box; use alloc::vec; use alloc::vec::Vec; use allocationerror::AllocationError; -use core::borrow::Borrow; -use core::borrow::BorrowMut; use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::marker::PhantomData; @@ -1856,21 +1855,6 @@ impl Drop for IntoIter { } } -impl core::ops::Deref for SmallVec { - type Target = [T]; - - #[inline] - fn deref(&self) -> &Self::Target { - self.as_slice() - } -} -impl core::ops::DerefMut for SmallVec { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut_slice() - } -} - /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using thís function. #[doc(hidden)] @@ -2655,34 +2639,6 @@ impl Hash for SmallVec { } } -impl Borrow<[T]> for SmallVec { - #[inline] - fn borrow(&self) -> &[T] { - self.as_slice() - } -} - -impl BorrowMut<[T]> for SmallVec { - #[inline] - fn borrow_mut(&mut self) -> &mut [T] { - self.as_mut_slice() - } -} - -impl AsRef<[T]> for SmallVec { - #[inline] - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -impl AsMut<[T]> for SmallVec { - #[inline] - fn as_mut(&mut self) -> &mut [T] { - self.as_mut_slice() - } -} - impl Debug for SmallVec { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list().entries(self.iter()).finish() diff --git a/src/references.rs b/src/references.rs new file mode 100644 index 0000000..6e75c24 --- /dev/null +++ b/src/references.rs @@ -0,0 +1,45 @@ +use super::SmallVec; +use core::borrow::{Borrow, BorrowMut}; + +impl core::ops::Deref for SmallVec { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} +impl core::ops::DerefMut for SmallVec { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} + +impl AsRef<[T]> for SmallVec { + #[inline] + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +impl AsMut<[T]> for SmallVec { + #[inline] + fn as_mut(&mut self) -> &mut [T] { + self.as_mut_slice() + } +} + +impl Borrow<[T]> for SmallVec { + #[inline] + fn borrow(&self) -> &[T] { + self.as_slice() + } +} + +impl BorrowMut<[T]> for SmallVec { + #[inline] + fn borrow_mut(&mut self) -> &mut [T] { + self.as_mut_slice() + } +} \ No newline at end of file From 3e02aa8d7ea49f05978acaef50be651323fafb26 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 00:16:42 +0200 Subject: [PATCH 05/15] fix: style --- src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/references.rs b/src/references.rs index 6e75c24..dd933f1 100644 --- a/src/references.rs +++ b/src/references.rs @@ -42,4 +42,4 @@ impl BorrowMut<[T]> for SmallVec { fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } -} \ No newline at end of file +} From 46e847c29056c0dde657ac34070708aa389d2d29 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 02:32:37 +0200 Subject: [PATCH 06/15] feat: more modules --- benches/bench.rs | 6 +- rustfmt.toml | 2 +- src/allocationerror.rs | 10 ++- src/bytes.rs | 6 +- src/comparisons.rs | 82 ++++++++++++++++++++++++ src/lib.rs | 140 +++++------------------------------------ src/mallocsizeof.rs | 24 +++++++ src/rawsmallvec.rs | 14 +++-- src/references.rs | 6 +- src/serde.rs | 14 +++-- src/std.rs | 3 +- src/tests.rs | 47 +++++++------- 12 files changed, 182 insertions(+), 172 deletions(-) create mode 100644 src/comparisons.rs create mode 100644 src/mallocsizeof.rs diff --git a/benches/bench.rs b/benches/bench.rs index 2386400..0320449 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -3,8 +3,10 @@ extern crate test; -use smallvec::{smallvec, SmallVec}; -use test::Bencher; +use { + smallvec::{smallvec, SmallVec}, + test::Bencher, +}; const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; diff --git a/rustfmt.toml b/rustfmt.toml index 5171db1..3e05b31 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ wrap_comments = true -imports_granularity = "Preserve" +imports_granularity = "One" group_imports = "One" format_code_in_doc_comments = true \ No newline at end of file diff --git a/src/allocationerror.rs b/src/allocationerror.rs index a0ea22b..8c657a0 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -1,6 +1,10 @@ -use alloc::alloc::Layout; -use core::error::Error; -use core::fmt::{Display, Formatter, Result as Format}; +use { + alloc::alloc::Layout, + core::{ + error::Error, + fmt::{Display, Formatter, Result as Format}, + }, +}; /// Error type for APIs with fallible heap allocation #[derive(Debug)] diff --git a/src/bytes.rs b/src/bytes.rs index 441a5e6..71dd237 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1,5 +1,7 @@ -use super::SmallVec; -use bytes::{buf::UninitSlice, BufMut}; +use { + super::SmallVec, + bytes::{buf::UninitSlice, BufMut}, +}; unsafe impl BufMut for SmallVec { #[inline] diff --git a/src/comparisons.rs b/src/comparisons.rs new file mode 100644 index 0000000..cf7ceba --- /dev/null +++ b/src/comparisons.rs @@ -0,0 +1,82 @@ +use super::SmallVec; + +impl PartialEq> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &SmallVec) -> bool { + self.as_slice().eq(other.as_slice()) + } +} +impl Eq for SmallVec where T: Eq {} + +impl PartialEq<[U; M]> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &[U; M]) -> bool { + self[..] == other[..] + } +} + +impl PartialEq<&[U; M]> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &&[U; M]) -> bool { + self[..] == other[..] + } +} + +impl PartialEq<[U]> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &[U]) -> bool { + self[..] == other[..] + } +} + +impl PartialEq<&[U]> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &&[U]) -> bool { + self[..] == other[..] + } +} + +impl PartialEq<&mut [U]> for SmallVec +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &&mut [U]) -> bool { + self[..] == other[..] + } +} + +impl PartialOrd for SmallVec +where + T: PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &SmallVec) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl Ord for SmallVec +where + T: Ord, +{ + #[inline] + fn cmp(&self, other: &SmallVec) -> core::cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 6f02ae4..df20a4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,9 @@ pub extern crate alloc; mod allocationerror; #[cfg(feature = "bytes")] mod bytes; +mod comparisons; +#[cfg(feature = "malloc_size_of")] +mod mallocsizeof; mod rawsmallvec; mod references; #[cfg(feature = "serde")] @@ -67,23 +70,17 @@ mod taggedlen; #[cfg(test)] mod tests; -use alloc::alloc::Layout; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -use allocationerror::AllocationError; -use core::fmt::Debug; -use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use core::mem::align_of; -use core::mem::size_of; -use core::mem::ManuallyDrop; -use core::mem::MaybeUninit; -use core::ptr::copy; -use core::ptr::copy_nonoverlapping; -use core::ptr::NonNull; -#[cfg(feature = "malloc_size_of")] -use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; +use { + alloc::{alloc::Layout, boxed::Box, vec::Vec}, + allocationerror::AllocationError, + core::{ + fmt::Debug, + hash::{Hash, Hasher}, + marker::PhantomData, + mem::{align_of, size_of, ManuallyDrop, MaybeUninit}, + ptr::{copy, copy_nonoverlapping, NonNull}, + }, +}; #[cfg(feature = "internals")] pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[cfg(not(feature = "internals"))] @@ -709,8 +706,7 @@ impl SmallVec { /// # Examples /// /// ``` - /// use smallvec::SmallVec; - /// use std::mem::MaybeUninit; + /// use {smallvec::SmallVec, std::mem::MaybeUninit}; /// /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; /// let small_vec = unsafe { SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5) }; @@ -1862,7 +1858,8 @@ impl Drop for IntoIter { pub fn from_elem(elem: T, n: usize) -> SmallVec { if n > SmallVec::::inline_size() { // Standard Rust vectors are already specialized. - SmallVec::::from_vec(vec![elem; n]) + use core::iter::repeat_n; + SmallVec::from(Vec::from_iter(repeat_n(elem, n))) } else { #[cfg(feature = "specialization")] { @@ -2552,87 +2549,6 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { } } -impl PartialEq> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &SmallVec) -> bool { - self.as_slice().eq(other.as_slice()) - } -} -impl Eq for SmallVec where T: Eq {} - -impl PartialEq<[U; M]> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &[U; M]) -> bool { - self[..] == other[..] - } -} - -impl PartialEq<&[U; M]> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &&[U; M]) -> bool { - self[..] == other[..] - } -} - -impl PartialEq<[U]> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &[U]) -> bool { - self[..] == other[..] - } -} - -impl PartialEq<&[U]> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &&[U]) -> bool { - self[..] == other[..] - } -} - -impl PartialEq<&mut [U]> for SmallVec -where - T: PartialEq, -{ - #[inline] - fn eq(&self, other: &&mut [U]) -> bool { - self[..] == other[..] - } -} - -impl PartialOrd for SmallVec -where - T: PartialOrd, -{ - #[inline] - fn partial_cmp(&self, other: &SmallVec) -> Option { - self.as_slice().partial_cmp(other.as_slice()) - } -} - -impl Ord for SmallVec -where - T: Ord, -{ - #[inline] - fn cmp(&self, other: &SmallVec) -> core::cmp::Ordering { - self.as_slice().cmp(other.as_slice()) - } -} - impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) @@ -2656,25 +2572,3 @@ impl Debug for Drain<'_, T, N> { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } - -#[cfg(feature = "malloc_size_of")] -impl MallocShallowSizeOf for SmallVec { - fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - if self.spilled() { - unsafe { ops.malloc_size_of(self.as_ptr()) } - } else { - 0 - } - } -} - -#[cfg(feature = "malloc_size_of")] -impl MallocSizeOf for SmallVec { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - let mut n = self.shallow_size_of(ops); - for elem in self.iter() { - n += elem.size_of(ops); - } - n - } -} diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs new file mode 100644 index 0000000..6377b63 --- /dev/null +++ b/src/mallocsizeof.rs @@ -0,0 +1,24 @@ +use { + super::SmallVec, + malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}, +}; + +impl MallocShallowSizeOf for SmallVec { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if self.spilled() { + unsafe { ops.malloc_size_of(self.as_ptr()) } + } else { + 0 + } + } +} + +impl MallocSizeOf for SmallVec { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 58dbd64..f6fa459 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,9 +1,11 @@ -use super::allocationerror::AllocationError; -use super::TaggedLen; -use alloc::alloc::Layout; -use core::mem::{ManuallyDrop, MaybeUninit}; -use core::ptr::copy_nonoverlapping; -use core::ptr::NonNull; +use { + super::{allocationerror::AllocationError, TaggedLen}, + alloc::alloc::Layout, + core::{ + mem::{ManuallyDrop, MaybeUninit}, + ptr::{copy_nonoverlapping, NonNull}, + }, +}; /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. diff --git a/src/references.rs b/src/references.rs index dd933f1..ddac847 100644 --- a/src/references.rs +++ b/src/references.rs @@ -1,5 +1,7 @@ -use super::SmallVec; -use core::borrow::{Borrow, BorrowMut}; +use { + super::SmallVec, + core::borrow::{Borrow, BorrowMut}, +}; impl core::ops::Deref for SmallVec { type Target = [T]; diff --git a/src/serde.rs b/src/serde.rs index 6f32365..0f7d7e8 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -1,9 +1,11 @@ -use super::SmallVec; -use core::marker::PhantomData; -use serde_core::{ - de::{SeqAccess, Visitor}, - ser::SerializeSeq, - Deserialize, Deserializer, Serialize, Serializer, +use { + super::SmallVec, + core::marker::PhantomData, + serde_core::{ + de::{SeqAccess, Visitor}, + ser::SerializeSeq, + Deserialize, Deserializer, Serialize, Serializer, + }, }; impl Serialize for SmallVec diff --git a/src/std.rs b/src/std.rs index 6a59b90..4e5cbae 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,7 +1,6 @@ extern crate std; -use super::SmallVec; -use std::io; +use {super::SmallVec, std::io}; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] diff --git a/src/tests.rs b/src/tests.rs index 0442e24..887651a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,12 +1,10 @@ extern crate std; -use crate::{smallvec, SmallVec}; -use alloc::borrow::ToOwned; -use alloc::boxed::Box; -use alloc::rc::Rc; -use alloc::{vec, vec::Vec}; -use core::hash::Hasher; -use core::iter::FromIterator; +use { + crate::{smallvec, SmallVec}, + alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec::Vec}, + core::{hash::Hasher, iter::FromIterator}, +}; #[test] pub fn test_zero() { @@ -287,7 +285,7 @@ fn test_truncate() { #[test] fn test_truncate_references() { - let mut v = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut v = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]); let mut i = 8; let mut v: SmallVec<&mut u8, 8> = v.iter_mut().collect(); @@ -456,8 +454,7 @@ fn test_ord() { #[test] fn test_hash() { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hash; + use std::{collections::hash_map::DefaultHasher, hash::Hash}; fn hash(value: impl Hash) -> u64 { let mut hasher = DefaultHasher::new(); @@ -537,17 +534,17 @@ fn test_from() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); - let vec = vec![]; + let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = vec![1, 2, 3, 4, 5]; + let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); - let vec = vec![1, 2, 3, 4, 5]; + let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); @@ -559,7 +556,7 @@ fn test_from() { let array = [99; 128]; let small_vec: SmallVec = SmallVec::from(array); - assert_eq!(&*small_vec, vec![99u8; 128].as_slice()); + assert_eq!(&*small_vec, Vec::from([99u8; 128]).as_slice()); drop(small_vec); #[derive(PartialEq, Eq, Debug)] @@ -569,14 +566,14 @@ fn test_from() { assert_eq!(&*small_vec, &[NoClone(42)]); drop(small_vec); - let vec = vec![NoClone(42)]; + let vec = Vec::from([NoClone(42)]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[NoClone(42)]); drop(small_vec); let array = [1; 128]; let small_vec: SmallVec = SmallVec::from(array); - assert_eq!(&*small_vec, vec![1; 128].as_slice()); + assert_eq!(&*small_vec, Vec::from([1; 128]).as_slice()); drop(small_vec); let array = [99]; @@ -656,7 +653,7 @@ fn shrink_to_fit_unspill() { #[test] fn shrink_after_from_empty_vec() { - let mut v = SmallVec::::from_vec(vec![]); + let mut v = SmallVec::::from_vec(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } @@ -664,10 +661,10 @@ fn shrink_after_from_empty_vec() { #[test] fn test_into_vec() { let vec = SmallVec::::from_iter(0..2); - assert_eq!(vec.into_vec(), vec![0, 1]); + assert_eq!(vec.into_vec(), Vec::from([0, 1])); let vec = SmallVec::::from_iter(0..3); - assert_eq!(vec.into_vec(), vec![0, 1, 2]); + assert_eq!(vec.into_vec(), Vec::from([0, 1, 2])); } #[test] @@ -684,32 +681,32 @@ fn test_into_inner() { #[test] fn test_from_vec() { - let vec = vec![]; + let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = vec![]; + let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = vec![1]; + let vec = Vec::from([1]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1]); drop(small_vec); - let vec = vec![1, 2, 3]; + let vec = Vec::from([1, 2, 3]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3]); drop(small_vec); - let vec = vec![1, 2, 3, 4, 5]; + let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); - let vec = vec![1, 2, 3, 4, 5]; + let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); From ae1239502d988c4072a191829d0aee2adcd6fbaf Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 14:10:21 +0200 Subject: [PATCH 07/15] refactor: conversions file --- benches/bench.rs | 42 ------ rustfmt.toml | 8 +- src/allocationerror.rs | 3 - src/bytes.rs | 11 -- src/comparisons.rs | 8 - src/conversions.rs | 71 +++++++++ src/lib.rs | 330 +---------------------------------------- src/mallocsizeof.rs | 2 - src/rawsmallvec.rs | 13 -- src/references.rs | 6 - src/serde.rs | 8 - src/std.rs | 4 - src/taggedlen.rs | 7 - src/tests.rs | 165 --------------------- tests/macro.rs | 3 - 15 files changed, 79 insertions(+), 602 deletions(-) create mode 100644 src/conversions.rs diff --git a/benches/bench.rs b/benches/bench.rs index 0320449..3eced39 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,16 +1,12 @@ #![feature(test)] #![allow(deprecated)] - extern crate test; - use { smallvec::{smallvec, SmallVec}, test::Bencher, }; - const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; - trait Vector: for<'a> From<&'a [T]> + Extend { fn new() -> Self; fn push(&mut self, val: T); @@ -21,75 +17,58 @@ trait Vector: for<'a> From<&'a [T]> + Extend { fn from_elems(val: &[T]) -> Self; fn extend_from_slice(&mut self, other: &[T]); } - impl Vector for Vec { fn new() -> Self { Self::with_capacity(VEC_SIZE) } - fn push(&mut self, val: T) { self.push(val) } - fn pop(&mut self) -> Option { self.pop() } - fn remove(&mut self, p: usize) -> T { self.remove(p) } - fn insert(&mut self, n: usize, val: T) { self.insert(n, val) } - fn from_elem(val: T, n: usize) -> Self { vec![val; n] } - fn from_elems(val: &[T]) -> Self { val.to_owned() } - fn extend_from_slice(&mut self, other: &[T]) { Vec::extend_from_slice(self, other) } } - impl Vector for SmallVec { fn new() -> Self { Self::new() } - fn push(&mut self, val: T) { self.push(val) } - fn pop(&mut self) -> Option { self.pop() } - fn remove(&mut self, p: usize) -> T { self.remove(p) } - fn insert(&mut self, n: usize, val: T) { self.insert(n, val) } - fn from_elem(val: T, n: usize) -> Self { smallvec![val; n] } - fn from_elems(val: &[T]) -> Self { SmallVec::from(val) } - fn extend_from_slice(&mut self, other: &[T]) { SmallVec::extend_from_slice(self, other) } } - macro_rules! make_benches { ($typ:ty { $($b_name:ident => $g_name:ident($($args:expr),*),)* }) => { $( @@ -100,7 +79,6 @@ macro_rules! make_benches { )* } } - make_benches! { SmallVec { bench_push => gen_push(SPILLED_SIZE as _), @@ -126,7 +104,6 @@ make_benches! { bench_pushpop => gen_pushpop(), } } - make_benches! { Vec { bench_push_vec => gen_push(SPILLED_SIZE as _), @@ -152,13 +129,11 @@ make_benches! { bench_pushpop_vec => gen_pushpop(), } } - fn gen_push>(n: u64, b: &mut Bencher) { #[inline(never)] fn push_noinline>(vec: &mut V, x: u64) { vec.push(x); } - b.iter(|| { let mut vec = V::new(); for x in 0..n { @@ -167,13 +142,11 @@ fn gen_push>(n: u64, b: &mut Bencher) { vec }); } - fn gen_insert_push>(n: u64, b: &mut Bencher) { #[inline(never)] fn insert_push_noinline>(vec: &mut V, x: u64) { vec.insert(x as usize, x); } - b.iter(|| { let mut vec = V::new(); for x in 0..n { @@ -182,13 +155,11 @@ fn gen_insert_push>(n: u64, b: &mut Bencher) { vec }); } - fn gen_insert>(n: u64, b: &mut Bencher) { #[inline(never)] fn insert_noinline>(vec: &mut V, p: usize, x: u64) { vec.insert(p, x) } - b.iter(|| { let mut vec = V::new(); // Always insert at position 0 so that we are subject to shifts of @@ -200,22 +171,18 @@ fn gen_insert>(n: u64, b: &mut Bencher) { vec }); } - fn gen_remove>(n: usize, b: &mut Bencher) { #[inline(never)] fn remove_noinline>(vec: &mut V, p: usize) -> u64 { vec.remove(p) } - b.iter(|| { let mut vec = V::from_elem(0, n as _); - for _ in 0..n { remove_noinline(&mut vec, 0); } }); } - fn gen_extend>(n: u64, b: &mut Bencher) { b.iter(|| { let mut vec = V::new(); @@ -223,7 +190,6 @@ fn gen_extend>(n: u64, b: &mut Bencher) { vec }); } - fn gen_extend_filtered>(n: u64, b: &mut Bencher) { b.iter(|| { let mut vec = V::new(); @@ -231,7 +197,6 @@ fn gen_extend_filtered>(n: u64, b: &mut Bencher) { vec }); } - fn gen_from_iter>(n: u64, b: &mut Bencher) { let v: Vec = (0..n).collect(); b.iter(|| { @@ -239,7 +204,6 @@ fn gen_from_iter>(n: u64, b: &mut Bencher) { vec }); } - fn gen_from_slice>(n: u64, b: &mut Bencher) { let v: Vec = (0..n).collect(); b.iter(|| { @@ -247,7 +211,6 @@ fn gen_from_slice>(n: u64, b: &mut Bencher) { vec }); } - fn gen_extend_from_slice>(n: u64, b: &mut Bencher) { let v: Vec = (0..n).collect(); b.iter(|| { @@ -256,14 +219,12 @@ fn gen_extend_from_slice>(n: u64, b: &mut Bencher) { vec }); } - fn gen_pushpop>(b: &mut Bencher) { #[inline(never)] fn pushpop_noinline>(vec: &mut V, x: u64) -> Option { vec.push(x); vec.pop() } - b.iter(|| { let mut vec = V::new(); for x in 0..SPILLED_SIZE as _ { @@ -272,14 +233,12 @@ fn gen_pushpop>(b: &mut Bencher) { vec }); } - fn gen_from_elem>(n: usize, b: &mut Bencher) { b.iter(|| { let vec = V::from_elem(42, n); vec }); } - #[bench] fn bench_macro_from_list(b: &mut Bencher) { b.iter(|| { @@ -291,7 +250,6 @@ fn bench_macro_from_list(b: &mut Bencher) { vec }); } - #[bench] fn bench_macro_from_list_vec(b: &mut Bencher) { b.iter(|| { diff --git a/rustfmt.toml b/rustfmt.toml index 3e05b31..6643b4d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,10 @@ wrap_comments = true imports_granularity = "One" group_imports = "One" -format_code_in_doc_comments = true \ No newline at end of file +format_code_in_doc_comments = true +match_arm_blocks = false +blank_lines_lower_bound = 0 +blank_lines_upper_bound = 0 +condense_wildcard_suffixes = true +error_on_unformatted = true +error_on_line_overflow = true \ No newline at end of file diff --git a/src/allocationerror.rs b/src/allocationerror.rs index 8c657a0..c28f38c 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -5,7 +5,6 @@ use { fmt::{Display, Formatter, Result as Format}, }, }; - /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum AllocationError { @@ -17,11 +16,9 @@ pub enum AllocationError { layout: Layout, }, } - impl Display for AllocationError { fn fmt(&self, f: &mut Formatter) -> Format { write!(f, "Allocation error: {:?}", self) } } - impl Error for AllocationError {} diff --git a/src/bytes.rs b/src/bytes.rs index 71dd237..11f7fbc 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2,43 +2,35 @@ use { super::SmallVec, bytes::{buf::UninitSlice, BufMut}, }; - unsafe impl BufMut for SmallVec { #[inline] fn remaining_mut(&self) -> usize { // A vector can never have more than isize::MAX bytes isize::MAX as usize - self.len() } - #[inline] unsafe fn advance_mut(&mut self, cnt: usize) { let len = self.len(); let remaining = self.capacity() - len; - if remaining < cnt { panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); } - // Addition will not overflow since the sum is at most the capacity. self.set_len(len + cnt); } - #[inline] fn chunk_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); // Grow the smallvec } - let cap = self.capacity(); let len = self.len(); - let ptr = self.as_mut_ptr(); // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be // valid for `cap - len` bytes. The subtraction will not underflow since // `len <= cap`. unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } } - // Specialize these methods so they can skip checking `remaining_mut` // and `advance_mut`. #[inline] @@ -48,7 +40,6 @@ unsafe impl BufMut for SmallVec { { // In case the src isn't contiguous, reserve upfront. self.reserve(src.remaining()); - while src.has_remaining() { let s = src.chunk(); let l = s.len(); @@ -56,12 +47,10 @@ unsafe impl BufMut for SmallVec { src.advance(l); } } - #[inline] fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } - #[inline] fn put_bytes(&mut self, val: u8, cnt: usize) { // If the addition overflows, then the `resize` will fail. diff --git a/src/comparisons.rs b/src/comparisons.rs index cf7ceba..f4ca1d3 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -1,5 +1,4 @@ use super::SmallVec; - impl PartialEq> for SmallVec where T: PartialEq, @@ -10,7 +9,6 @@ where } } impl Eq for SmallVec where T: Eq {} - impl PartialEq<[U; M]> for SmallVec where T: PartialEq, @@ -20,7 +18,6 @@ where self[..] == other[..] } } - impl PartialEq<&[U; M]> for SmallVec where T: PartialEq, @@ -30,7 +27,6 @@ where self[..] == other[..] } } - impl PartialEq<[U]> for SmallVec where T: PartialEq, @@ -40,7 +36,6 @@ where self[..] == other[..] } } - impl PartialEq<&[U]> for SmallVec where T: PartialEq, @@ -50,7 +45,6 @@ where self[..] == other[..] } } - impl PartialEq<&mut [U]> for SmallVec where T: PartialEq, @@ -60,7 +54,6 @@ where self[..] == other[..] } } - impl PartialOrd for SmallVec where T: PartialOrd, @@ -70,7 +63,6 @@ where self.as_slice().partial_cmp(other.as_slice()) } } - impl Ord for SmallVec where T: Ord, diff --git a/src/conversions.rs b/src/conversions.rs new file mode 100644 index 0000000..18da6b4 --- /dev/null +++ b/src/conversions.rs @@ -0,0 +1,71 @@ +#[cfg(feature = "specialization")] +use super::spec_traits; +use { + super::SmallVec, + alloc::vec::Vec, + core::{mem::ManuallyDrop, ptr::copy_nonoverlapping}, +}; +impl From<&mut [T; M]> for SmallVec { + #[inline] + fn from(slice: &mut [T; M]) -> Self { + Self::from(slice as &[T]) + } +} +impl From<[T; M]> for SmallVec { + fn from(array: [T; M]) -> Self { + if M > N { + // If M > N, we'd have to heap allocate anyway, + // so delegate for Vec for the allocation. + Self::from(Vec::from(array)) + } else { + // M <= N + let mut this = Self::new(); + debug_assert!(M <= this.capacity()); + let array = ManuallyDrop::new(array); + // SAFETY: M <= this.capacity() + unsafe { + copy_nonoverlapping(array.as_ptr(), this.as_mut_ptr(), M); + this.set_len(M); + } + this + } + } +} +impl From> for SmallVec { + fn from(array: Vec) -> Self { + Self::from_vec(array) + } +} +impl From<&[T]> for SmallVec { + #[inline] + fn from(slice: &[T]) -> Self { + if slice.len() > Self::inline_size() { + // Standard Rust vectors are already specialized. + Self::from_vec(Vec::from(slice)) + } else { + // SAFETY: The precondition is checked in the initial comparison above. + unsafe { + #[cfg(feature = "specialization")] + { + >::spec_from(slice) + } + #[cfg(not(feature = "specialization"))] + { + Self::from_slice_fallback(slice) + } + } + } + } +} +impl From<&mut [T]> for SmallVec { + #[inline] + fn from(slice: &mut [T]) -> Self { + Self::from(slice as &[T]) + } +} +impl From<&[T; M]> for SmallVec { + #[inline] + fn from(slice: &[T; M]) -> Self { + Self::from(slice as &[T]) + } +} diff --git a/src/lib.rs b/src/lib.rs index df20a4c..a1eb5bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,14 +50,13 @@ #![cfg_attr(feature = "specialization", allow(incomplete_features))] #![cfg_attr(feature = "specialization", feature(specialization, trusted_len))] #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] - #[doc(hidden)] pub extern crate alloc; - mod allocationerror; #[cfg(feature = "bytes")] mod bytes; mod comparisons; +mod conversions; #[cfg(feature = "malloc_size_of")] mod mallocsizeof; mod rawsmallvec; @@ -69,7 +68,6 @@ mod std; mod taggedlen; #[cfg(test)] mod tests; - use { alloc::{alloc::Layout, boxed::Box, vec::Vec}, allocationerror::AllocationError, @@ -85,7 +83,6 @@ use { pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[cfg(not(feature = "internals"))] use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; - #[inline] fn infallible(result: Result) -> T { match result { @@ -94,7 +91,6 @@ fn infallible(result: Result) -> T { Err(AllocationError::Failure { layout }) => alloc::alloc::handle_alloc_error(layout), } } - #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -103,7 +99,6 @@ where R: core::ops::RangeBounds, { let len = bounds.end; - let start = match range.start_bound() { core::ops::Bound::Included(&start) => start, core::ops::Bound::Excluded(start) => start @@ -111,7 +106,6 @@ where .unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")), core::ops::Bound::Unbounded => 0, }; - let end = match range.end_bound() { core::ops::Bound::Included(end) => end .checked_add(1) @@ -119,34 +113,28 @@ where core::ops::Bound::Excluded(&end) => end, core::ops::Bound::Unbounded => len, }; - if start > end { panic!("slice index starts at {start} but ends at {end}"); } if end > len { panic!("range end index {end} out of range for slice of length {len}"); } - core::ops::Range { start, end } } - #[repr(C)] pub struct SmallVec { len: TaggedLen, raw: RawSmallVec, _marker: PhantomData, } - unsafe impl Send for SmallVec {} unsafe impl Sync for SmallVec {} - impl Default for SmallVec { #[inline] fn default() -> Self { Self::new() } } - /// An iterator that removes the items from a `SmallVec` and yields them by /// value. /// @@ -166,10 +154,8 @@ pub struct Drain<'a, T: 'a, const N: usize> { iter: core::slice::Iter<'a, T>, vec: core::ptr::NonNull>, } - impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { type Item = T; - #[inline] fn next(&mut self) -> Option { // SAFETY: we shrunk the length of the vector so it no longer owns these items, @@ -178,13 +164,11 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { .next() .map(|reference| unsafe { core::ptr::read(reference) }) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } - impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { #[inline] fn next_back(&mut self) -> Option { @@ -194,21 +178,17 @@ impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { .map(|reference| unsafe { core::ptr::read(reference) }) } } - impl ExactSizeIterator for Drain<'_, T, N> { #[inline] fn len(&self) -> usize { self.iter.len() } } - impl core::iter::FusedIterator for Drain<'_, T, N> {} - impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { fn drop(&mut self) { /// Moves back the un-`Drain`ed elements to restore the original `Vec`. struct DropGuard<'r, 'a, T, const N: usize>(&'r mut Drain<'a, T, N>); - impl<'r, 'a, T, const N: usize> Drop for DropGuard<'r, 'a, T, N> { fn drop(&mut self) { if self.0.tail_len > 0 { @@ -228,12 +208,9 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { } } } - let iter = core::mem::take(&mut self.iter); let drop_len = iter.len(); - let mut vec = self.vec; - if SmallVec::::IS_ZST { // ZSTs have no identity, so we don't need to move them around, we only need to // drop the correct amount. this can be achieved by manipulating the @@ -244,24 +221,19 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { vec.set_len(old_len + drop_len + self.tail_len); vec.truncate(old_len + self.tail_len); } - return; } - // ensure elements are moved back into their appropriate places, even when // drop_in_place panics let _guard = DropGuard(self); - if drop_len == 0 { return; } - // as_slice() must only be called when iter.len() is > 0 because // it also gets touched by vec::Splice which may turn it into a dangling pointer // which would make it and the vec pointer point to different allocations which // would lead to invalid pointer arithmetic below. let drop_ptr = iter.as_slice().as_ptr(); - unsafe { // drop_ptr comes from a slice::Iter which only gives us a &[T] but for // drop_in_place a pointer with mutable provenance is necessary. @@ -277,13 +249,11 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { } } } - impl Drain<'_, T, N> { #[must_use] pub fn as_slice(&self) -> &[T] { self.iter.as_slice() } - /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the @@ -299,7 +269,6 @@ impl Drain<'_, T, N> { range_end - range_start, ) }; - for place in range_slice { if let Some(new_item) = replace_with.next() { unsafe { core::ptr::write(place, new_item) }; @@ -310,19 +279,16 @@ impl Drain<'_, T, N> { } true } - /// Makes room for inserting more elements before the tail. #[track_caller] unsafe fn move_tail(&mut self, additional: usize) { let vec = unsafe { self.vec.as_mut() }; let len = self.tail_start + self.tail_len; - // Test let old_len = vec.len(); vec.set_len(len); vec.reserve(additional); vec.set_len(old_len); - let new_tail_start = self.tail_start + additional; unsafe { let src = vec.as_ptr().add(self.tail_start); @@ -332,7 +298,6 @@ impl Drain<'_, T, N> { self.tail_start = new_tail_start; } } - /// An iterator which uses a closure to determine if an element should be /// removed. /// @@ -356,7 +321,6 @@ where /// The filter test predicate. pred: F, } - impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -368,13 +332,11 @@ where .finish() } } - impl Iterator for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, { type Item = T; - fn next(&mut self) -> Option { unsafe { while self.idx < self.end { @@ -398,12 +360,10 @@ where None } } - fn size_hint(&self) -> (usize, Option) { (0, Some(self.end - self.idx)) } } - impl Drop for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -427,12 +387,10 @@ where } } } - pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, replace_with: I, } - impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: Debug + Iterator + 'a, @@ -442,27 +400,21 @@ where f.debug_tuple("Splice").field(&self.drain).finish() } } - impl Iterator for Splice<'_, I, N> { type Item = I::Item; - fn next(&mut self) -> Option { self.drain.next() } - fn size_hint(&self) -> (usize, Option) { self.drain.size_hint() } } - impl DoubleEndedIterator for Splice<'_, I, N> { fn next_back(&mut self) -> Option { self.drain.next_back() } } - impl ExactSizeIterator for Splice<'_, I, N> {} - impl Drop for Splice<'_, I, N> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -472,18 +424,15 @@ impl Drop for Splice<'_, I, N> { // deallocated memory, so that Drain::drop is still allowed to call // iter.len(), otherwise it would break the ptr.sub_ptr contract. self.drain.iter = [].iter(); - unsafe { if self.drain.tail_len == 0 { self.drain.vec.as_mut().extend(self.replace_with.by_ref()); return; } - // First fill the range left by drain(). if !self.drain.fill(&mut self.replace_with) { return; } - // There may be more elements. Use the lower bound as an estimate. // FIXME: Is the upper bound a better guess? Or something else? let (lower_bound, _upper_bound) = self.replace_with.size_hint(); @@ -493,7 +442,6 @@ impl Drop for Splice<'_, I, N> { return; } } - // Collect any remaining elements. let mut collected = self .replace_with @@ -512,7 +460,6 @@ impl Drop for Splice<'_, I, N> { // `vec.len`. } } - /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. @@ -529,12 +476,10 @@ pub struct IntoIter { end: TaggedLen, _marker: PhantomData, } - // SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) // an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. unsafe impl Send for IntoIter where T: Send {} unsafe impl Sync for IntoIter where T: Sync {} - impl IntoIter { #[inline] const fn as_ptr(&self) -> *const T { @@ -546,7 +491,6 @@ impl IntoIter { self.raw.as_ptr_inline() } } - #[inline] const fn as_mut_ptr(&mut self) -> *mut T { let on_heap = self.end.on_heap(); @@ -557,7 +501,6 @@ impl IntoIter { self.raw.as_mut_ptr_inline() } } - #[inline] pub const fn as_slice(&self) -> &[T] { // SAFETY: The members in self.begin..self.end.value() are all initialized @@ -567,7 +510,6 @@ impl IntoIter { core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) } } - #[inline] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: see above @@ -577,10 +519,8 @@ impl IntoIter { } } } - impl Iterator for IntoIter { type Item = T; - #[inline] fn next(&mut self) -> Option { if self.begin == self.end.value() { @@ -595,14 +535,12 @@ impl Iterator for IntoIter { } } } - #[inline] fn size_hint(&self) -> (usize, Option) { let size = self.end.value() - self.begin; (size, Some(size)) } } - impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { @@ -624,7 +562,6 @@ impl DoubleEndedIterator for IntoIter { } impl ExactSizeIterator for IntoIter {} impl core::iter::FusedIterator for IntoIter {} - impl SmallVec { #[inline] pub const fn new() -> SmallVec { @@ -634,7 +571,6 @@ impl SmallVec { _marker: PhantomData, } } - #[inline] pub fn with_capacity(capacity: usize) -> Self { let mut this = Self::new(); @@ -643,28 +579,23 @@ impl SmallVec { } this } - #[inline] pub const fn from_buf(elements: [T; S]) -> Self { const { assert!(S <= N); } - // Although we create a new buffer, since S and N are known at compile time, // even with `-C opt-level=1`, it gets optimized as best as it could be. // (Checked with ) let mut buf: MaybeUninit<[T; N]> = MaybeUninit::uninit(); - // SAFETY: buf and elements do not overlap, are aligned and have space // for at least S elements since S <= N. // We will drop the elements only once since we do forget(elements). unsafe { copy_nonoverlapping(elements.as_ptr(), buf.as_mut_ptr() as *mut T, S); } - // `elements` have been moved into buf and will be dropped by SmallVec core::mem::forget(elements); - // SAFETY: all the members in 0..S are initialized Self { len: TaggedLen::new(S, false), @@ -672,7 +603,6 @@ impl SmallVec { _marker: PhantomData, } } - #[inline] pub fn from_buf_and_len(buf: [T; N], len: usize) -> Self { assert!(len <= N); @@ -688,17 +618,14 @@ impl SmallVec { // allocation let remainder_ptr = vec.raw.as_mut_ptr_inline().add(len); let remainder_len = N - len; - // SAFETY: the values are initialized, so dropping them here is fine. core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( remainder_ptr, remainder_len, )); } - vec } - /// Constructs a new `SmallVec` on the stack from an A without copying /// elements. Also sets the length. The user is responsible for ensuring /// that `len <= A::size()`. @@ -707,10 +634,8 @@ impl SmallVec { /// /// ``` /// use {smallvec::SmallVec, std::mem::MaybeUninit}; - /// /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; /// let small_vec = unsafe { SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5) }; - /// /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` /// @@ -727,16 +652,13 @@ impl SmallVec { } } } - impl SmallVec { const IS_ZST: bool = size_of::() == 0; - #[inline] pub fn from_vec(vec: Vec) -> Self { if vec.capacity() == 0 { return Self::new(); } - if Self::IS_ZST { // "Move" elements to stack buffer. They're ZST so we don't actually have to do // anything. Just make sure they're not dropped. @@ -744,7 +666,6 @@ impl SmallVec { // memory is deallocated, if it needs to be. let mut vec = vec; let len = vec.len(); - // SAFETY: `0` is less than the vector's capacity. // old_len..new_len is an empty range. So there are no uninitialized elements unsafe { vec.set_len(0) }; @@ -760,7 +681,6 @@ impl SmallVec { // SAFETY: vec.capacity is not `0` (checked above), so the pointer // can not dangle and thus specifically cannot be null. let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; - Self { len: TaggedLen::new(len, true), raw: RawSmallVec::new_heap(ptr, cap), @@ -768,7 +688,6 @@ impl SmallVec { } } } - /// Sets the tag to be on the heap /// /// # Safety @@ -778,7 +697,6 @@ impl SmallVec { unsafe fn set_on_heap(&mut self) { self.len = TaggedLen::new(self.len(), true); } - /// Sets the tag to be inline /// /// # Safety @@ -788,7 +706,6 @@ impl SmallVec { unsafe fn set_inline(&mut self) { self.len = TaggedLen::new(self.len(), false); } - /// Sets the length of a vector. /// /// This will explicitly set the size of the vector, without actually @@ -805,7 +722,6 @@ impl SmallVec { let on_heap = self.len.on_heap(); self.len = TaggedLen::new(new_len, on_heap); } - #[inline] pub const fn inline_size() -> usize { if Self::IS_ZST { @@ -814,18 +730,15 @@ impl SmallVec { N } } - #[inline] pub const fn len(&self) -> usize { self.len.value() } - #[must_use] #[inline] pub const fn is_empty(&self) -> bool { self.len() == 0 } - #[inline] pub const fn capacity(&self) -> usize { if self.len.on_heap() { @@ -835,12 +748,10 @@ impl SmallVec { Self::inline_size() } } - #[inline] pub const fn spilled(&self) -> bool { self.len.on_heap() } - /// Splits the collection into two at the given index. /// /// Returns a newly allocated vector containing the elements in the range @@ -871,34 +782,27 @@ impl SmallVec { pub fn split_off(&mut self, at: usize) -> Self { let len = self.len(); assert!(at <= len); - let other_len = len - at; let mut other = Self::with_capacity(other_len); - // Unsafely `set_len` and copy items to `other`. unsafe { self.set_len(at); other.set_len(other_len); - core::ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other_len); } other } - pub fn drain(&mut self, range: R) -> Drain<'_, T, N> where R: core::ops::RangeBounds, { let len = self.len(); let core::ops::Range { start, end } = slice_range(range, ..len); - unsafe { // SAFETY: `start <= len` self.set_len(start); - // SAFETY: all the elements in `start..end` are initialized let range_slice = core::slice::from_raw_parts(self.as_ptr().add(start), end - start); - // SAFETY: all the elements in `end..len` are initialized Drain { tail_start: end, @@ -911,7 +815,6 @@ impl SmallVec { } } } - /// Creates an iterator which uses a closure to determine if element in the /// range should be removed. /// @@ -969,12 +872,10 @@ impl SmallVec { /// # use smallvec::SmallVec; /// let mut numbers: SmallVec = /// SmallVec::from(&[1i32, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); - /// /// let evens = numbers /// .extract_if(.., |x| *x % 2 == 0) /// .collect::>(); /// let odds = numbers; - /// /// assert_eq!(evens, SmallVec::::from(&[2i32, 4, 6, 8, 14])); /// assert_eq!( /// odds, @@ -1003,12 +904,10 @@ impl SmallVec { { let old_len = self.len(); let core::ops::Range { start, end } = slice_range(range, ..old_len); - // Guard against us getting leaked (leak amplification) unsafe { self.set_len(0); } - ExtractIf { vec: self, idx: start, @@ -1018,7 +917,6 @@ impl SmallVec { pred: filter, } } - pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> where R: core::ops::RangeBounds, @@ -1029,7 +927,6 @@ impl SmallVec { replace_with: replace_with.into_iter(), } } - #[inline] pub fn push(&mut self, value: T) { let len = self.len(); @@ -1043,7 +940,6 @@ impl SmallVec { unsafe { ptr.write(value) }; unsafe { self.set_len(len + 1) } } - #[inline] pub fn pop(&mut self) -> Option { if self.is_empty() { @@ -1059,7 +955,6 @@ impl SmallVec { Some(value) } } - #[inline] pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let last = self.last_mut()?; @@ -1069,7 +964,6 @@ impl SmallVec { None } } - #[inline] pub fn append(&mut self, other: &mut SmallVec) { // can't overflow since both are smaller than isize::MAX and 2 * isize::MAX < @@ -1080,7 +974,6 @@ impl SmallVec { if total_len > self.capacity() { self.reserve(other_len); } - // SAFETY: see `Self::push` let ptr = unsafe { self.as_mut_ptr().add(len) }; unsafe { other.set_len(0) } @@ -1089,25 +982,20 @@ impl SmallVec { unsafe { copy_nonoverlapping(other.as_ptr(), ptr, other_len) }; unsafe { self.set_len(total_len) } } - #[inline] pub fn grow(&mut self, new_capacity: usize) { infallible(self.try_grow(new_capacity)); } - #[cold] pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), AllocationError> { if Self::IS_ZST { return Ok(()); } - let len = self.len(); assert!(new_capacity >= len); - if new_capacity > Self::inline_size() { // SAFETY: we checked all the preconditions let result = unsafe { self.raw.try_grow_raw(self.len, new_capacity) }; - if result.is_ok() { // SAFETY: the allocation succeeded, so self.raw.heap is now active unsafe { self.set_on_heap() }; @@ -1120,7 +1008,6 @@ impl SmallVec { // SAFETY: heap member is active let (ptr, old_cap) = self.raw.heap; // inline member is now active - // SAFETY: len <= new_capacity <= Self::inline_size() // so the copy is within bounds of the inline member copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), len); @@ -1135,7 +1022,6 @@ impl SmallVec { Ok(()) } } - #[inline] pub fn reserve(&mut self, additional: usize) { // can't overflow since len <= capacity @@ -1149,7 +1035,6 @@ impl SmallVec { self.grow(new_capacity); } } - #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), AllocationError> { if additional > self.capacity() - self.len() { @@ -1163,7 +1048,6 @@ impl SmallVec { Ok(()) } } - #[inline] pub fn reserve_exact(&mut self, additional: usize) { // can't overflow since len <= capacity @@ -1176,7 +1060,6 @@ impl SmallVec { self.grow(new_capacity); } } - #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), AllocationError> { if additional > self.capacity() - self.len() { @@ -1189,7 +1072,6 @@ impl SmallVec { Ok(()) } } - #[inline] pub fn shrink_to_fit(&mut self) { if !self.spilled() { @@ -1215,7 +1097,6 @@ impl SmallVec { unsafe { infallible(self.raw.try_grow_raw(self.len, len)) }; } } - #[inline] pub fn shrink_to(&mut self, min_capacity: usize) { if !self.spilled() { @@ -1247,7 +1128,6 @@ impl SmallVec { } } } - #[inline] pub fn truncate(&mut self, len: usize) { let old_len = self.len(); @@ -1263,7 +1143,6 @@ impl SmallVec { } } } - #[inline] pub fn swap_remove(&mut self, index: usize) -> T { let len = self.len(); @@ -1284,7 +1163,6 @@ impl SmallVec { value } } - #[inline] pub fn clear(&mut self) { // SAFETY: we set `len` to a smaller value @@ -1298,7 +1176,6 @@ impl SmallVec { )); } } - #[inline] pub fn remove(&mut self, index: usize) -> T { let len = self.len(); @@ -1318,7 +1195,6 @@ impl SmallVec { ith_item } } - #[inline] pub fn insert(&mut self, index: usize, value: T) { let len = self.len(); @@ -1335,12 +1211,10 @@ impl SmallVec { } // the element at `index` is now initialized ptr.add(index).write(value); - // SAFETY: all the elements are initialized self.set_len(len + 1); } } - #[inline] pub const fn as_slice(&self) -> &[T] { let len = self.len(); @@ -1348,7 +1222,6 @@ impl SmallVec { // SAFETY: all the elements in `..len` are initialized unsafe { core::slice::from_raw_parts(ptr, len) } } - #[inline] pub const fn as_mut_slice(&mut self) -> &mut [T] { let len = self.len(); @@ -1356,7 +1229,6 @@ impl SmallVec { // SAFETY: see above unsafe { core::slice::from_raw_parts_mut(ptr, len) } } - #[inline] pub const fn as_ptr(&self) -> *const T { if self.len.on_heap() { @@ -1366,7 +1238,6 @@ impl SmallVec { self.raw.as_ptr_inline() } } - #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { if self.len.on_heap() { @@ -1376,7 +1247,6 @@ impl SmallVec { self.raw.as_mut_ptr_inline() } } - #[inline] pub fn into_vec(self) -> Vec { let len = self.len(); @@ -1406,12 +1276,10 @@ impl SmallVec { } } } - #[inline] pub fn into_boxed_slice(self) -> Box<[T]> { self.into_vec().into_boxed_slice() } - #[inline] pub fn into_inner(self) -> Result<[T; N], Self> { if self.len() != N { @@ -1428,12 +1296,10 @@ impl SmallVec { unsafe { Ok(ptr.read()) } } } - #[inline] pub fn retain bool>(&mut self, mut f: F) { self.retain_mut(|elem| f(elem)) } - #[inline] pub fn retain_mut bool>(&mut self, mut f: F) { let mut del = 0; @@ -1452,7 +1318,6 @@ impl SmallVec { } self.truncate(len - del); } - #[inline] pub fn dedup(&mut self) where @@ -1460,7 +1325,6 @@ impl SmallVec { { self.dedup_by(|a, b| a == b); } - #[inline] pub fn dedup_by_key(&mut self, mut key: F) where @@ -1469,7 +1333,6 @@ impl SmallVec { { self.dedup_by(|a, b| key(a) == key(b)); } - #[inline] pub fn dedup_by(&mut self, mut same_bucket: F) where @@ -1481,10 +1344,8 @@ impl SmallVec { if len <= 1 { return; } - let ptr = self.as_mut_ptr(); let mut w: usize = 1; - unsafe { for r in 1..len { let p_r = ptr.add(r); @@ -1498,10 +1359,8 @@ impl SmallVec { } } } - self.truncate(w); } - pub fn resize_with(&mut self, new_len: usize, f: F) where F: FnMut() -> T, @@ -1518,7 +1377,6 @@ impl SmallVec { self.truncate(new_len); } } - pub fn leak<'a>(self) -> &'a mut [T] { if !self.spilled() { panic!( @@ -1528,7 +1386,6 @@ impl SmallVec { let mut me = ManuallyDrop::new(self); unsafe { core::slice::from_raw_parts_mut(me.as_mut_ptr(), me.len()) } } - /// Returns the remaining spare capacity of the vector as a slice of /// `MaybeUninit`. /// @@ -1544,7 +1401,6 @@ impl SmallVec { ) } } - /// Creates a `SmallVec` directly from the raw components of another /// `SmallVec`. /// @@ -1578,20 +1434,16 @@ impl SmallVec { /// /// ``` /// use smallvec::{smallvec, SmallVec}; - /// /// let mut v: SmallVec<_, 1> = smallvec![1, 2, 3]; - /// /// // Pull out the important parts of `v`. /// let p = v.as_mut_ptr(); /// let len = v.len(); /// let cap = v.capacity(); /// let spilled = v.spilled(); - /// /// unsafe { /// // Forget all about `v`. The heap allocation that stored the /// // three values won't be deallocated. /// std::mem::forget(v); - /// /// // Overwrite memory with [4, 5, 6]. /// // /// // This is only safe if `spilled` is true! Otherwise, we are @@ -1601,7 +1453,6 @@ impl SmallVec { /// for i in 0..len { /// std::ptr::write(p.add(i), 4 + i); /// } - /// /// // Put everything back together into a SmallVec with a different /// // amount of inline storage, but which is still less than `cap`. /// let rebuilt = SmallVec::<_, 2>::from_raw_parts(p, len, cap); @@ -1611,14 +1462,12 @@ impl SmallVec { #[inline] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> SmallVec { assert!(!Self::IS_ZST); - // SAFETY: We require caller to provide same ptr as we alloc // and we never alloc null pointer. let ptr = unsafe { debug_assert!(!ptr.is_null(), "Called `from_raw_parts` with null pointer."); NonNull::new_unchecked(ptr) }; - SmallVec { len: TaggedLen::new(length, true), raw: RawSmallVec::new_heap(ptr, capacity), @@ -1626,7 +1475,6 @@ impl SmallVec { } } } - impl SmallVec { #[inline] pub fn resize(&mut self, len: usize, value: T) { @@ -1637,19 +1485,16 @@ impl SmallVec { self.truncate(len); } } - #[inline] pub fn extend_from_slice(&mut self, other: &[T]) { self.extend(other.iter()) } - pub fn extend_from_within(&mut self, src: R) where R: core::ops::RangeBounds, { let src = slice_range(src, ..self.len()); self.reserve(src.len()); - // SAFETY: The call to `reserve` ensures that the capacity is large enough. // The range is within bounds through the use of `core::slice::range`. unsafe { @@ -1657,14 +1502,12 @@ impl SmallVec { { >::spec_extend_from_within(self, src); } - #[cfg(not(feature = "specialization"))] { self.extend_from_within_fallback(src); } } } - #[inline] pub fn extend_from_slice_copy(&mut self, other: &[T]) where @@ -1672,10 +1515,8 @@ impl SmallVec { { let len = other.len(); let src = other.as_ptr(); - let l = self.len(); self.reserve(len); - // SAFETY: Additional memory has been reserved, // therefore the pointer access is valid. unsafe { @@ -1684,7 +1525,6 @@ impl SmallVec { self.set_len(l + len); } } - pub fn extend_from_within_copy(&mut self, src: R) where R: core::ops::RangeBounds, @@ -1694,7 +1534,6 @@ impl SmallVec { let core::ops::Range { start, end } = src; let len = end - start; self.reserve(len); - // SAFETY: The call to `reserve` ensures that the capacity is large enough. // The range is within bounds through the use of `core::slice::range`. unsafe { @@ -1704,7 +1543,6 @@ impl SmallVec { self.set_len(l + len); } } - pub fn insert_from_slice_copy(&mut self, index: usize, other: &[T]) where T: Copy, @@ -1721,12 +1559,10 @@ impl SmallVec { copy(ith_ptr, shifted_ptr, l - index); // elements at `index..index + other_len` are now initialized copy_nonoverlapping(other.as_ptr(), ith_ptr, len); - // SAFETY: all the elements are initialized self.set_len(l + len); } } - /// A function for creating [`SmallVec`] values out of slices /// for types with the [`Copy`] trait. pub fn from_slice_copy(slice: &[T]) -> Self @@ -1736,18 +1572,15 @@ impl SmallVec { let src = slice.as_ptr(); let len = slice.len(); let mut result = Self::with_capacity(len); - // SAFETY: By using `with_capacity`, the pointer will point to valid memory. unsafe { let dst = result.as_mut_ptr(); copy_nonoverlapping(src, dst, len); result.set_len(len); } - result } } - struct DropGuard { ptr: *mut T, len: usize, @@ -1760,13 +1593,11 @@ impl Drop for DropGuard { } } } - struct DropDealloc { ptr: NonNull, size_bytes: usize, align: usize, } - impl Drop for DropDealloc { #[inline] fn drop(&mut self) { @@ -1780,7 +1611,6 @@ impl Drop for DropDealloc { } } } - #[cfg(feature = "may_dangle")] unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { fn drop(&mut self) { @@ -1804,7 +1634,6 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { } } } - #[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { @@ -1827,7 +1656,6 @@ impl Drop for SmallVec { } } } - impl Drop for IntoIter { fn drop(&mut self) { // SAFETY: see above @@ -1850,7 +1678,6 @@ impl Drop for IntoIter { } } } - /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using thís function. #[doc(hidden)] @@ -1866,7 +1693,6 @@ pub fn from_elem(elem: T, n: usize) -> SmallVec // SAFETY: The precondition is checked in the initial comparison above. unsafe { as spec_traits::SpecFromElem>::spec_from_elem(elem, n) } } - #[cfg(not(feature = "specialization"))] { // SAFETY: The precondition is checked in the initial comparison above. @@ -1874,11 +1700,9 @@ pub fn from_elem(elem: T, n: usize) -> SmallVec } } } - #[cfg(feature = "specialization")] mod spec_traits { use super::*; - /// A trait for specializing the implementation of [`from_elem`]. /// /// [`from_elem`]: crate::from_elem @@ -1891,7 +1715,6 @@ mod spec_traits { /// The caller must ensure that `n <= Self::inline_size()`. unsafe fn spec_from_elem(elem: T, n: usize) -> Self; } - impl SpecFromElem for SmallVec { #[inline] default unsafe fn spec_from_elem(elem: T, n: usize) -> Self { @@ -1899,14 +1722,11 @@ mod spec_traits { unsafe { SmallVec::from_elem_fallback(elem, n) } } } - impl SpecFromElem for SmallVec { unsafe fn spec_from_elem(elem: T, n: usize) -> Self { let mut result = Self::new(); - if n > 0 { let ptr = result.raw.as_mut_ptr_inline(); - // SAFETY: The caller ensures that the first `n` // is smaller than the inline size. unsafe { @@ -1915,17 +1735,14 @@ mod spec_traits { } } } - // SAFETY: The first `n` elements of the vector // have been initialized in the loop above. unsafe { result.set_len(n); } - result } } - /// A trait for specializing the implementations of [`Extend`] and /// [`extend_from_slice`]. /// @@ -1933,7 +1750,6 @@ mod spec_traits { pub(crate) trait SpecExtend { fn spec_extend(&mut self, iter: I); } - impl SpecExtend for SmallVec where I: Iterator, @@ -1943,7 +1759,6 @@ mod spec_traits { self.extend_fallback(iter); } } - impl SpecExtend for SmallVec where I: core::iter::TrustedLen, @@ -1953,7 +1768,6 @@ mod spec_traits { panic!("capacity overflow") }; self.reserve(additional); - // SAFETY: A `TrustedLen` iterator provides accurate information // about its size, which was used to reserve additional memory. // This ensures that the access operations inside the loop always @@ -1962,27 +1776,22 @@ mod spec_traits { let len = self.len(); let ptr = self.as_mut_ptr().add(len); let mut guard = DropGuard { ptr, len: 0 }; - for x in iter { ptr.add(guard.len).write(x); guard.len += 1; } - // The elements have been initialized in the loop above. self.set_len(len + guard.len); core::mem::forget(guard); } } } - impl SpecExtend> for SmallVec { fn spec_extend(&mut self, mut iter: IntoIter) { let slice = iter.as_slice(); let len = slice.len(); let old_len = self.len(); - self.reserve(len); - // SAFETY: Additional memory has been reserved above. // Therefore, the copy operates on valid memory. unsafe { @@ -1990,17 +1799,14 @@ mod spec_traits { let src = slice.as_ptr(); copy_nonoverlapping(src, dst, len); } - // SAFETY: The elements were initialized above. unsafe { self.set_len(old_len + len); } - // Mark the iterator as fully consumed. iter.begin = iter.end.value(); } } - impl<'a, T: 'a, const N: usize, I> SpecExtend<&'a T, I> for SmallVec where I: Iterator, @@ -2011,7 +1817,6 @@ mod spec_traits { self.spec_extend(iterator.cloned()) } } - impl<'a, T: 'a, const N: usize> SpecExtend<&'a T, core::slice::Iter<'a, T>> for SmallVec where T: Copy, @@ -2020,9 +1825,7 @@ mod spec_traits { let slice = iter.as_slice(); let len = slice.len(); let old_len = self.len(); - self.reserve(len); - // SAFETY: Additional memory has been reserved above. // Therefore, the copy operates on valid memory. unsafe { @@ -2030,14 +1833,12 @@ mod spec_traits { let src = slice.as_ptr(); copy_nonoverlapping(src, dst, len); } - // SAFETY: The elements were initialized above. unsafe { self.set_len(old_len + len); } } } - /// A trait for specializing the implementation of [`extend_from_within`]. /// /// [`extend_from_within`]: crate::SmallVec::extend_from_within @@ -2053,7 +1854,6 @@ mod spec_traits { /// [`extend_from_within`]: SmallVec::extend_from_within unsafe fn spec_extend_from_within(&mut self, src: core::ops::Range); } - impl SpecExtendFromWithin for SmallVec { default unsafe fn spec_extend_from_within(&mut self, src: core::ops::Range) { // SAFETY: Safety conditions are identical. @@ -2062,14 +1862,11 @@ mod spec_traits { } } } - impl SpecExtendFromWithin for SmallVec { unsafe fn spec_extend_from_within(&mut self, src: core::ops::Range) { let old_len = self.len(); - let start = src.start; let len = src.len(); - // SAFETY: The caller ensures that the vector has spare capacity // for at least `src.len()` elements. This is also the amount of memory // accessed when the data is copied. @@ -2079,21 +1876,18 @@ mod spec_traits { let src = ptr.add(start); copy_nonoverlapping(src, dst, len); } - // SAFETY: The elements were initialized above. unsafe { self.set_len(old_len + len); } } } - /// A trait for specializing the implementation of [`FromIterator`]. /// /// [`clone_from`]: Clone::clone_from pub(crate) trait SpecFromIterator { fn spec_from_iter(iter: I) -> Self; } - impl SpecFromIterator for SmallVec where I: Iterator, @@ -2103,7 +1897,6 @@ mod spec_traits { Self::from_iter_fallback(iter) } } - impl SpecFromIterator for SmallVec where I: core::iter::TrustedLen, @@ -2122,28 +1915,24 @@ mod spec_traits { v } } - /// A trait for specializing the implementation of [`clone_from`]. /// /// [`clone_from`]: Clone::clone_from pub(crate) trait SpecCloneFrom { fn spec_clone_from(&mut self, source: &[T]); } - impl SpecCloneFrom for SmallVec { #[inline] default fn spec_clone_from(&mut self, source: &[T]) { self.clone_from_fallback(source); } } - impl SpecCloneFrom for SmallVec { fn spec_clone_from(&mut self, source: &[T]) { self.clear(); self.extend_from_slice(source); } } - /// A trait for specializing the implementation of [`From`] /// with the source type being slices. pub(crate) trait SpecFromSlice { @@ -2155,38 +1944,31 @@ mod spec_traits { /// The caller must ensure that `slice.len() <= Self::inline_size()`. unsafe fn spec_from(slice: &[T]) -> Self; } - impl SpecFromSlice for SmallVec { default unsafe fn spec_from(slice: &[T]) -> Self { // SAFETY: Safety conditions are identical. unsafe { Self::from_slice_fallback(slice) } } } - impl SpecFromSlice for SmallVec { unsafe fn spec_from(slice: &[T]) -> Self { let mut v = Self::new(); - let src = slice.as_ptr(); let len = slice.len(); let dst = v.as_mut_ptr(); - // SAFETY: The caller ensures that the slice length is smaller // than or equal to the inline length. unsafe { copy_nonoverlapping(src, dst, len); } - // SAFETY: The elements were initialized above. unsafe { v.set_len(len); } - v } } } - /// Fallback functions for various specialized methods. These are kept in /// a separate implementation block for easy access whenever specialization is /// disabled. @@ -2202,11 +1984,9 @@ impl SmallVec { T: Clone, { let mut result = Self::new(); - if n > 0 { let ptr = result.raw.as_mut_ptr_inline(); let mut guard = DropGuard { ptr, len: 0 }; - // SAFETY: The caller ensures that the first `n` // is smaller than the inline size. unsafe { @@ -2218,16 +1998,13 @@ impl SmallVec { ptr.add(n - 1).write(elem); } } - // SAFETY: The first `n` elements of the vector // have been initialized in the loop above. unsafe { result.set_len(n); } - result } - fn extend_fallback(&mut self, iter: I) where I: IntoIterator, @@ -2239,7 +2016,6 @@ impl SmallVec { self.push(x); } } - /// Main worker for [`extend_from_within`]. /// /// # Safety @@ -2254,10 +2030,8 @@ impl SmallVec { T: Clone, { let old_len = self.len(); - let start = src.start; let len = src.len(); - // SAFETY: The caller ensures that the vector has spare capacity // for at least `src.len()` elements. This implies that the loop // operates on valid memory. @@ -2265,7 +2039,6 @@ impl SmallVec { let ptr = self.as_mut_ptr(); let dst = ptr.add(old_len); let src = ptr.add(start); - let mut guard = DropGuard { ptr: dst, len: 0 }; for i in 0..len { let val = (*src.add(i)).clone(); @@ -2274,13 +2047,11 @@ impl SmallVec { } core::mem::forget(guard); } - // SAFETY: The elements were initialized in the loop above. unsafe { self.set_len(old_len + len); } } - fn from_iter_fallback(iter: I) -> Self where I: Iterator, @@ -2292,25 +2063,20 @@ impl SmallVec { } v } - fn clone_from_fallback(&mut self, source: &[T]) where T: Clone, { // Inspired from `impl Clone for Vec`. - // Drop anything that will not be overwritten. self.truncate(source.len()); - // SAFETY: self.len <= other.len due to the truncate above, so the // slices here are always in-bounds. let (init, tail) = unsafe { source.split_at_unchecked(self.len()) }; - // Reuse the contained values' allocations/resources. self.clone_from_slice(init); self.extend(tail.iter().cloned()); } - /// Creates a `SmallVec` value based on the contents of `slice`. /// This will use the inline storage, not the heap. /// @@ -2322,11 +2088,9 @@ impl SmallVec { T: Clone, { let mut v = Self::new(); - let src = slice.as_ptr(); let len = slice.len(); let dst = v.as_mut_ptr(); - // SAFETY: The caller ensures that the slice length is smaller // than or equal to the inline length. unsafe { @@ -2338,114 +2102,36 @@ impl SmallVec { } core::mem::forget(guard); } - // SAFETY: The elements were initialized in the loop above. unsafe { v.set_len(len); } - v } } - -impl From<&[T]> for SmallVec { - #[inline] - fn from(slice: &[T]) -> Self { - if slice.len() > Self::inline_size() { - // Standard Rust vectors are already specialized. - Self::from_vec(Vec::from(slice)) - } else { - // SAFETY: The precondition is checked in the initial comparison above. - unsafe { - #[cfg(feature = "specialization")] - { - >::spec_from(slice) - } - - #[cfg(not(feature = "specialization"))] - { - Self::from_slice_fallback(slice) - } - } - } - } -} - -impl From<&mut [T]> for SmallVec { - #[inline] - fn from(slice: &mut [T]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<&[T; M]> for SmallVec { - #[inline] - fn from(slice: &[T; M]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<&mut [T; M]> for SmallVec { - #[inline] - fn from(slice: &mut [T; M]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<[T; M]> for SmallVec { - fn from(array: [T; M]) -> Self { - if M > N { - // If M > N, we'd have to heap allocate anyway, - // so delegate for Vec for the allocation. - Self::from(Vec::from(array)) - } else { - // M <= N - let mut this = Self::new(); - debug_assert!(M <= this.capacity()); - let array = ManuallyDrop::new(array); - // SAFETY: M <= this.capacity() - unsafe { - copy_nonoverlapping(array.as_ptr(), this.as_mut_ptr(), M); - this.set_len(M); - } - this - } - } -} - -impl From> for SmallVec { - fn from(array: Vec) -> Self { - Self::from_vec(array) - } -} - impl Clone for SmallVec { #[inline] fn clone(&self) -> SmallVec { SmallVec::from(self.as_slice()) } - #[inline] fn clone_from(&mut self, source: &Self) { #[cfg(feature = "specialization")] { >::spec_clone_from(self, source); } - #[cfg(not(feature = "specialization"))] { self.clone_from_fallback(&*source); } } } - impl Clone for IntoIter { #[inline] fn clone(&self) -> IntoIter { SmallVec::from(self.as_slice()).into_iter() } } - impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2453,14 +2139,12 @@ impl Extend for SmallVec { { spec_traits::SpecExtend::::spec_extend(self, iter.into_iter()); } - #[cfg(not(feature = "specialization"))] { self.extend_fallback(iter); } } } - impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2468,14 +2152,12 @@ impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { { spec_traits::SpecExtend::<&'a T, _>::spec_extend(self, iter.into_iter()); } - #[cfg(not(feature = "specialization"))] { self.extend_fallback(iter.into_iter().cloned()); } } } - impl core::iter::FromIterator for SmallVec { #[inline] fn from_iter>(iter: I) -> Self { @@ -2483,14 +2165,12 @@ impl core::iter::FromIterator for SmallVec { { spec_traits::SpecFromIterator::::spec_from_iter(iter.into_iter()) } - #[cfg(not(feature = "specialization"))] { Self::from_iter_fallback(iter.into_iter()) } } } - #[macro_export] macro_rules! smallvec { ($elem:expr; $n:expr) => ({ @@ -2500,7 +2180,6 @@ macro_rules! smallvec { $crate::SmallVec::from([$($($x),+)?]) }); } - #[macro_export] macro_rules! smallvec_inline { // count helper: transform any expression into 1 @@ -2513,7 +2192,6 @@ macro_rules! smallvec_inline { $crate::SmallVec::<_, N>::from_buf([$($x),*]) }); } - impl IntoIterator for SmallVec { type IntoIter = IntoIter; type Item = T; @@ -2532,7 +2210,6 @@ impl IntoIterator for SmallVec { } } } - impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { type IntoIter = core::slice::Iter<'a, T>; type Item = &'a T; @@ -2540,7 +2217,6 @@ impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { self.iter() } } - impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { type IntoIter = core::slice::IterMut<'a, T>; type Item = &'a mut T; @@ -2548,25 +2224,21 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { self.iter_mut() } } - impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } - impl Debug for SmallVec { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list().entries(self.iter()).finish() } } - impl Debug for IntoIter { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } - impl Debug for Drain<'_, T, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs index 6377b63..7a49d86 100644 --- a/src/mallocsizeof.rs +++ b/src/mallocsizeof.rs @@ -2,7 +2,6 @@ use { super::SmallVec, malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}, }; - impl MallocShallowSizeOf for SmallVec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { if self.spilled() { @@ -12,7 +11,6 @@ impl MallocShallowSizeOf for SmallVec { } } } - impl MallocSizeOf for SmallVec { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = self.shallow_size_of(ops); diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index f6fa459..2f501f0 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -6,7 +6,6 @@ use { ptr::{copy_nonoverlapping, NonNull}, }, }; - /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. /// @@ -17,10 +16,8 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize), } - impl RawSmallVec { pub const IS_ZST: bool = size_of::() == 0; - #[inline] pub const fn new() -> Self { Self::new_inline(MaybeUninit::uninit()) @@ -37,7 +34,6 @@ impl RawSmallVec { heap: (ptr, capacity), } } - #[inline] pub const fn as_ptr_inline(&self) -> *const T { // SAFETY: it is safe because we aren't reading the value, just getting a @@ -46,14 +42,12 @@ impl RawSmallVec { #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] (unsafe { &raw const self.inline }).cast::() } - #[inline] pub const fn as_mut_ptr_inline(&mut self) -> *mut T { // SAFETY: same as above #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] (unsafe { &raw mut self.inline }).cast::() } - /// # Safety /// /// The vector must be on the heap @@ -61,7 +55,6 @@ impl RawSmallVec { pub const unsafe fn as_ptr_heap(&self) -> *const T { self.heap.0.as_ptr() } - /// # Safety /// /// The vector must be on the heap @@ -69,7 +62,6 @@ impl RawSmallVec { pub const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { self.heap.0.as_ptr() } - /// # Safety /// /// `new_capacity` must be non zero, and greater or equal to the length. @@ -83,7 +75,6 @@ impl RawSmallVec { debug_assert!(!Self::IS_ZST); debug_assert!(new_capacity > 0); debug_assert!(new_capacity >= len.value()); - let was_on_heap = len.on_heap(); let ptr = if was_on_heap { self.as_mut_ptr_heap() @@ -91,13 +82,11 @@ impl RawSmallVec { self.as_mut_ptr_inline() }; let len = len.value(); - let new_layout = Layout::array::(new_capacity).map_err(|_| AllocationError::CapacityOverflow)?; if new_layout.size() > isize::MAX as usize { return Err(AllocationError::CapacityOverflow); } - let new_ptr = if len == 0 || !was_on_heap { // get a fresh allocation let new_ptr = alloc(new_layout) as *mut T; // `new_layout` has nonzero size. @@ -107,12 +96,10 @@ impl RawSmallVec { new_ptr } else { // use realloc - // this can't overflow since we already constructed an equivalent layout during // the previous allocation let old_layout = Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); - // SAFETY: ptr was allocated with this allocator // old_layout is the same as the layout used to allocate the previous memory // block new_layout.size() is greater than zero diff --git a/src/references.rs b/src/references.rs index ddac847..fff4b4b 100644 --- a/src/references.rs +++ b/src/references.rs @@ -2,10 +2,8 @@ use { super::SmallVec, core::borrow::{Borrow, BorrowMut}, }; - impl core::ops::Deref for SmallVec { type Target = [T]; - #[inline] fn deref(&self) -> &Self::Target { self.as_slice() @@ -17,28 +15,24 @@ impl core::ops::DerefMut for SmallVec { self.as_mut_slice() } } - impl AsRef<[T]> for SmallVec { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } - impl AsMut<[T]> for SmallVec { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } - impl Borrow<[T]> for SmallVec { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } - impl BorrowMut<[T]> for SmallVec { #[inline] fn borrow_mut(&mut self) -> &mut [T] { diff --git a/src/serde.rs b/src/serde.rs index 0f7d7e8..18fb2a3 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -7,7 +7,6 @@ use { Deserialize, Deserializer, Serialize, Serializer, }, }; - impl Serialize for SmallVec where T: Serialize, @@ -20,7 +19,6 @@ where state.end() } } - impl<'de, T, const N: usize> Deserialize<'de> for SmallVec where T: Deserialize<'de>, @@ -31,21 +29,17 @@ where }) } } - struct SmallVecVisitor { phantom: PhantomData, } - impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor where T: Deserialize<'de>, { type Value = SmallVec; - fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a sequence") } - fn visit_seq(self, mut seq: B) -> Result where B: SeqAccess<'de>, @@ -54,11 +48,9 @@ where let len = seq.size_hint().unwrap_or(0); let mut values = SmallVec::new(); values.try_reserve(len).map_err(B::Error::custom)?; - while let Some(value) = seq.next_element()? { values.push(value); } - Ok(values) } } diff --git a/src/std.rs b/src/std.rs index 4e5cbae..b9e2568 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,7 +1,5 @@ extern crate std; - use {super::SmallVec, std::io}; - #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl io::Write for SmallVec { @@ -10,13 +8,11 @@ impl io::Write for SmallVec { self.extend_from_slice(buf); Ok(buf.len()) } - #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.extend_from_slice(buf); Ok(()) } - #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/src/taggedlen.rs b/src/taggedlen.rs index 99025d2..acc97fa 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -1,5 +1,4 @@ use core::marker::PhantomData; - /// Vec guarantees that its length is always less than [`isize::MAX`] in /// *bytes*. /// @@ -11,7 +10,6 @@ use core::marker::PhantomData; /// For a ZST, we never use the heap, so we just store the length directly. #[repr(transparent)] pub struct TaggedLen(usize, PhantomData); - // Clone and Copy must be manually implemented because the generic interferes // with the derive attribute implementations. impl Clone for TaggedLen { @@ -19,15 +17,12 @@ impl Clone for TaggedLen { fn clone(&self) -> Self { Self(self.0, PhantomData) } - #[inline] fn clone_from(&mut self, source: &Self) { self.0 = source.0; } } - impl Copy for TaggedLen {} - impl TaggedLen { const IS_ZST: bool = size_of::() == 0; #[inline] @@ -40,7 +35,6 @@ impl TaggedLen { Self((len << 1) | on_heap as usize, PhantomData) } } - #[inline] #[must_use] pub const fn on_heap(self) -> bool { @@ -50,7 +44,6 @@ impl TaggedLen { (self.0 & 1_usize) == 1 } } - #[inline] pub const fn value(self) -> usize { if Self::IS_ZST { diff --git a/src/tests.rs b/src/tests.rs index 887651a..d4af1a4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,11 +1,9 @@ extern crate std; - use { crate::{smallvec, SmallVec}, alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec::Vec}, core::{hash::Hasher, iter::FromIterator}, }; - #[test] pub fn test_zero() { let mut v = SmallVec::<_, 0>::new(); @@ -14,10 +12,8 @@ pub fn test_zero() { assert!(v.spilled()); assert_eq!(&*v, &[0]); } - // We heap allocate all these strings so that double frees will show up under // valgrind. - #[test] pub fn test_inline() { let mut v = SmallVec::<_, 16>::new(); @@ -25,7 +21,6 @@ pub fn test_inline() { v.push("there".to_owned()); assert_eq!(&*v, &["hello".to_owned(), "there".to_owned(),][..]); } - #[test] pub fn test_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -45,7 +40,6 @@ pub fn test_spill() { ][..] ); } - #[test] pub fn test_double_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -71,38 +65,32 @@ pub fn test_double_spill() { ][..] ); } - // https://github.com/servo/rust-smallvec/issues/4 #[test] fn issue_4() { SmallVec::, 2>::new(); } - // https://github.com/servo/rust-smallvec/issues/5 #[test] fn issue_5() { assert!(Some(SmallVec::<&u32, 2>::new()).is_some()); } - #[test] fn test_with_capacity() { let v: SmallVec = SmallVec::with_capacity(1); assert!(v.is_empty()); assert!(!v.spilled()); assert_eq!(v.capacity(), 3); - let v: SmallVec = SmallVec::with_capacity(10); assert!(v.is_empty()); assert!(v.spilled()); assert_eq!(v.capacity(), 10); } - #[test] fn drain() { let mut v: SmallVec = SmallVec::new(); v.push(3); assert_eq!(v.drain(..).collect::>(), &[3]); - // spilling the vec v.push(3); v.push(4); @@ -111,7 +99,6 @@ fn drain() { assert_eq!(v.drain(1..).collect::>(), &[4, 5]); // drain should not change the capacity assert_eq!(v.capacity(), old_capacity); - // Exercise the tail-shifting code when in the inline state // This has the potential to produce UB due to aliasing let mut v: SmallVec = SmallVec::new(); @@ -119,27 +106,23 @@ fn drain() { v.push(2); assert_eq!(v.drain(..1).collect::>(), &[1]); } - #[test] fn drain_rev() { let mut v: SmallVec = SmallVec::new(); v.push(3); assert_eq!(v.drain(..).rev().collect::>(), &[3]); - // spilling the vec v.push(3); v.push(4); v.push(5); assert_eq!(v.drain(..).rev().collect::>(), &[5, 4, 3]); } - #[test] fn drain_forget() { let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6, 7]; std::mem::forget(v.drain(2..5)); assert_eq!(v.len(), 2); } - #[test] fn splice() { // The range starts right before the end. @@ -148,14 +131,12 @@ fn splice() { let u: SmallVec = v.splice(6.., new).collect(); assert_eq!(v, [0, 1, 2, 3, 4, 5, 7, 8, 9, 10]); assert_eq!(u, [6]); - // The range is empty. let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6]; let new = [7, 8, 9, 10]; let u: SmallVec = v.splice(1..1, new).collect(); assert_eq!(v, [0, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6]); assert_eq!(u, [0u8; 0]); - // The range is at the beginning and nonempty. let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6]; let new = [7, 8, 9, 10]; @@ -163,13 +144,11 @@ fn splice() { assert_eq!(v, [7, 8, 9, 10, 3, 4, 5, 6]); assert_eq!(u, [0, 1, 2]); } - #[test] fn into_iter() { let mut v: SmallVec = SmallVec::new(); v.push(3); assert_eq!(v.into_iter().collect::>(), &[3]); - // spilling the vec let mut v: SmallVec = SmallVec::new(); v.push(3); @@ -177,13 +156,11 @@ fn into_iter() { v.push(5); assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); } - #[test] fn into_iter_rev() { let mut v: SmallVec = SmallVec::new(); v.push(3); assert_eq!(v.into_iter().rev().collect::>(), &[3]); - // spilling the vec let mut v: SmallVec = SmallVec::new(); v.push(3); @@ -191,19 +168,15 @@ fn into_iter_rev() { v.push(5); assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); } - #[test] fn into_iter_drop() { use std::cell::Cell; - struct DropCounter<'a>(&'a Cell); - impl<'a> Drop for DropCounter<'a> { fn drop(&mut self) { self.0.set(self.0.get() + 1); } } - { let cell = Cell::new(0); let mut v: SmallVec, 2> = SmallVec::new(); @@ -211,7 +184,6 @@ fn into_iter_drop() { v.into_iter(); assert_eq!(cell.get(), 1); } - { let cell = Cell::new(0); let mut v: SmallVec, 2> = SmallVec::new(); @@ -220,7 +192,6 @@ fn into_iter_drop() { assert!(v.into_iter().next().is_some()); assert_eq!(cell.get(), 2); } - { let cell = Cell::new(0); let mut v: SmallVec, 2> = SmallVec::new(); @@ -244,79 +215,62 @@ fn into_iter_drop() { assert_eq!(cell.get(), 3); } } - #[test] fn test_capacity() { let mut v: SmallVec = SmallVec::new(); v.reserve(1); assert_eq!(v.capacity(), 2); assert!(!v.spilled()); - v.reserve_exact(0x100); assert!(v.capacity() >= 0x100); - v.push(0); v.push(1); v.push(2); v.push(3); - v.shrink_to_fit(); assert!(v.capacity() < 0x100); } - #[test] fn test_truncate() { let mut v: SmallVec, 8> = SmallVec::new(); - for x in 0..8 { v.push(Box::new(x)); } v.truncate(4); - assert_eq!(v.len(), 4); assert!(!v.spilled()); - assert_eq!(*v.swap_remove(1), 1); assert_eq!(*v.remove(1), 3); v.insert(1, Box::new(3)); - assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); } - #[test] fn test_truncate_references() { let mut v = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]); let mut i = 8; let mut v: SmallVec<&mut u8, 8> = v.iter_mut().collect(); - v.truncate(4); - assert_eq!(v.len(), 4); assert!(!v.spilled()); - assert_eq!(*v.swap_remove(1), 1); assert_eq!(*v.remove(1), 3); v.insert(1, &mut i); - assert_eq!( &v.iter_mut().map(|v| &mut **v).collect::>(), &[&mut 0, &mut 8, &mut 2] ); } - #[test] fn test_split_off() { let mut vec: SmallVec = smallvec![1, 2, 3, 4, 5, 6]; let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); - let split_off = vec.split_off(4); assert_eq!(&vec[..], &[1, 2, 3, 4]); assert_eq!(&split_off[..], &[5, 6]); assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); } - #[test] fn test_split_off_take_all() { // Allocate enough capacity that we can tell whether the split-off vector's @@ -325,19 +279,16 @@ fn test_split_off_take_all() { vec.extend([1, 2, 3, 4, 5, 6]); let orig_ptr = vec.as_ptr(); let orig_capacity: usize = vec.capacity(); - let split_off = vec.split_off(0); assert_eq!(&vec[..], &[0u32; 0]); assert_eq!(&split_off[..], &[1, 2, 3, 4, 5, 6]); assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); - // The split-off vector should be newly-allocated, and should not have // stolen the original vector's allocation. assert!(split_off.capacity() < orig_capacity); assert_ne!(split_off.as_ptr(), orig_ptr); } - #[test] fn test_append() { let mut v: SmallVec = SmallVec::new(); @@ -345,18 +296,15 @@ fn test_append() { v.push(x); } assert_eq!(v.len(), 4); - let mut n: SmallVec = SmallVec::from_buf([5, 6]); v.append(&mut n); assert_eq!(v.len(), 6); assert_eq!(n.len(), 0); - assert_eq!( &v.iter().map(|v| *v).collect::>(), &[0, 1, 2, 3, 5, 6] ); } - #[test] #[should_panic] fn test_invalid_grow() { @@ -364,14 +312,12 @@ fn test_invalid_grow() { v.extend(0..8); v.grow(5); } - #[test] #[should_panic] fn drain_overflow() { let mut v: SmallVec = smallvec![0]; v.drain(..=usize::MAX); } - #[test] fn test_extend_from_slice() { let mut v: SmallVec = SmallVec::new(); @@ -385,7 +331,6 @@ fn test_extend_from_slice() { &[0, 1, 2, 3, 5, 6] ); } - #[test] fn test_extend_from_within() { let mut v: SmallVec = smallvec![0, 1, 2, 3]; @@ -395,24 +340,20 @@ fn test_extend_from_within() { &[0, 1, 2, 3, 1, 2], ); } - #[test] #[should_panic] fn test_drop_panic_smallvec() { // This test should only panic once, and not double panic, // which would mean a double drop struct DropPanic; - impl Drop for DropPanic { fn drop(&mut self) { panic!("drop"); } } - let mut v = SmallVec::<_, 1>::new(); v.push(DropPanic); } - #[test] fn test_eq() { let mut a: SmallVec = SmallVec::new(); @@ -427,11 +368,9 @@ fn test_eq() { // c = [3, 4] c.push(3); c.push(4); - assert!(a == b); assert!(a != c); } - #[test] fn test_ord() { let mut a: SmallVec = SmallVec::new(); @@ -445,30 +384,25 @@ fn test_ord() { // c = [1, 2] c.push(1); c.push(2); - assert!(a < b); assert!(b > a); assert!(b < c); assert!(c > b); } - #[test] fn test_hash() { use std::{collections::hash_map::DefaultHasher, hash::Hash}; - fn hash(value: impl Hash) -> u64 { let mut hasher = DefaultHasher::new(); value.hash(&mut hasher); hasher.finish() } - { let mut a: SmallVec = SmallVec::new(); let b = [1, 2]; a.extend(b.iter().cloned()); assert_eq!(hash(a), hash(b)); } - { let mut a: SmallVec = SmallVec::new(); let b = [1, 2, 11, 12]; @@ -476,7 +410,6 @@ fn test_hash() { assert_eq!(hash(a), hash(b)); } } - #[test] fn test_as_ref() { let mut a: SmallVec = SmallVec::new(); @@ -487,7 +420,6 @@ fn test_as_ref() { a.push(3); assert_eq!(a.as_ref(), [1, 2, 3]); } - #[test] fn test_as_mut() { let mut a: SmallVec = SmallVec::new(); @@ -500,11 +432,9 @@ fn test_as_mut() { a.as_mut()[1] = 4; assert_eq!(a.as_mut(), [1, 4, 3]); } - #[test] fn test_borrow() { use std::borrow::Borrow; - let mut a: SmallVec = SmallVec::new(); a.push(1); assert_eq!(a.borrow(), [1]); @@ -513,11 +443,9 @@ fn test_borrow() { a.push(3); assert_eq!(a.borrow(), [1, 2, 3]); } - #[test] fn test_borrow_mut() { use std::borrow::BorrowMut; - let mut a: SmallVec = SmallVec::new(); a.push(1); assert_eq!(a.borrow_mut(), [1]); @@ -528,66 +456,54 @@ fn test_borrow_mut() { BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; assert_eq!(a.borrow_mut(), [1, 4, 3]); } - #[test] fn test_from() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); - let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); - let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); - let array = [1]; let small_vec: SmallVec = SmallVec::from(array); assert_eq!(&*small_vec, &[1]); drop(small_vec); - let array = [99; 128]; let small_vec: SmallVec = SmallVec::from(array); assert_eq!(&*small_vec, Vec::from([99u8; 128]).as_slice()); drop(small_vec); - #[derive(PartialEq, Eq, Debug)] struct NoClone(u8); let array = [NoClone(42)]; let small_vec: SmallVec = SmallVec::from(array); assert_eq!(&*small_vec, &[NoClone(42)]); drop(small_vec); - let vec = Vec::from([NoClone(42)]); let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[NoClone(42)]); drop(small_vec); - let array = [1; 128]; let small_vec: SmallVec = SmallVec::from(array); assert_eq!(&*small_vec, Vec::from([1; 128]).as_slice()); drop(small_vec); - let array = [99]; let small_vec: SmallVec = SmallVec::from(array); assert_eq!(&*small_vec, &[99u8]); drop(small_vec); } - #[test] fn test_from_slice() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); } - #[test] fn test_exact_size_iterator() { let mut vec = SmallVec::::from(&[1, 2, 3][..]); @@ -595,7 +511,6 @@ fn test_exact_size_iterator() { assert_eq!(vec.drain(..2).len(), 2); assert_eq!(vec.into_iter().len(), 1); } - #[test] fn test_into_iter_as_slice() { let vec = SmallVec::::from(&[1, 2, 3][..]); @@ -609,7 +524,6 @@ fn test_into_iter_as_slice() { assert_eq!(iter.as_slice(), &[2]); assert_eq!(iter.as_mut_slice(), &[2]); } - #[test] fn test_into_iter_clone() { // Test that the cloned iterator yields identical elements and that it owns its @@ -621,7 +535,6 @@ fn test_into_iter_clone() { } assert_eq!(clone_iter.next(), None); } - #[test] fn test_into_iter_clone_partially_consumed_iterator() { // Test that the cloned iterator only contains the remaining elements of the @@ -633,7 +546,6 @@ fn test_into_iter_clone_partially_consumed_iterator() { } assert_eq!(clone_iter.next(), None); } - #[test] fn test_into_iter_clone_empty_smallvec() { let mut iter = SmallVec::::new().into_iter(); @@ -641,7 +553,6 @@ fn test_into_iter_clone_empty_smallvec() { assert_eq!(iter.next(), None); assert_eq!(clone_iter.next(), None); } - #[test] fn shrink_to_fit_unspill() { let mut vec = SmallVec::::from_iter(0..3); @@ -650,68 +561,55 @@ fn shrink_to_fit_unspill() { vec.shrink_to_fit(); assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible"); } - #[test] fn shrink_after_from_empty_vec() { let mut v = SmallVec::::from_vec(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } - #[test] fn test_into_vec() { let vec = SmallVec::::from_iter(0..2); assert_eq!(vec.into_vec(), Vec::from([0, 1])); - let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.into_vec(), Vec::from([0, 1, 2])); } - #[test] fn test_into_inner() { let vec = SmallVec::::from_iter(0..2); assert_eq!(vec.into_inner(), Ok([0, 1])); - let vec = SmallVec::::from_iter(0..1); assert_eq!(vec.clone().into_inner(), Err(vec)); - let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.clone().into_inner(), Err(vec)); } - #[test] fn test_from_vec() { let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = Vec::new(); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); - let vec = Vec::from([1]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1]); drop(small_vec); - let vec = Vec::from([1, 2, 3]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3]); drop(small_vec); - let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); - let vec = Vec::from([1, 2, 3, 4, 5]); let small_vec: SmallVec = SmallVec::from_vec(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); } - #[test] fn test_retain() { // Test inline data storage @@ -721,7 +619,6 @@ fn test_retain() { assert_eq!(sv.pop(), Some(2)); assert_eq!(sv.pop(), Some(1)); assert_eq!(sv.pop(), None); - // Test spilled data storage let mut sv: SmallVec = SmallVec::from(&[1, 2, 3, 3, 4]); sv.retain(|&i| i != 3); @@ -729,7 +626,6 @@ fn test_retain() { assert_eq!(sv.pop(), Some(2)); assert_eq!(sv.pop(), Some(1)); assert_eq!(sv.pop(), None); - // Test that drop implementations are called for inline. let one = Rc::new(1); let mut sv: SmallVec, 3> = SmallVec::new(); @@ -737,7 +633,6 @@ fn test_retain() { assert_eq!(Rc::strong_count(&one), 2); sv.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); - // Test that drop implementations are called for spilled data. let mut sv: SmallVec, 1> = SmallVec::new(); sv.push(Rc::clone(&one)); @@ -746,54 +641,43 @@ fn test_retain() { sv.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); } - #[test] fn test_dedup() { let mut dupes: SmallVec = SmallVec::from(&[1, 1, 2, 3, 3]); dupes.dedup(); assert_eq!(&*dupes, &[1, 2, 3]); - let mut empty: SmallVec = SmallVec::new(); empty.dedup(); assert!(empty.is_empty()); - let mut all_ones: SmallVec = SmallVec::from(&[1, 1, 1, 1, 1]); all_ones.dedup(); assert_eq!(all_ones.len(), 1); - let mut no_dupes: SmallVec = SmallVec::from(&[1, 2, 3, 4, 5]); no_dupes.dedup(); assert_eq!(no_dupes.len(), 5); } - #[test] fn test_resize() { let mut v: SmallVec = SmallVec::new(); v.push(1); v.resize(5, 0); assert_eq!(v[..], [1, 0, 0, 0, 0][..]); - v.resize(2, -1); assert_eq!(v[..], [1, 0][..]); } - #[cfg(feature = "std")] #[test] fn test_write() { use std::io::Write; - let data = [1, 2, 3, 4, 5]; - let mut small_vec: SmallVec = SmallVec::new(); let len = small_vec.write(&data[..]).unwrap(); assert_eq!(len, 5); assert_eq!(small_vec.as_ref(), data.as_ref()); - let mut small_vec: SmallVec = SmallVec::new(); small_vec.write_all(&data[..]).unwrap(); assert_eq!(small_vec.as_ref(), data.as_ref()); } - #[cfg(feature = "serde")] #[test] fn test_serde() { @@ -818,7 +702,6 @@ fn test_serde() { ], ); } - #[test] fn grow_to_shrink() { let mut v: SmallVec = SmallVec::new(); @@ -835,7 +718,6 @@ fn grow_to_shrink() { v.push(4); assert_eq!(v[..], [4]); } - #[test] fn resumable_extend() { let s = "a b c"; @@ -847,14 +729,12 @@ fn resumable_extend() { v.extend(it); assert_eq!(v[..], ['a']); } - // #139 #[test] fn uninhabited() { enum Void {} let _sv = SmallVec::::new(); } - #[test] fn grow_spilled_same_size() { let mut v: SmallVec = SmallVec::new(); @@ -868,12 +748,10 @@ fn grow_spilled_same_size() { assert_eq!(v.capacity(), 4); assert_eq!(v[..], [0, 1, 2]); } - #[test] fn const_generics() { let _v = SmallVec::::default(); } - #[test] fn const_new() { let v = const_new_inner(); @@ -898,49 +776,38 @@ const fn const_new_inline_sized() -> SmallVec { const fn const_new_inline_args() -> SmallVec { crate::smallvec_inline![1, 4] } - #[test] fn empty_macro() { let _v: SmallVec = smallvec![]; } - #[test] fn zero_size_items() { SmallVec::<(), 0>::new().push(()); } - #[test] fn test_clone_from() { let mut a: SmallVec = SmallVec::new(); a.push(1); a.push(2); a.push(3); - let mut b: SmallVec = SmallVec::new(); b.push(10); - let mut c: SmallVec = SmallVec::new(); c.push(20); c.push(21); c.push(22); - a.clone_from(&b); assert_eq!(&*a, &[10]); - b.clone_from(&c); assert_eq!(&*b, &[20, 21, 22]); } - #[test] fn test_extract_if() { let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; - let b: SmallVec = a.extract_if(1..9, |x| *x % 3 == 0).collect(); - assert_eq!(a, SmallVec::::from(&[0, 1u8, 2, 4, 5, 7, 8, 0])); assert_eq!(b, SmallVec::::from(&[3u8, 6])); } - /// This assortment of tests, in combination with miri, verifies we handle UB on /// fishy arguments given to SmallVec. Draining and extending the allocation are /// fairly well-tested earlier, but `smallvec.insert(usize::MAX, val)` once @@ -954,58 +821,48 @@ fn max_dont_panic() { let _ = sv.get(usize::MAX); sv.truncate(usize::MAX); } - #[test] #[should_panic] fn max_remove() { let mut sv: SmallVec = smallvec![0]; sv.remove(usize::MAX); } - #[test] #[should_panic] fn max_swap_remove() { let mut sv: SmallVec = smallvec![0]; sv.swap_remove(usize::MAX); } - #[test] #[should_panic] fn max_insert() { let mut sv: SmallVec = smallvec![0]; sv.insert(usize::MAX, 0); } - #[test] fn collect_from_iter() { // Regression test for https://github.com/servo/rust-smallvec/issues/353 struct IterNoHint(I); - impl Iterator for IterNoHint { type Item = I::Item; fn next(&mut self) -> Option { self.0.next() } - // no implementation of size_hint means it returns (0, None) - which forces // from_iter to grow the allocated space iteratively. } - // A length of 3 is fine to trigger this bug under valgrind, but making the // vector 1 million elements makes it crash - which is much easier to // detect. let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); - let _y: SmallVec = SmallVec::from_iter(iter); } - #[test] fn test_collect_with_spill() { let input = "0123456"; let collected: SmallVec = input.chars().collect(); assert_eq!(collected, &['0', '1', '2', '3', '4', '5', '6']); } - #[test] fn test_spare_capacity_mut() { let mut v: SmallVec = SmallVec::new(); @@ -1013,55 +870,41 @@ fn test_spare_capacity_mut() { let spare = v.spare_capacity_mut(); assert_eq!(spare.len(), 2); assert_eq!(spare.as_ptr().cast::(), v.as_ptr()); - v.push(1); assert!(!v.spilled()); let spare = v.spare_capacity_mut(); assert_eq!(spare.len(), 1); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(1) }); - v.push(2); assert!(!v.spilled()); let spare = v.spare_capacity_mut(); assert_eq!(spare.len(), 0); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(2) }); - v.push(3); assert!(v.spilled()); let spare = v.spare_capacity_mut(); assert!(spare.len() >= 1); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(3) }); } - // Adopted from `tests/test_buf_mut.rs` in the `bytes` crate. #[cfg(feature = "bytes")] mod buf_mut { use bytes::BufMut as _; - type SmallVec = crate::SmallVec; - #[test] fn test_smallvec_as_mut_buf() { let mut buf = SmallVec::with_capacity(64); - assert_eq!(buf.remaining_mut(), isize::MAX as usize); - assert!(buf.chunk_mut().len() >= 64); - buf.put(&b"zomg"[..]); - assert_eq!(&buf, b"zomg"); - assert_eq!(buf.remaining_mut(), isize::MAX as usize - 4); assert_eq!(buf.capacity(), 64); - for _ in 0..16 { buf.put(&b"zomg"[..]); } - assert_eq!(buf.len(), 68); } - #[test] fn test_smallvec_put_bytes() { let mut buf = SmallVec::new(); @@ -1069,53 +912,45 @@ mod buf_mut { buf.put_bytes(19, 2); assert_eq!([17, 19, 19], &buf[..]); } - #[test] fn test_put_u8() { let mut buf = SmallVec::with_capacity(8); buf.put_u8(33); assert_eq!(b"\x21", &buf[..]); } - #[test] fn test_put_u16() { let mut buf = SmallVec::with_capacity(8); buf.put_u16(8532); assert_eq!(b"\x21\x54", &buf[..]); - buf.clear(); buf.put_u16_le(8532); assert_eq!(b"\x54\x21", &buf[..]); } - #[test] fn test_put_int() { let mut buf = SmallVec::with_capacity(8); buf.put_int(0x1020304050607080, 3); assert_eq!(b"\x60\x70\x80", &buf[..]); } - #[test] #[should_panic] fn test_put_int_nbytes_overflow() { let mut buf = SmallVec::with_capacity(8); buf.put_int(0x1020304050607080, 9); } - #[test] fn test_put_int_le() { let mut buf = SmallVec::with_capacity(8); buf.put_int_le(0x1020304050607080, 3); assert_eq!(b"\x80\x70\x60", &buf[..]); } - #[test] #[should_panic] fn test_put_int_le_nbytes_overflow() { let mut buf = SmallVec::with_capacity(8); buf.put_int_le(0x1020304050607080, 9); } - #[test] #[should_panic(expected = "advance out of bounds: the len is 8 but advancing by 12")] fn test_smallvec_advance_mut() { diff --git a/tests/macro.rs b/tests/macro.rs index a5d3a71..66e183d 100644 --- a/tests/macro.rs +++ b/tests/macro.rs @@ -4,19 +4,16 @@ #[test] fn smallvec() { let mut vec: smallvec::SmallVec; - macro_rules! check { ($init:tt) => { vec = smallvec::smallvec! $init; assert_eq!(*vec, *vec! $init); } } - check!([0; 0]); check!([1; 1]); check!([2; 2]); check!([3; 3]); - check!([]); check!([1]); check!([1, 2]); From 65cbc1e648f1e4819486030da96f3dda044fa405 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 15:18:30 +0200 Subject: [PATCH 08/15] fix: made error type public again --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a1eb5bd..7b4c1ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,9 +68,9 @@ mod std; mod taggedlen; #[cfg(test)] mod tests; +pub use allocationerror::AllocationError; use { alloc::{alloc::Layout, boxed::Box, vec::Vec}, - allocationerror::AllocationError, core::{ fmt::Debug, hash::{Hash, Hasher}, From 1e29e5dfcfc40094f3ad9c9a26e4282b88ab49cb Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 26 Aug 2026 14:08:55 +0200 Subject: [PATCH 09/15] fix: newline amount --- rustfmt.toml | 2 +- src/allocationerror.rs | 3 ++ src/bytes.rs | 3 +- src/comparisons.rs | 10 ++++++ src/conversions.rs | 8 ++++- src/lib.rs | 51 ++++++++++++++++++++++++++++++ src/mallocsizeof.rs | 4 ++- src/rawsmallvec.rs | 4 ++- src/references.rs | 7 +++++ src/serde.rs | 5 +++ src/std.rs | 4 ++- src/taggedlen.rs | 3 ++ src/tests.rs | 71 ++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 169 insertions(+), 6 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 6643b4d..2fbbc2f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -4,7 +4,7 @@ group_imports = "One" format_code_in_doc_comments = true match_arm_blocks = false blank_lines_lower_bound = 0 -blank_lines_upper_bound = 0 +blank_lines_upper_bound = 1 condense_wildcard_suffixes = true error_on_unformatted = true error_on_line_overflow = true \ No newline at end of file diff --git a/src/allocationerror.rs b/src/allocationerror.rs index c28f38c..8c657a0 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -5,6 +5,7 @@ use { fmt::{Display, Formatter, Result as Format}, }, }; + /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum AllocationError { @@ -16,9 +17,11 @@ pub enum AllocationError { layout: Layout, }, } + impl Display for AllocationError { fn fmt(&self, f: &mut Formatter) -> Format { write!(f, "Allocation error: {:?}", self) } } + impl Error for AllocationError {} diff --git a/src/bytes.rs b/src/bytes.rs index 11f7fbc..9472993 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -2,6 +2,7 @@ use { super::SmallVec, bytes::{buf::UninitSlice, BufMut}, }; + unsafe impl BufMut for SmallVec { #[inline] fn remaining_mut(&self) -> usize { @@ -57,4 +58,4 @@ unsafe impl BufMut for SmallVec { let new_len = self.len().saturating_add(cnt); self.resize(new_len, val); } -} +} \ No newline at end of file diff --git a/src/comparisons.rs b/src/comparisons.rs index f4ca1d3..a9019ea 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -1,4 +1,5 @@ use super::SmallVec; + impl PartialEq> for SmallVec where T: PartialEq, @@ -8,7 +9,9 @@ where self.as_slice().eq(other.as_slice()) } } + impl Eq for SmallVec where T: Eq {} + impl PartialEq<[U; M]> for SmallVec where T: PartialEq, @@ -18,6 +21,7 @@ where self[..] == other[..] } } + impl PartialEq<&[U; M]> for SmallVec where T: PartialEq, @@ -27,6 +31,7 @@ where self[..] == other[..] } } + impl PartialEq<[U]> for SmallVec where T: PartialEq, @@ -36,6 +41,7 @@ where self[..] == other[..] } } + impl PartialEq<&[U]> for SmallVec where T: PartialEq, @@ -45,6 +51,7 @@ where self[..] == other[..] } } + impl PartialEq<&mut [U]> for SmallVec where T: PartialEq, @@ -54,6 +61,7 @@ where self[..] == other[..] } } + impl PartialOrd for SmallVec where T: PartialOrd, @@ -63,6 +71,7 @@ where self.as_slice().partial_cmp(other.as_slice()) } } + impl Ord for SmallVec where T: Ord, @@ -72,3 +81,4 @@ where self.as_slice().cmp(other.as_slice()) } } + diff --git a/src/conversions.rs b/src/conversions.rs index 18da6b4..86eea89 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -5,12 +5,14 @@ use { alloc::vec::Vec, core::{mem::ManuallyDrop, ptr::copy_nonoverlapping}, }; + impl From<&mut [T; M]> for SmallVec { #[inline] fn from(slice: &mut [T; M]) -> Self { Self::from(slice as &[T]) } } + impl From<[T; M]> for SmallVec { fn from(array: [T; M]) -> Self { if M > N { @@ -31,11 +33,13 @@ impl From<[T; M]> for SmallVec { } } } + impl From> for SmallVec { fn from(array: Vec) -> Self { Self::from_vec(array) } } + impl From<&[T]> for SmallVec { #[inline] fn from(slice: &[T]) -> Self { @@ -57,15 +61,17 @@ impl From<&[T]> for SmallVec { } } } + impl From<&mut [T]> for SmallVec { #[inline] fn from(slice: &mut [T]) -> Self { Self::from(slice as &[T]) } } + impl From<&[T; M]> for SmallVec { #[inline] fn from(slice: &[T; M]) -> Self { Self::from(slice as &[T]) } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7b4c1ef..d48c2d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,7 @@ use { ptr::{copy, copy_nonoverlapping, NonNull}, }, }; + #[cfg(feature = "internals")] pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[cfg(not(feature = "internals"))] @@ -91,6 +92,7 @@ fn infallible(result: Result) -> T { Err(AllocationError::Failure { layout }) => alloc::alloc::handle_alloc_error(layout), } } + #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -121,12 +123,14 @@ where } core::ops::Range { start, end } } + #[repr(C)] pub struct SmallVec { len: TaggedLen, raw: RawSmallVec, _marker: PhantomData, } + unsafe impl Send for SmallVec {} unsafe impl Sync for SmallVec {} impl Default for SmallVec { @@ -135,6 +139,7 @@ impl Default for SmallVec { Self::new() } } + /// An iterator that removes the items from a `SmallVec` and yields them by /// value. /// @@ -154,6 +159,7 @@ pub struct Drain<'a, T: 'a, const N: usize> { iter: core::slice::Iter<'a, T>, vec: core::ptr::NonNull>, } + impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { type Item = T; #[inline] @@ -169,6 +175,7 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { self.iter.size_hint() } } + impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { #[inline] fn next_back(&mut self) -> Option { @@ -178,12 +185,14 @@ impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { .map(|reference| unsafe { core::ptr::read(reference) }) } } + impl ExactSizeIterator for Drain<'_, T, N> { #[inline] fn len(&self) -> usize { self.iter.len() } } + impl core::iter::FusedIterator for Drain<'_, T, N> {} impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { fn drop(&mut self) { @@ -249,6 +258,7 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { } } } + impl Drain<'_, T, N> { #[must_use] pub fn as_slice(&self) -> &[T] { @@ -298,6 +308,7 @@ impl Drain<'_, T, N> { self.tail_start = new_tail_start; } } + /// An iterator which uses a closure to determine if an element should be /// removed. /// @@ -321,6 +332,7 @@ where /// The filter test predicate. pred: F, } + impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -332,6 +344,7 @@ where .finish() } } + impl Iterator for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -364,6 +377,7 @@ where (0, Some(self.end - self.idx)) } } + impl Drop for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -387,10 +401,12 @@ where } } } + pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, replace_with: I, } + impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: Debug + Iterator + 'a, @@ -400,6 +416,7 @@ where f.debug_tuple("Splice").field(&self.drain).finish() } } + impl Iterator for Splice<'_, I, N> { type Item = I::Item; fn next(&mut self) -> Option { @@ -409,11 +426,13 @@ impl Iterator for Splice<'_, I, N> { self.drain.size_hint() } } + impl DoubleEndedIterator for Splice<'_, I, N> { fn next_back(&mut self) -> Option { self.drain.next_back() } } + impl ExactSizeIterator for Splice<'_, I, N> {} impl Drop for Splice<'_, I, N> { fn drop(&mut self) { @@ -460,6 +479,7 @@ impl Drop for Splice<'_, I, N> { // `vec.len`. } } + /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. @@ -476,6 +496,7 @@ pub struct IntoIter { end: TaggedLen, _marker: PhantomData, } + // SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) // an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. unsafe impl Send for IntoIter where T: Send {} @@ -519,6 +540,7 @@ impl IntoIter { } } } + impl Iterator for IntoIter { type Item = T; #[inline] @@ -541,6 +563,7 @@ impl Iterator for IntoIter { (size, Some(size)) } } + impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { @@ -560,6 +583,7 @@ impl DoubleEndedIterator for IntoIter { } } } + impl ExactSizeIterator for IntoIter {} impl core::iter::FusedIterator for IntoIter {} impl SmallVec { @@ -652,6 +676,7 @@ impl SmallVec { } } } + impl SmallVec { const IS_ZST: bool = size_of::() == 0; #[inline] @@ -1475,6 +1500,7 @@ impl SmallVec { } } } + impl SmallVec { #[inline] pub fn resize(&mut self, len: usize, value: T) { @@ -1581,10 +1607,12 @@ impl SmallVec { result } } + struct DropGuard { ptr: *mut T, len: usize, } + impl Drop for DropGuard { #[inline] fn drop(&mut self) { @@ -1593,11 +1621,13 @@ impl Drop for DropGuard { } } } + struct DropDealloc { ptr: NonNull, size_bytes: usize, align: usize, } + impl Drop for DropDealloc { #[inline] fn drop(&mut self) { @@ -1611,6 +1641,7 @@ impl Drop for DropDealloc { } } } + #[cfg(feature = "may_dangle")] unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { fn drop(&mut self) { @@ -1634,6 +1665,7 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { } } } + #[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { @@ -1656,6 +1688,7 @@ impl Drop for SmallVec { } } } + impl Drop for IntoIter { fn drop(&mut self) { // SAFETY: see above @@ -1678,6 +1711,7 @@ impl Drop for IntoIter { } } } + /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using thís function. #[doc(hidden)] @@ -1700,6 +1734,7 @@ pub fn from_elem(elem: T, n: usize) -> SmallVec } } } + #[cfg(feature = "specialization")] mod spec_traits { use super::*; @@ -1969,6 +2004,7 @@ mod spec_traits { } } } + /// Fallback functions for various specialized methods. These are kept in /// a separate implementation block for easy access whenever specialization is /// disabled. @@ -2109,6 +2145,7 @@ impl SmallVec { v } } + impl Clone for SmallVec { #[inline] fn clone(&self) -> SmallVec { @@ -2126,12 +2163,14 @@ impl Clone for SmallVec { } } } + impl Clone for IntoIter { #[inline] fn clone(&self) -> IntoIter { SmallVec::from(self.as_slice()).into_iter() } } + impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2145,6 +2184,7 @@ impl Extend for SmallVec { } } } + impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2158,6 +2198,7 @@ impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { } } } + impl core::iter::FromIterator for SmallVec { #[inline] fn from_iter>(iter: I) -> Self { @@ -2171,6 +2212,7 @@ impl core::iter::FromIterator for SmallVec { } } } + #[macro_export] macro_rules! smallvec { ($elem:expr; $n:expr) => ({ @@ -2180,6 +2222,7 @@ macro_rules! smallvec { $crate::SmallVec::from([$($($x),+)?]) }); } + #[macro_export] macro_rules! smallvec_inline { // count helper: transform any expression into 1 @@ -2192,6 +2235,7 @@ macro_rules! smallvec_inline { $crate::SmallVec::<_, N>::from_buf([$($x),*]) }); } + impl IntoIterator for SmallVec { type IntoIter = IntoIter; type Item = T; @@ -2210,6 +2254,7 @@ impl IntoIterator for SmallVec { } } } + impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { type IntoIter = core::slice::Iter<'a, T>; type Item = &'a T; @@ -2217,6 +2262,7 @@ impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { self.iter() } } + impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { type IntoIter = core::slice::IterMut<'a, T>; type Item = &'a mut T; @@ -2224,23 +2270,28 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { self.iter_mut() } } + impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } + impl Debug for SmallVec { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list().entries(self.iter()).finish() } } + impl Debug for IntoIter { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } + impl Debug for Drain<'_, T, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } + diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs index 7a49d86..1f7677d 100644 --- a/src/mallocsizeof.rs +++ b/src/mallocsizeof.rs @@ -2,6 +2,7 @@ use { super::SmallVec, malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}, }; + impl MallocShallowSizeOf for SmallVec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { if self.spilled() { @@ -11,6 +12,7 @@ impl MallocShallowSizeOf for SmallVec { } } } + impl MallocSizeOf for SmallVec { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = self.shallow_size_of(ops); @@ -19,4 +21,4 @@ impl MallocSizeOf for SmallVec { } n } -} +} \ No newline at end of file diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 2f501f0..7cd0ceb 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -6,6 +6,7 @@ use { ptr::{copy_nonoverlapping, NonNull}, }, }; + /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. /// @@ -16,6 +17,7 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize), } + impl RawSmallVec { pub const IS_ZST: bool = size_of::() == 0; #[inline] @@ -111,4 +113,4 @@ impl RawSmallVec { *self = Self::new_heap(new_ptr, new_capacity); Ok(()) } -} +} \ No newline at end of file diff --git a/src/references.rs b/src/references.rs index fff4b4b..47f633a 100644 --- a/src/references.rs +++ b/src/references.rs @@ -2,6 +2,7 @@ use { super::SmallVec, core::borrow::{Borrow, BorrowMut}, }; + impl core::ops::Deref for SmallVec { type Target = [T]; #[inline] @@ -9,33 +10,39 @@ impl core::ops::Deref for SmallVec { self.as_slice() } } + impl core::ops::DerefMut for SmallVec { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } + impl AsRef<[T]> for SmallVec { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } + impl AsMut<[T]> for SmallVec { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } + impl Borrow<[T]> for SmallVec { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } + impl BorrowMut<[T]> for SmallVec { #[inline] fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } + diff --git a/src/serde.rs b/src/serde.rs index 18fb2a3..8b34929 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -7,6 +7,7 @@ use { Deserialize, Deserializer, Serialize, Serializer, }, }; + impl Serialize for SmallVec where T: Serialize, @@ -19,6 +20,7 @@ where state.end() } } + impl<'de, T, const N: usize> Deserialize<'de> for SmallVec where T: Deserialize<'de>, @@ -29,9 +31,11 @@ where }) } } + struct SmallVecVisitor { phantom: PhantomData, } + impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor where T: Deserialize<'de>, @@ -54,3 +58,4 @@ where Ok(values) } } + diff --git a/src/std.rs b/src/std.rs index b9e2568..bb6146a 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,5 +1,7 @@ extern crate std; + use {super::SmallVec, std::io}; + #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl io::Write for SmallVec { @@ -17,4 +19,4 @@ impl io::Write for SmallVec { fn flush(&mut self) -> io::Result<()> { Ok(()) } -} +} \ No newline at end of file diff --git a/src/taggedlen.rs b/src/taggedlen.rs index acc97fa..1a13d90 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; + /// Vec guarantees that its length is always less than [`isize::MAX`] in /// *bytes*. /// @@ -22,7 +23,9 @@ impl Clone for TaggedLen { self.0 = source.0; } } + impl Copy for TaggedLen {} + impl TaggedLen { const IS_ZST: bool = size_of::() == 0; #[inline] diff --git a/src/tests.rs b/src/tests.rs index d4af1a4..57cb4ca 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -4,6 +4,7 @@ use { alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec::Vec}, core::{hash::Hasher, iter::FromIterator}, }; + #[test] pub fn test_zero() { let mut v = SmallVec::<_, 0>::new(); @@ -12,6 +13,7 @@ pub fn test_zero() { assert!(v.spilled()); assert_eq!(&*v, &[0]); } + // We heap allocate all these strings so that double frees will show up under // valgrind. #[test] @@ -21,6 +23,7 @@ pub fn test_inline() { v.push("there".to_owned()); assert_eq!(&*v, &["hello".to_owned(), "there".to_owned(),][..]); } + #[test] pub fn test_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -40,6 +43,7 @@ pub fn test_spill() { ][..] ); } + #[test] pub fn test_double_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -65,16 +69,19 @@ pub fn test_double_spill() { ][..] ); } + // https://github.com/servo/rust-smallvec/issues/4 #[test] fn issue_4() { SmallVec::, 2>::new(); } + // https://github.com/servo/rust-smallvec/issues/5 #[test] fn issue_5() { assert!(Some(SmallVec::<&u32, 2>::new()).is_some()); } + #[test] fn test_with_capacity() { let v: SmallVec = SmallVec::with_capacity(1); @@ -86,6 +93,7 @@ fn test_with_capacity() { assert!(v.spilled()); assert_eq!(v.capacity(), 10); } + #[test] fn drain() { let mut v: SmallVec = SmallVec::new(); @@ -106,6 +114,7 @@ fn drain() { v.push(2); assert_eq!(v.drain(..1).collect::>(), &[1]); } + #[test] fn drain_rev() { let mut v: SmallVec = SmallVec::new(); @@ -117,12 +126,14 @@ fn drain_rev() { v.push(5); assert_eq!(v.drain(..).rev().collect::>(), &[5, 4, 3]); } + #[test] fn drain_forget() { let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6, 7]; std::mem::forget(v.drain(2..5)); assert_eq!(v.len(), 2); } + #[test] fn splice() { // The range starts right before the end. @@ -144,6 +155,7 @@ fn splice() { assert_eq!(v, [7, 8, 9, 10, 3, 4, 5, 6]); assert_eq!(u, [0, 1, 2]); } + #[test] fn into_iter() { let mut v: SmallVec = SmallVec::new(); @@ -156,6 +168,7 @@ fn into_iter() { v.push(5); assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); } + #[test] fn into_iter_rev() { let mut v: SmallVec = SmallVec::new(); @@ -168,6 +181,7 @@ fn into_iter_rev() { v.push(5); assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); } + #[test] fn into_iter_drop() { use std::cell::Cell; @@ -215,6 +229,7 @@ fn into_iter_drop() { assert_eq!(cell.get(), 3); } } + #[test] fn test_capacity() { let mut v: SmallVec = SmallVec::new(); @@ -230,6 +245,7 @@ fn test_capacity() { v.shrink_to_fit(); assert!(v.capacity() < 0x100); } + #[test] fn test_truncate() { let mut v: SmallVec, 8> = SmallVec::new(); @@ -244,6 +260,7 @@ fn test_truncate() { v.insert(1, Box::new(3)); assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); } + #[test] fn test_truncate_references() { let mut v = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]); @@ -260,6 +277,7 @@ fn test_truncate_references() { &[&mut 0, &mut 8, &mut 2] ); } + #[test] fn test_split_off() { let mut vec: SmallVec = smallvec![1, 2, 3, 4, 5, 6]; @@ -271,6 +289,7 @@ fn test_split_off() { assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); } + #[test] fn test_split_off_take_all() { // Allocate enough capacity that we can tell whether the split-off vector's @@ -289,6 +308,7 @@ fn test_split_off_take_all() { assert!(split_off.capacity() < orig_capacity); assert_ne!(split_off.as_ptr(), orig_ptr); } + #[test] fn test_append() { let mut v: SmallVec = SmallVec::new(); @@ -305,6 +325,7 @@ fn test_append() { &[0, 1, 2, 3, 5, 6] ); } + #[test] #[should_panic] fn test_invalid_grow() { @@ -312,12 +333,14 @@ fn test_invalid_grow() { v.extend(0..8); v.grow(5); } + #[test] #[should_panic] fn drain_overflow() { let mut v: SmallVec = smallvec![0]; v.drain(..=usize::MAX); } + #[test] fn test_extend_from_slice() { let mut v: SmallVec = SmallVec::new(); @@ -331,6 +354,7 @@ fn test_extend_from_slice() { &[0, 1, 2, 3, 5, 6] ); } + #[test] fn test_extend_from_within() { let mut v: SmallVec = smallvec![0, 1, 2, 3]; @@ -340,6 +364,7 @@ fn test_extend_from_within() { &[0, 1, 2, 3, 1, 2], ); } + #[test] #[should_panic] fn test_drop_panic_smallvec() { @@ -354,6 +379,7 @@ fn test_drop_panic_smallvec() { let mut v = SmallVec::<_, 1>::new(); v.push(DropPanic); } + #[test] fn test_eq() { let mut a: SmallVec = SmallVec::new(); @@ -371,6 +397,7 @@ fn test_eq() { assert!(a == b); assert!(a != c); } + #[test] fn test_ord() { let mut a: SmallVec = SmallVec::new(); @@ -389,6 +416,7 @@ fn test_ord() { assert!(b < c); assert!(c > b); } + #[test] fn test_hash() { use std::{collections::hash_map::DefaultHasher, hash::Hash}; @@ -410,6 +438,7 @@ fn test_hash() { assert_eq!(hash(a), hash(b)); } } + #[test] fn test_as_ref() { let mut a: SmallVec = SmallVec::new(); @@ -420,6 +449,7 @@ fn test_as_ref() { a.push(3); assert_eq!(a.as_ref(), [1, 2, 3]); } + #[test] fn test_as_mut() { let mut a: SmallVec = SmallVec::new(); @@ -432,6 +462,7 @@ fn test_as_mut() { a.as_mut()[1] = 4; assert_eq!(a.as_mut(), [1, 4, 3]); } + #[test] fn test_borrow() { use std::borrow::Borrow; @@ -443,6 +474,7 @@ fn test_borrow() { a.push(3); assert_eq!(a.borrow(), [1, 2, 3]); } + #[test] fn test_borrow_mut() { use std::borrow::BorrowMut; @@ -456,6 +488,7 @@ fn test_borrow_mut() { BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; assert_eq!(a.borrow_mut(), [1, 4, 3]); } + #[test] fn test_from() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); @@ -499,11 +532,13 @@ fn test_from() { assert_eq!(&*small_vec, &[99u8]); drop(small_vec); } + #[test] fn test_from_slice() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); } + #[test] fn test_exact_size_iterator() { let mut vec = SmallVec::::from(&[1, 2, 3][..]); @@ -511,6 +546,7 @@ fn test_exact_size_iterator() { assert_eq!(vec.drain(..2).len(), 2); assert_eq!(vec.into_iter().len(), 1); } + #[test] fn test_into_iter_as_slice() { let vec = SmallVec::::from(&[1, 2, 3][..]); @@ -524,6 +560,7 @@ fn test_into_iter_as_slice() { assert_eq!(iter.as_slice(), &[2]); assert_eq!(iter.as_mut_slice(), &[2]); } + #[test] fn test_into_iter_clone() { // Test that the cloned iterator yields identical elements and that it owns its @@ -535,6 +572,7 @@ fn test_into_iter_clone() { } assert_eq!(clone_iter.next(), None); } + #[test] fn test_into_iter_clone_partially_consumed_iterator() { // Test that the cloned iterator only contains the remaining elements of the @@ -546,6 +584,7 @@ fn test_into_iter_clone_partially_consumed_iterator() { } assert_eq!(clone_iter.next(), None); } + #[test] fn test_into_iter_clone_empty_smallvec() { let mut iter = SmallVec::::new().into_iter(); @@ -553,6 +592,7 @@ fn test_into_iter_clone_empty_smallvec() { assert_eq!(iter.next(), None); assert_eq!(clone_iter.next(), None); } + #[test] fn shrink_to_fit_unspill() { let mut vec = SmallVec::::from_iter(0..3); @@ -561,12 +601,14 @@ fn shrink_to_fit_unspill() { vec.shrink_to_fit(); assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible"); } + #[test] fn shrink_after_from_empty_vec() { let mut v = SmallVec::::from_vec(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } + #[test] fn test_into_vec() { let vec = SmallVec::::from_iter(0..2); @@ -574,6 +616,7 @@ fn test_into_vec() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.into_vec(), Vec::from([0, 1, 2])); } + #[test] fn test_into_inner() { let vec = SmallVec::::from_iter(0..2); @@ -583,6 +626,7 @@ fn test_into_inner() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.clone().into_inner(), Err(vec)); } + #[test] fn test_from_vec() { let vec = Vec::new(); @@ -610,6 +654,7 @@ fn test_from_vec() { assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); } + #[test] fn test_retain() { // Test inline data storage @@ -641,6 +686,7 @@ fn test_retain() { sv.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); } + #[test] fn test_dedup() { let mut dupes: SmallVec = SmallVec::from(&[1, 1, 2, 3, 3]); @@ -656,6 +702,7 @@ fn test_dedup() { no_dupes.dedup(); assert_eq!(no_dupes.len(), 5); } + #[test] fn test_resize() { let mut v: SmallVec = SmallVec::new(); @@ -665,6 +712,7 @@ fn test_resize() { v.resize(2, -1); assert_eq!(v[..], [1, 0][..]); } + #[cfg(feature = "std")] #[test] fn test_write() { @@ -678,6 +726,7 @@ fn test_write() { small_vec.write_all(&data[..]).unwrap(); assert_eq!(small_vec.as_ref(), data.as_ref()); } + #[cfg(feature = "serde")] #[test] fn test_serde() { @@ -702,6 +751,7 @@ fn test_serde() { ], ); } + #[test] fn grow_to_shrink() { let mut v: SmallVec = SmallVec::new(); @@ -718,6 +768,7 @@ fn grow_to_shrink() { v.push(4); assert_eq!(v[..], [4]); } + #[test] fn resumable_extend() { let s = "a b c"; @@ -729,12 +780,14 @@ fn resumable_extend() { v.extend(it); assert_eq!(v[..], ['a']); } + // #139 #[test] fn uninhabited() { enum Void {} let _sv = SmallVec::::new(); } + #[test] fn grow_spilled_same_size() { let mut v: SmallVec = SmallVec::new(); @@ -748,10 +801,12 @@ fn grow_spilled_same_size() { assert_eq!(v.capacity(), 4); assert_eq!(v[..], [0, 1, 2]); } + #[test] fn const_generics() { let _v = SmallVec::::default(); } + #[test] fn const_new() { let v = const_new_inner(); @@ -767,23 +822,29 @@ fn const_new() { assert_eq!(v[0], 1); assert_eq!(v[1], 4); } + const fn const_new_inner() -> SmallVec { SmallVec::::new() } + const fn const_new_inline_sized() -> SmallVec { crate::smallvec_inline![1; 4] } + const fn const_new_inline_args() -> SmallVec { crate::smallvec_inline![1, 4] } + #[test] fn empty_macro() { let _v: SmallVec = smallvec![]; } + #[test] fn zero_size_items() { SmallVec::<(), 0>::new().push(()); } + #[test] fn test_clone_from() { let mut a: SmallVec = SmallVec::new(); @@ -801,6 +862,7 @@ fn test_clone_from() { b.clone_from(&c); assert_eq!(&*b, &[20, 21, 22]); } + #[test] fn test_extract_if() { let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; @@ -808,6 +870,7 @@ fn test_extract_if() { assert_eq!(a, SmallVec::::from(&[0, 1u8, 2, 4, 5, 7, 8, 0])); assert_eq!(b, SmallVec::::from(&[3u8, 6])); } + /// This assortment of tests, in combination with miri, verifies we handle UB on /// fishy arguments given to SmallVec. Draining and extending the allocation are /// fairly well-tested earlier, but `smallvec.insert(usize::MAX, val)` once @@ -821,24 +884,28 @@ fn max_dont_panic() { let _ = sv.get(usize::MAX); sv.truncate(usize::MAX); } + #[test] #[should_panic] fn max_remove() { let mut sv: SmallVec = smallvec![0]; sv.remove(usize::MAX); } + #[test] #[should_panic] fn max_swap_remove() { let mut sv: SmallVec = smallvec![0]; sv.swap_remove(usize::MAX); } + #[test] #[should_panic] fn max_insert() { let mut sv: SmallVec = smallvec![0]; sv.insert(usize::MAX, 0); } + #[test] fn collect_from_iter() { // Regression test for https://github.com/servo/rust-smallvec/issues/353 @@ -857,12 +924,14 @@ fn collect_from_iter() { let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); let _y: SmallVec = SmallVec::from_iter(iter); } + #[test] fn test_collect_with_spill() { let input = "0123456"; let collected: SmallVec = input.chars().collect(); assert_eq!(collected, &['0', '1', '2', '3', '4', '5', '6']); } + #[test] fn test_spare_capacity_mut() { let mut v: SmallVec = SmallVec::new(); @@ -886,6 +955,7 @@ fn test_spare_capacity_mut() { assert!(spare.len() >= 1); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(3) }); } + // Adopted from `tests/test_buf_mut.rs` in the `bytes` crate. #[cfg(feature = "bytes")] mod buf_mut { @@ -960,3 +1030,4 @@ mod buf_mut { } } } + From c797f4da20f1f639769fb1b247c66dc5ec0e321b Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 26 Aug 2026 14:15:45 +0200 Subject: [PATCH 10/15] fix: style check --- src/bytes.rs | 2 +- src/comparisons.rs | 1 - src/conversions.rs | 2 +- src/lib.rs | 2 -- src/mallocsizeof.rs | 2 +- src/rawsmallvec.rs | 2 +- src/references.rs | 1 - src/serde.rs | 1 - src/std.rs | 2 +- src/tests.rs | 1 - 10 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index 9472993..8880fb9 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -58,4 +58,4 @@ unsafe impl BufMut for SmallVec { let new_len = self.len().saturating_add(cnt); self.resize(new_len, val); } -} \ No newline at end of file +} diff --git a/src/comparisons.rs b/src/comparisons.rs index a9019ea..eec29d7 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -81,4 +81,3 @@ where self.as_slice().cmp(other.as_slice()) } } - diff --git a/src/conversions.rs b/src/conversions.rs index 86eea89..a7b4d40 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -74,4 +74,4 @@ impl From<&[T; M]> for SmallVec fn from(slice: &[T; M]) -> Self { Self::from(slice as &[T]) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index d48c2d8..163c578 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,6 @@ use { ptr::{copy, copy_nonoverlapping, NonNull}, }, }; - #[cfg(feature = "internals")] pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; #[cfg(not(feature = "internals"))] @@ -2294,4 +2293,3 @@ impl Debug for Drain<'_, T, N> { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } - diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs index 1f7677d..6377b63 100644 --- a/src/mallocsizeof.rs +++ b/src/mallocsizeof.rs @@ -21,4 +21,4 @@ impl MallocSizeOf for SmallVec { } n } -} \ No newline at end of file +} diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 7cd0ceb..2463836 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -113,4 +113,4 @@ impl RawSmallVec { *self = Self::new_heap(new_ptr, new_capacity); Ok(()) } -} \ No newline at end of file +} diff --git a/src/references.rs b/src/references.rs index 47f633a..fe93e8b 100644 --- a/src/references.rs +++ b/src/references.rs @@ -45,4 +45,3 @@ impl BorrowMut<[T]> for SmallVec { self.as_mut_slice() } } - diff --git a/src/serde.rs b/src/serde.rs index 8b34929..5e16f41 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -58,4 +58,3 @@ where Ok(values) } } - diff --git a/src/std.rs b/src/std.rs index bb6146a..e743b92 100644 --- a/src/std.rs +++ b/src/std.rs @@ -19,4 +19,4 @@ impl io::Write for SmallVec { fn flush(&mut self) -> io::Result<()> { Ok(()) } -} \ No newline at end of file +} diff --git a/src/tests.rs b/src/tests.rs index 57cb4ca..6cc7cb8 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1030,4 +1030,3 @@ mod buf_mut { } } } - From 4c15dbc87628490d1b6c16fb845abfb4833717e9 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 26 Aug 2026 18:16:08 +0000 Subject: [PATCH 11/15] chore: added wiki to readme (#442) --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e9b253c..98821fe 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,26 @@ rust-smallvec ============= -> **⚠️ Note:** -> This is the code for smallvec 2.0, which is not yet ready for release. For -> details about the changes in version 2.0, please see [#183], [#240], and [#284]. -> The status of the v2 branch is tracked on [#425]. +> [!IMPORTANT] +> This branch contains the code for SmallVec v2, which is not yet ready for release. +> If your code is using any of the alpha version of SmallVec, beware that the API might +> change between versions. +> +> The status of v2 can be tracked in: +> - [its tracking issue](https://github.com/servo/rust-smallvec/issues/425) +> - [the wiki spec](https://github.com/servo/rust-smallvec/wiki) > > The source code for the latest smallvec 1.x.y release can be found on the -> [v1 branch]. Bug fixes for smallvec 1 should be based on that branch, while +> [v1 branch](https://github.com/servo/rust-smallvec/tree/v1). +> Bug fixes for smallvec v1 should be based on that branch, while > new feature development should go on the v2 branch. -[v1 branch]: https://github.com/servo/rust-smallvec/tree/v1 -[#183]: https://github.com/servo/rust-smallvec/issues/183 -[#240]: https://github.com/servo/rust-smallvec/issues/240 -[#284]: https://github.com/servo/rust-smallvec/issues/284 -[#425]: https://github.com/servo/rust-smallvec/issues/425 - ## About smallvec [Documentation](https://docs.rs/smallvec/) +[Wiki](https://github.com/servo/rust-smallvec/wiki) + [Release notes](https://github.com/servo/rust-smallvec/releases) "Small vector" optimization for Rust: store up to a small number of items on the stack From 383a91e90f7dd0f914e47c58da5f2a328cb64ecc Mon Sep 17 00:00:00 2001 From: bolshoytoster <91278344+bolshoytoster@users.noreply.github.com> Date: Wed, 26 Aug 2026 18:55:42 +0000 Subject: [PATCH 12/15] Deprecate smallvec! and smallvec_inline! (#445) * Deprecate smallvec! and smallvec_inline! * Disallow single comma as macro input --- src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 163c578..45d7a53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2212,6 +2212,7 @@ impl core::iter::FromIterator for SmallVec { } } +#[deprecated] #[macro_export] macro_rules! smallvec { ($elem:expr; $n:expr) => ({ @@ -2222,16 +2223,14 @@ macro_rules! smallvec { }); } +#[deprecated] #[macro_export] macro_rules! smallvec_inline { - // count helper: transform any expression into 1 - (@one $x:expr) => (1usize); ($elem:expr; $n:expr) => ({ $crate::SmallVec::<_, $n>::from_buf([$elem; $n]) }); - ($($x:expr),+ $(,)?) => ({ - const N: usize = 0usize $(+ $crate::smallvec_inline!(@one $x))*; - $crate::SmallVec::<_, N>::from_buf([$($x),*]) + ($($($x:expr),+$(,)?)?) => ({ + $crate::SmallVec::from_buf([$($($x),+)?]) }); } From 01e6e934456a8407b42da9adab6c469b9813b5ad Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Sun, 23 Aug 2026 23:05:50 +0200 Subject: [PATCH 13/15] feat: added bytes, serde, std, taggedlen files --- src/allocationerror.rs | 6 ++ src/bytes.rs | 44 ++++++++ src/lib.rs | 221 +++++++++++++++++++++++++++++++++++++---- src/rawsmallvec.rs | 57 +++++++++++ src/serde.rs | 25 +++++ src/std.rs | 17 ++++ src/taggedlen.rs | 20 ++++ src/tests.rs | 11 ++ 8 files changed, 383 insertions(+), 18 deletions(-) diff --git a/src/allocationerror.rs b/src/allocationerror.rs index 8c657a0..71451d2 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -1,3 +1,4 @@ +<<<<<<< HEAD use { alloc::alloc::Layout, core::{ @@ -5,6 +6,11 @@ use { fmt::{Display, Formatter, Result as Format}, }, }; +======= +use alloc::alloc::Layout; +use core::error::Error; +use core::fmt::{Display, Formatter, Result as Format}; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) /// Error type for APIs with fallible heap allocation #[derive(Debug)] diff --git a/src/bytes.rs b/src/bytes.rs index 8880fb9..09c2b58 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1,7 +1,12 @@ +<<<<<<< HEAD use { super::SmallVec, bytes::{buf::UninitSlice, BufMut}, }; +======= +use bytes::{buf::UninitSlice, BufMut}; +use super::SmallVec; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) unsafe impl BufMut for SmallVec { #[inline] @@ -9,29 +14,56 @@ unsafe impl BufMut for SmallVec { // A vector can never have more than isize::MAX bytes isize::MAX as usize - self.len() } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] unsafe fn advance_mut(&mut self, cnt: usize) { let len = self.len(); let remaining = self.capacity() - len; +<<<<<<< HEAD if remaining < cnt { panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); } // Addition will not overflow since the sum is at most the capacity. self.set_len(len + cnt); } +======= + + if remaining < cnt { + panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); + } + + // Addition will not overflow since the sum is at most the capacity. + self.set_len(len + cnt); + } + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn chunk_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); // Grow the smallvec } +<<<<<<< HEAD let cap = self.capacity(); let len = self.len(); +======= + + let cap = self.capacity(); + let len = self.len(); + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) let ptr = self.as_mut_ptr(); // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be // valid for `cap - len` bytes. The subtraction will not underflow since // `len <= cap`. unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) // Specialize these methods so they can skip checking `remaining_mut` // and `advance_mut`. #[inline] @@ -41,6 +73,10 @@ unsafe impl BufMut for SmallVec { { // In case the src isn't contiguous, reserve upfront. self.reserve(src.remaining()); +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) while src.has_remaining() { let s = src.chunk(); let l = s.len(); @@ -48,10 +84,18 @@ unsafe impl BufMut for SmallVec { src.advance(l); } } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn put_bytes(&mut self, val: u8, cnt: usize) { // If the addition overflows, then the `resize` will fail. diff --git a/src/lib.rs b/src/lib.rs index 45d7a53..322408e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,15 +52,11 @@ #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #[doc(hidden)] pub extern crate alloc; + mod allocationerror; #[cfg(feature = "bytes")] mod bytes; -mod comparisons; -mod conversions; -#[cfg(feature = "malloc_size_of")] -mod mallocsizeof; mod rawsmallvec; -mod references; #[cfg(feature = "serde")] mod serde; #[cfg(feature = "std")] @@ -68,21 +64,37 @@ mod std; mod taggedlen; #[cfg(test)] mod tests; -pub use allocationerror::AllocationError; -use { - alloc::{alloc::Layout, boxed::Box, vec::Vec}, - core::{ - fmt::Debug, - hash::{Hash, Hasher}, - marker::PhantomData, - mem::{align_of, size_of, ManuallyDrop, MaybeUninit}, - ptr::{copy, copy_nonoverlapping, NonNull}, - }, -}; + +use alloc::alloc::Layout; +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; +use allocationerror::AllocationError; +use core::borrow::Borrow; +use core::borrow::BorrowMut; +use core::fmt::Debug; +use core::hash::{Hash, Hasher}; +use core::marker::PhantomData; +use core::mem::align_of; +use core::mem::size_of; +use core::mem::ManuallyDrop; +use core::mem::MaybeUninit; +use core::ptr::copy; +use core::ptr::copy_nonoverlapping; +use core::ptr::NonNull; +#[cfg(feature = "malloc_size_of")] +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "internals")] -pub use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; +pub use { + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen +}; #[cfg(not(feature = "internals"))] -use {rawsmallvec::RawSmallVec, taggedlen::TaggedLen}; +use { + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen +}; + #[inline] fn infallible(result: Result) -> T { match result { @@ -678,6 +690,7 @@ impl SmallVec { impl SmallVec { const IS_ZST: bool = size_of::() == 0; + #[inline] pub fn from_vec(vec: Vec) -> Self { if vec.capacity() == 0 { @@ -2292,3 +2305,175 @@ impl Debug for Drain<'_, T, N> { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl Serialize for SmallVec +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result { + let mut state = serializer.serialize_seq(Some(self.len()))?; + for item in self { + state.serialize_element(item)?; + } + state.end() + } +} + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl<'de, T, const N: usize> Deserialize<'de> for SmallVec +where + T: Deserialize<'de>, +{ + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_seq(SmallVecVisitor { + phantom: PhantomData, + }) + } +} + +#[cfg(feature = "serde")] +struct SmallVecVisitor { + phantom: PhantomData, +} + +#[cfg(feature = "serde")] +impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor +where + T: Deserialize<'de>, +{ + type Value = SmallVec; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: B) -> Result + where + B: SeqAccess<'de>, + { + use serde_core::de::Error; + let len = seq.size_hint().unwrap_or(0); + let mut values = SmallVec::new(); + values.try_reserve(len).map_err(B::Error::custom)?; + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } +} + +#[cfg(feature = "malloc_size_of")] +impl MallocShallowSizeOf for SmallVec { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if self.spilled() { + unsafe { ops.malloc_size_of(self.as_ptr()) } + } else { + 0 + } + } +} + +#[cfg(feature = "malloc_size_of")] +impl MallocSizeOf for SmallVec { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl io::Write for SmallVec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "bytes")] +unsafe impl BufMut for SmallVec { + #[inline] + fn remaining_mut(&self) -> usize { + // A vector can never have more than isize::MAX bytes + isize::MAX as usize - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let len = self.len(); + let remaining = self.capacity() - len; + + if remaining < cnt { + panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); + } + + // Addition will not overflow since the sum is at most the capacity. + self.set_len(len + cnt); + } + + #[inline] + fn chunk_mut(&mut self) -> &mut UninitSlice { + if self.capacity() == self.len() { + self.reserve(64); // Grow the smallvec + } + + let cap = self.capacity(); + let len = self.len(); + + let ptr = self.as_mut_ptr(); + // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be + // valid for `cap - len` bytes. The subtraction will not underflow since + // `len <= cap`. + unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } + } + + // Specialize these methods so they can skip checking `remaining_mut` + // and `advance_mut`. + #[inline] + fn put(&mut self, mut src: T) + where + Self: Sized, + { + // In case the src isn't contiguous, reserve upfront. + self.reserve(src.remaining()); + + while src.has_remaining() { + let s = src.chunk(); + let l = s.len(); + self.extend_from_slice(s); + src.advance(l); + } + } + + #[inline] + fn put_slice(&mut self, src: &[u8]) { + self.extend_from_slice(src); + } + + #[inline] + fn put_bytes(&mut self, val: u8, cnt: usize) { + // If the addition overflows, then the `resize` will fail. + let new_len = self.len().saturating_add(cnt); + self.resize(new_len, val); + } +} diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 2463836..96eaed4 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,3 +1,4 @@ +<<<<<<< HEAD use { super::{allocationerror::AllocationError, TaggedLen}, alloc::alloc::Layout, @@ -6,6 +7,14 @@ use { ptr::{copy_nonoverlapping, NonNull}, }, }; +======= +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ptr::NonNull; +use super::TaggedLen; +use super::allocationerror::AllocationError; +use core::ptr::copy_nonoverlapping; +use alloc::alloc::Layout; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. @@ -20,6 +29,10 @@ pub union RawSmallVec { impl RawSmallVec { pub const IS_ZST: bool = size_of::() == 0; +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] pub const fn new() -> Self { Self::new_inline(MaybeUninit::uninit()) @@ -36,6 +49,10 @@ impl RawSmallVec { heap: (ptr, capacity), } } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] pub const fn as_ptr_inline(&self) -> *const T { // SAFETY: it is safe because we aren't reading the value, just getting a @@ -44,12 +61,20 @@ impl RawSmallVec { #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] (unsafe { &raw const self.inline }).cast::() } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] pub const fn as_mut_ptr_inline(&mut self) -> *mut T { // SAFETY: same as above #[allow(unused_unsafe, reason = "requires unsafe in MSRV")] (unsafe { &raw mut self.inline }).cast::() } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) /// # Safety /// /// The vector must be on the heap @@ -57,6 +82,10 @@ impl RawSmallVec { pub const unsafe fn as_ptr_heap(&self) -> *const T { self.heap.0.as_ptr() } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) /// # Safety /// /// The vector must be on the heap @@ -64,6 +93,10 @@ impl RawSmallVec { pub const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { self.heap.0.as_ptr() } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) /// # Safety /// /// `new_capacity` must be non zero, and greater or equal to the length. @@ -77,6 +110,10 @@ impl RawSmallVec { debug_assert!(!Self::IS_ZST); debug_assert!(new_capacity > 0); debug_assert!(new_capacity >= len.value()); +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) let was_on_heap = len.on_heap(); let ptr = if was_on_heap { self.as_mut_ptr_heap() @@ -84,11 +121,19 @@ impl RawSmallVec { self.as_mut_ptr_inline() }; let len = len.value(); +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) let new_layout = Layout::array::(new_capacity).map_err(|_| AllocationError::CapacityOverflow)?; if new_layout.size() > isize::MAX as usize { return Err(AllocationError::CapacityOverflow); } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) let new_ptr = if len == 0 || !was_on_heap { // get a fresh allocation let new_ptr = alloc(new_layout) as *mut T; // `new_layout` has nonzero size. @@ -98,10 +143,18 @@ impl RawSmallVec { new_ptr } else { // use realloc +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) // this can't overflow since we already constructed an equivalent layout during // the previous allocation let old_layout = Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) // SAFETY: ptr was allocated with this allocator // old_layout is the same as the layout used to allocate the previous memory // block new_layout.size() is greater than zero @@ -113,4 +166,8 @@ impl RawSmallVec { *self = Self::new_heap(new_ptr, new_capacity); Ok(()) } +<<<<<<< HEAD +} +======= } +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) diff --git a/src/serde.rs b/src/serde.rs index 5e16f41..742e43a 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -1,3 +1,4 @@ +<<<<<<< HEAD use { super::SmallVec, core::marker::PhantomData, @@ -7,6 +8,11 @@ use { Deserialize, Deserializer, Serialize, Serializer, }, }; +======= +use serde_core::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, SeqAccess}, ser::SerializeSeq}; +use super::SmallVec; +use core::marker::PhantomData; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) impl Serialize for SmallVec where @@ -41,9 +47,17 @@ where T: Deserialize<'de>, { type Value = SmallVec; +<<<<<<< HEAD fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a sequence") } +======= + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a sequence") + } + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) fn visit_seq(self, mut seq: B) -> Result where B: SeqAccess<'de>, @@ -52,9 +66,20 @@ where let len = seq.size_hint().unwrap_or(0); let mut values = SmallVec::new(); values.try_reserve(len).map_err(B::Error::custom)?; +<<<<<<< HEAD while let Some(value) = seq.next_element()? { values.push(value); } Ok(values) } } +======= + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } +} +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) diff --git a/src/std.rs b/src/std.rs index e743b92..ce1ad3d 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,6 +1,11 @@ extern crate std; +<<<<<<< HEAD use {super::SmallVec, std::io}; +======= +use super::SmallVec; +use std::io; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] @@ -10,13 +15,25 @@ impl io::Write for SmallVec { self.extend_from_slice(buf); Ok(buf.len()) } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.extend_from_slice(buf); Ok(()) } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } +<<<<<<< HEAD +} +======= } +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) diff --git a/src/taggedlen.rs b/src/taggedlen.rs index 1a13d90..27844ca 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -11,6 +11,10 @@ use core::marker::PhantomData; /// For a ZST, we never use the heap, so we just store the length directly. #[repr(transparent)] pub struct TaggedLen(usize, PhantomData); +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) // Clone and Copy must be manually implemented because the generic interferes // with the derive attribute implementations. impl Clone for TaggedLen { @@ -18,6 +22,10 @@ impl Clone for TaggedLen { fn clone(&self) -> Self { Self(self.0, PhantomData) } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] fn clone_from(&mut self, source: &Self) { self.0 = source.0; @@ -38,6 +46,10 @@ impl TaggedLen { Self((len << 1) | on_heap as usize, PhantomData) } } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] #[must_use] pub const fn on_heap(self) -> bool { @@ -47,6 +59,10 @@ impl TaggedLen { (self.0 & 1_usize) == 1 } } +<<<<<<< HEAD +======= + +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[inline] pub const fn value(self) -> usize { if Self::IS_ZST { @@ -55,4 +71,8 @@ impl TaggedLen { self.0 >> 1 } } +<<<<<<< HEAD +} +======= } +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) diff --git a/src/tests.rs b/src/tests.rs index 6cc7cb8..b7e31fc 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,9 +1,20 @@ extern crate std; +<<<<<<< HEAD use { crate::{smallvec, SmallVec}, alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec::Vec}, core::{hash::Hasher, iter::FromIterator}, }; +======= + +use crate::{smallvec, SmallVec}; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::rc::Rc; +use alloc::{vec, vec::Vec}; +use core::hash::Hasher; +use core::iter::FromIterator; +>>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) #[test] pub fn test_zero() { From 52330b9bfdc9cc4e1f1adba2c6cac55a089f5f2c Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 14:10:21 +0200 Subject: [PATCH 14/15] refactor: conversions file --- rustfmt.toml | 4 ++ src/allocationerror.rs | 5 +- src/bytes.rs | 30 +++++++- src/comparisons.rs | 8 --- src/conversions.rs | 18 +++++ src/lib.rs | 153 +++++++++++++++++++++++------------------ src/mallocsizeof.rs | 2 - src/rawsmallvec.rs | 37 +++++++++- src/references.rs | 5 -- src/serde.rs | 16 +++-- src/std.rs | 10 +++ src/taggedlen.rs | 15 +++- src/tests.rs | 72 ++----------------- 13 files changed, 216 insertions(+), 159 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 2fbbc2f..05339b2 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -4,7 +4,11 @@ group_imports = "One" format_code_in_doc_comments = true match_arm_blocks = false blank_lines_lower_bound = 0 +<<<<<<< HEAD blank_lines_upper_bound = 1 +======= +blank_lines_upper_bound = 0 +>>>>>>> 239c751 (refactor: conversions file) condense_wildcard_suffixes = true error_on_unformatted = true error_on_line_overflow = true \ No newline at end of file diff --git a/src/allocationerror.rs b/src/allocationerror.rs index 71451d2..baf2cbb 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -6,12 +6,15 @@ use { fmt::{Display, Formatter, Result as Format}, }, }; +<<<<<<< HEAD ======= use alloc::alloc::Layout; use core::error::Error; use core::fmt::{Display, Formatter, Result as Format}; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum AllocationError { @@ -23,11 +26,9 @@ pub enum AllocationError { layout: Layout, }, } - impl Display for AllocationError { fn fmt(&self, f: &mut Formatter) -> Format { write!(f, "Allocation error: {:?}", self) } } - impl Error for AllocationError {} diff --git a/src/bytes.rs b/src/bytes.rs index 09c2b58..f7ade1a 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -3,11 +3,14 @@ use { super::SmallVec, bytes::{buf::UninitSlice, BufMut}, }; +<<<<<<< HEAD ======= use bytes::{buf::UninitSlice, BufMut}; use super::SmallVec; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) unsafe impl BufMut for SmallVec { #[inline] fn remaining_mut(&self) -> usize { @@ -15,13 +18,17 @@ unsafe impl BufMut for SmallVec { isize::MAX as usize - self.len() } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] unsafe fn advance_mut(&mut self, cnt: usize) { let len = self.len(); let remaining = self.capacity() - len; +<<<<<<< HEAD <<<<<<< HEAD if remaining < cnt { panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); @@ -31,20 +38,25 @@ unsafe impl BufMut for SmallVec { } ======= +======= +>>>>>>> 239c751 (refactor: conversions file) if remaining < cnt { panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); } - // Addition will not overflow since the sum is at most the capacity. self.set_len(len + cnt); } +<<<<<<< HEAD >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn chunk_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); // Grow the smallvec } +<<<<<<< HEAD <<<<<<< HEAD let cap = self.capacity(); let len = self.len(); @@ -54,6 +66,10 @@ unsafe impl BufMut for SmallVec { let len = self.len(); >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= + let cap = self.capacity(); + let len = self.len(); +>>>>>>> 239c751 (refactor: conversions file) let ptr = self.as_mut_ptr(); // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be // valid for `cap - len` bytes. The subtraction will not underflow since @@ -61,9 +77,12 @@ unsafe impl BufMut for SmallVec { unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) // Specialize these methods so they can skip checking `remaining_mut` // and `advance_mut`. #[inline] @@ -74,9 +93,12 @@ unsafe impl BufMut for SmallVec { // In case the src isn't contiguous, reserve upfront. self.reserve(src.remaining()); <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) while src.has_remaining() { let s = src.chunk(); let l = s.len(); @@ -85,17 +107,23 @@ unsafe impl BufMut for SmallVec { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn put_bytes(&mut self, val: u8, cnt: usize) { // If the addition overflows, then the `resize` will fail. diff --git a/src/comparisons.rs b/src/comparisons.rs index eec29d7..70b307c 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -1,5 +1,4 @@ use super::SmallVec; - impl PartialEq> for SmallVec where T: PartialEq, @@ -11,7 +10,6 @@ where } impl Eq for SmallVec where T: Eq {} - impl PartialEq<[U; M]> for SmallVec where T: PartialEq, @@ -21,7 +19,6 @@ where self[..] == other[..] } } - impl PartialEq<&[U; M]> for SmallVec where T: PartialEq, @@ -31,7 +28,6 @@ where self[..] == other[..] } } - impl PartialEq<[U]> for SmallVec where T: PartialEq, @@ -41,7 +37,6 @@ where self[..] == other[..] } } - impl PartialEq<&[U]> for SmallVec where T: PartialEq, @@ -51,7 +46,6 @@ where self[..] == other[..] } } - impl PartialEq<&mut [U]> for SmallVec where T: PartialEq, @@ -61,7 +55,6 @@ where self[..] == other[..] } } - impl PartialOrd for SmallVec where T: PartialOrd, @@ -71,7 +64,6 @@ where self.as_slice().partial_cmp(other.as_slice()) } } - impl Ord for SmallVec where T: Ord, diff --git a/src/conversions.rs b/src/conversions.rs index a7b4d40..0cb6289 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -5,14 +5,20 @@ use { alloc::vec::Vec, core::{mem::ManuallyDrop, ptr::copy_nonoverlapping}, }; +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From<&mut [T; M]> for SmallVec { #[inline] fn from(slice: &mut [T; M]) -> Self { Self::from(slice as &[T]) } } +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From<[T; M]> for SmallVec { fn from(array: [T; M]) -> Self { if M > N { @@ -33,13 +39,19 @@ impl From<[T; M]> for SmallVec { } } } +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From> for SmallVec { fn from(array: Vec) -> Self { Self::from_vec(array) } } +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From<&[T]> for SmallVec { #[inline] fn from(slice: &[T]) -> Self { @@ -61,14 +73,20 @@ impl From<&[T]> for SmallVec { } } } +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From<&mut [T]> for SmallVec { #[inline] fn from(slice: &mut [T]) -> Self { Self::from(slice as &[T]) } } +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) impl From<&[T; M]> for SmallVec { #[inline] fn from(slice: &[T; M]) -> Self { diff --git a/src/lib.rs b/src/lib.rs index 322408e..c949c68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,10 +52,13 @@ #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #[doc(hidden)] pub extern crate alloc; - mod allocationerror; #[cfg(feature = "bytes")] mod bytes; +mod comparisons; +mod conversions; +#[cfg(feature = "malloc_size_of")] +mod mallocsizeof; mod rawsmallvec; #[cfg(feature = "serde")] mod serde; @@ -64,26 +67,17 @@ mod std; mod taggedlen; #[cfg(test)] mod tests; - -use alloc::alloc::Layout; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -use allocationerror::AllocationError; -use core::borrow::Borrow; -use core::borrow::BorrowMut; -use core::fmt::Debug; -use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use core::mem::align_of; -use core::mem::size_of; -use core::mem::ManuallyDrop; -use core::mem::MaybeUninit; -use core::ptr::copy; -use core::ptr::copy_nonoverlapping; -use core::ptr::NonNull; -#[cfg(feature = "malloc_size_of")] -use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; +use { + alloc::{alloc::Layout, boxed::Box, vec::Vec}, + allocationerror::AllocationError, + core::{ + fmt::Debug, + hash::{Hash, Hasher}, + marker::PhantomData, + mem::{align_of, size_of, ManuallyDrop, MaybeUninit}, + ptr::{copy, copy_nonoverlapping, NonNull}, + }, +}; #[cfg(feature = "internals")] pub use { rawsmallvec::RawSmallVec, @@ -103,7 +97,6 @@ fn infallible(result: Result) -> T { Err(AllocationError::Failure { layout }) => alloc::alloc::handle_alloc_error(layout), } } - #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -134,14 +127,12 @@ where } core::ops::Range { start, end } } - #[repr(C)] pub struct SmallVec { len: TaggedLen, raw: RawSmallVec, _marker: PhantomData, } - unsafe impl Send for SmallVec {} unsafe impl Sync for SmallVec {} impl Default for SmallVec { @@ -150,7 +141,6 @@ impl Default for SmallVec { Self::new() } } - /// An iterator that removes the items from a `SmallVec` and yields them by /// value. /// @@ -170,7 +160,6 @@ pub struct Drain<'a, T: 'a, const N: usize> { iter: core::slice::Iter<'a, T>, vec: core::ptr::NonNull>, } - impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { type Item = T; #[inline] @@ -186,7 +175,6 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { self.iter.size_hint() } } - impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { #[inline] fn next_back(&mut self) -> Option { @@ -196,14 +184,12 @@ impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { .map(|reference| unsafe { core::ptr::read(reference) }) } } - impl ExactSizeIterator for Drain<'_, T, N> { #[inline] fn len(&self) -> usize { self.iter.len() } } - impl core::iter::FusedIterator for Drain<'_, T, N> {} impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { fn drop(&mut self) { @@ -269,7 +255,6 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { } } } - impl Drain<'_, T, N> { #[must_use] pub fn as_slice(&self) -> &[T] { @@ -319,7 +304,6 @@ impl Drain<'_, T, N> { self.tail_start = new_tail_start; } } - /// An iterator which uses a closure to determine if an element should be /// removed. /// @@ -343,7 +327,6 @@ where /// The filter test predicate. pred: F, } - impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -355,7 +338,6 @@ where .finish() } } - impl Iterator for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -388,7 +370,6 @@ where (0, Some(self.end - self.idx)) } } - impl Drop for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -412,12 +393,10 @@ where } } } - pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, replace_with: I, } - impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: Debug + Iterator + 'a, @@ -427,7 +406,6 @@ where f.debug_tuple("Splice").field(&self.drain).finish() } } - impl Iterator for Splice<'_, I, N> { type Item = I::Item; fn next(&mut self) -> Option { @@ -437,13 +415,11 @@ impl Iterator for Splice<'_, I, N> { self.drain.size_hint() } } - impl DoubleEndedIterator for Splice<'_, I, N> { fn next_back(&mut self) -> Option { self.drain.next_back() } } - impl ExactSizeIterator for Splice<'_, I, N> {} impl Drop for Splice<'_, I, N> { fn drop(&mut self) { @@ -490,7 +466,6 @@ impl Drop for Splice<'_, I, N> { // `vec.len`. } } - /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. @@ -507,7 +482,6 @@ pub struct IntoIter { end: TaggedLen, _marker: PhantomData, } - // SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) // an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. unsafe impl Send for IntoIter where T: Send {} @@ -551,7 +525,6 @@ impl IntoIter { } } } - impl Iterator for IntoIter { type Item = T; #[inline] @@ -574,7 +547,6 @@ impl Iterator for IntoIter { (size, Some(size)) } } - impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { @@ -687,10 +659,8 @@ impl SmallVec { } } } - impl SmallVec { const IS_ZST: bool = size_of::() == 0; - #[inline] pub fn from_vec(vec: Vec) -> Self { if vec.capacity() == 0 { @@ -1512,7 +1482,6 @@ impl SmallVec { } } } - impl SmallVec { #[inline] pub fn resize(&mut self, len: usize, value: T) { @@ -1619,7 +1588,6 @@ impl SmallVec { result } } - struct DropGuard { ptr: *mut T, len: usize, @@ -1633,13 +1601,11 @@ impl Drop for DropGuard { } } } - struct DropDealloc { ptr: NonNull, size_bytes: usize, align: usize, } - impl Drop for DropDealloc { #[inline] fn drop(&mut self) { @@ -1653,7 +1619,6 @@ impl Drop for DropDealloc { } } } - #[cfg(feature = "may_dangle")] unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { fn drop(&mut self) { @@ -1677,7 +1642,6 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { } } } - #[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { @@ -1700,7 +1664,6 @@ impl Drop for SmallVec { } } } - impl Drop for IntoIter { fn drop(&mut self) { // SAFETY: see above @@ -1723,7 +1686,6 @@ impl Drop for IntoIter { } } } - /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using thís function. #[doc(hidden)] @@ -1746,7 +1708,6 @@ pub fn from_elem(elem: T, n: usize) -> SmallVec } } } - #[cfg(feature = "specialization")] mod spec_traits { use super::*; @@ -2016,7 +1977,6 @@ mod spec_traits { } } } - /// Fallback functions for various specialized methods. These are kept in /// a separate implementation block for easy access whenever specialization is /// disabled. @@ -2158,6 +2118,77 @@ impl SmallVec { } } +impl From<&[T]> for SmallVec { + #[inline] + fn from(slice: &[T]) -> Self { + if slice.len() > Self::inline_size() { + // Standard Rust vectors are already specialized. + Self::from_vec(Vec::from(slice)) + } else { + // SAFETY: The precondition is checked in the initial comparison above. + unsafe { + #[cfg(feature = "specialization")] + { + >::spec_from(slice) + } + + #[cfg(not(feature = "specialization"))] + { + Self::from_slice_fallback(slice) + } + } + } + } +} + +impl From<&mut [T]> for SmallVec { + #[inline] + fn from(slice: &mut [T]) -> Self { + Self::from(slice as &[T]) + } +} + +impl From<&[T; M]> for SmallVec { + #[inline] + fn from(slice: &[T; M]) -> Self { + Self::from(slice as &[T]) + } +} + +impl From<&mut [T; M]> for SmallVec { + #[inline] + fn from(slice: &mut [T; M]) -> Self { + Self::from(slice as &[T]) + } +} + +impl From<[T; M]> for SmallVec { + fn from(array: [T; M]) -> Self { + if M > N { + // If M > N, we'd have to heap allocate anyway, + // so delegate for Vec for the allocation. + Self::from(Vec::from(array)) + } else { + // M <= N + let mut this = Self::new(); + debug_assert!(M <= this.capacity()); + let array = ManuallyDrop::new(array); + // SAFETY: M <= this.capacity() + unsafe { + copy_nonoverlapping(array.as_ptr(), this.as_mut_ptr(), M); + this.set_len(M); + } + this + } + } +} + +impl From> for SmallVec { + fn from(array: Vec) -> Self { + Self::from_vec(array) + } +} + impl Clone for SmallVec { #[inline] fn clone(&self) -> SmallVec { @@ -2175,14 +2206,12 @@ impl Clone for SmallVec { } } } - impl Clone for IntoIter { #[inline] fn clone(&self) -> IntoIter { SmallVec::from(self.as_slice()).into_iter() } } - impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2196,7 +2225,6 @@ impl Extend for SmallVec { } } } - impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2210,7 +2238,6 @@ impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { } } } - impl core::iter::FromIterator for SmallVec { #[inline] fn from_iter>(iter: I) -> Self { @@ -2236,7 +2263,6 @@ macro_rules! smallvec { }); } -#[deprecated] #[macro_export] macro_rules! smallvec_inline { ($elem:expr; $n:expr) => ({ @@ -2246,7 +2272,6 @@ macro_rules! smallvec_inline { $crate::SmallVec::from_buf([$($($x),+)?]) }); } - impl IntoIterator for SmallVec { type IntoIter = IntoIter; type Item = T; @@ -2265,7 +2290,6 @@ impl IntoIterator for SmallVec { } } } - impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { type IntoIter = core::slice::Iter<'a, T>; type Item = &'a T; @@ -2273,7 +2297,6 @@ impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { self.iter() } } - impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { type IntoIter = core::slice::IterMut<'a, T>; type Item = &'a mut T; @@ -2281,25 +2304,21 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { self.iter_mut() } } - impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } - impl Debug for SmallVec { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list().entries(self.iter()).finish() } } - impl Debug for IntoIter { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } - impl Debug for Drain<'_, T, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs index 6377b63..7a49d86 100644 --- a/src/mallocsizeof.rs +++ b/src/mallocsizeof.rs @@ -2,7 +2,6 @@ use { super::SmallVec, malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}, }; - impl MallocShallowSizeOf for SmallVec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { if self.spilled() { @@ -12,7 +11,6 @@ impl MallocShallowSizeOf for SmallVec { } } } - impl MallocSizeOf for SmallVec { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = self.shallow_size_of(ops); diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 96eaed4..cbff6ae 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -7,6 +7,7 @@ use { ptr::{copy_nonoverlapping, NonNull}, }, }; +<<<<<<< HEAD ======= use core::mem::{ManuallyDrop, MaybeUninit}; use core::ptr::NonNull; @@ -16,6 +17,8 @@ use core::ptr::copy_nonoverlapping; use alloc::alloc::Layout; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. /// @@ -26,13 +29,15 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize), } - impl RawSmallVec { pub const IS_ZST: bool = size_of::() == 0; <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] pub const fn new() -> Self { Self::new_inline(MaybeUninit::uninit()) @@ -50,9 +55,12 @@ impl RawSmallVec { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] pub const fn as_ptr_inline(&self) -> *const T { // SAFETY: it is safe because we aren't reading the value, just getting a @@ -62,9 +70,12 @@ impl RawSmallVec { (unsafe { &raw const self.inline }).cast::() } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] pub const fn as_mut_ptr_inline(&mut self) -> *mut T { // SAFETY: same as above @@ -72,9 +83,12 @@ impl RawSmallVec { (unsafe { &raw mut self.inline }).cast::() } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) /// # Safety /// /// The vector must be on the heap @@ -83,9 +97,12 @@ impl RawSmallVec { self.heap.0.as_ptr() } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) /// # Safety /// /// The vector must be on the heap @@ -94,9 +111,12 @@ impl RawSmallVec { self.heap.0.as_ptr() } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) /// # Safety /// /// `new_capacity` must be non zero, and greater or equal to the length. @@ -111,9 +131,12 @@ impl RawSmallVec { debug_assert!(new_capacity > 0); debug_assert!(new_capacity >= len.value()); <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) let was_on_heap = len.on_heap(); let ptr = if was_on_heap { self.as_mut_ptr_heap() @@ -122,18 +145,24 @@ impl RawSmallVec { }; let len = len.value(); <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) let new_layout = Layout::array::(new_capacity).map_err(|_| AllocationError::CapacityOverflow)?; if new_layout.size() > isize::MAX as usize { return Err(AllocationError::CapacityOverflow); } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) let new_ptr = if len == 0 || !was_on_heap { // get a fresh allocation let new_ptr = alloc(new_layout) as *mut T; // `new_layout` has nonzero size. @@ -144,17 +173,23 @@ impl RawSmallVec { } else { // use realloc <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) // this can't overflow since we already constructed an equivalent layout during // the previous allocation let old_layout = Layout::from_size_align_unchecked(self.heap.1 * size_of::(), align_of::()); <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) // SAFETY: ptr was allocated with this allocator // old_layout is the same as the layout used to allocate the previous memory // block new_layout.size() is greater than zero diff --git a/src/references.rs b/src/references.rs index fe93e8b..a7da355 100644 --- a/src/references.rs +++ b/src/references.rs @@ -2,7 +2,6 @@ use { super::SmallVec, core::borrow::{Borrow, BorrowMut}, }; - impl core::ops::Deref for SmallVec { type Target = [T]; #[inline] @@ -17,28 +16,24 @@ impl core::ops::DerefMut for SmallVec { self.as_mut_slice() } } - impl AsRef<[T]> for SmallVec { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } - impl AsMut<[T]> for SmallVec { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } - impl Borrow<[T]> for SmallVec { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } - impl BorrowMut<[T]> for SmallVec { #[inline] fn borrow_mut(&mut self) -> &mut [T] { diff --git a/src/serde.rs b/src/serde.rs index 742e43a..63bc0cd 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -8,12 +8,15 @@ use { Deserialize, Deserializer, Serialize, Serializer, }, }; +<<<<<<< HEAD ======= use serde_core::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, SeqAccess}, ser::SerializeSeq}; use super::SmallVec; use core::marker::PhantomData; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) impl Serialize for SmallVec where T: Serialize, @@ -26,7 +29,6 @@ where state.end() } } - impl<'de, T, const N: usize> Deserialize<'de> for SmallVec where T: Deserialize<'de>, @@ -37,16 +39,15 @@ where }) } } - struct SmallVecVisitor { phantom: PhantomData, } - impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor where T: Deserialize<'de>, { type Value = SmallVec; +<<<<<<< HEAD <<<<<<< HEAD fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a sequence") @@ -58,6 +59,11 @@ where } >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a sequence") + } +>>>>>>> 239c751 (refactor: conversions file) fn visit_seq(self, mut seq: B) -> Result where B: SeqAccess<'de>, @@ -66,6 +72,7 @@ where let len = seq.size_hint().unwrap_or(0); let mut values = SmallVec::new(); values.try_reserve(len).map_err(B::Error::custom)?; +<<<<<<< HEAD <<<<<<< HEAD while let Some(value) = seq.next_element()? { values.push(value); @@ -75,10 +82,11 @@ where } ======= +======= +>>>>>>> 239c751 (refactor: conversions file) while let Some(value) = seq.next_element()? { values.push(value); } - Ok(values) } } diff --git a/src/std.rs b/src/std.rs index ce1ad3d..2e4a749 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,4 +1,5 @@ extern crate std; +<<<<<<< HEAD <<<<<<< HEAD use {super::SmallVec, std::io}; @@ -7,6 +8,9 @@ use super::SmallVec; use std::io; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +use {super::SmallVec, std::io}; +>>>>>>> 239c751 (refactor: conversions file) #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl io::Write for SmallVec { @@ -16,18 +20,24 @@ impl io::Write for SmallVec { Ok(buf.len()) } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.extend_from_slice(buf); Ok(()) } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/src/taggedlen.rs b/src/taggedlen.rs index 27844ca..8a3fae5 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -1,5 +1,4 @@ use core::marker::PhantomData; - /// Vec guarantees that its length is always less than [`isize::MAX`] in /// *bytes*. /// @@ -12,9 +11,12 @@ use core::marker::PhantomData; #[repr(transparent)] pub struct TaggedLen(usize, PhantomData); <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) // Clone and Copy must be manually implemented because the generic interferes // with the derive attribute implementations. impl Clone for TaggedLen { @@ -23,17 +25,18 @@ impl Clone for TaggedLen { Self(self.0, PhantomData) } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] fn clone_from(&mut self, source: &Self) { self.0 = source.0; } } - impl Copy for TaggedLen {} - impl TaggedLen { const IS_ZST: bool = size_of::() == 0; #[inline] @@ -47,9 +50,12 @@ impl TaggedLen { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] #[must_use] pub const fn on_heap(self) -> bool { @@ -60,9 +66,12 @@ impl TaggedLen { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[inline] pub const fn value(self) -> usize { if Self::IS_ZST { diff --git a/src/tests.rs b/src/tests.rs index b7e31fc..451de90 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,10 +1,14 @@ extern crate std; <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 239c751 (refactor: conversions file) use { crate::{smallvec, SmallVec}, alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec::Vec}, core::{hash::Hasher, iter::FromIterator}, }; +<<<<<<< HEAD ======= use crate::{smallvec, SmallVec}; @@ -16,6 +20,8 @@ use core::hash::Hasher; use core::iter::FromIterator; >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +>>>>>>> 239c751 (refactor: conversions file) #[test] pub fn test_zero() { let mut v = SmallVec::<_, 0>::new(); @@ -24,7 +30,6 @@ pub fn test_zero() { assert!(v.spilled()); assert_eq!(&*v, &[0]); } - // We heap allocate all these strings so that double frees will show up under // valgrind. #[test] @@ -34,7 +39,6 @@ pub fn test_inline() { v.push("there".to_owned()); assert_eq!(&*v, &["hello".to_owned(), "there".to_owned(),][..]); } - #[test] pub fn test_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -54,7 +58,6 @@ pub fn test_spill() { ][..] ); } - #[test] pub fn test_double_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -80,19 +83,16 @@ pub fn test_double_spill() { ][..] ); } - // https://github.com/servo/rust-smallvec/issues/4 #[test] fn issue_4() { SmallVec::, 2>::new(); } - // https://github.com/servo/rust-smallvec/issues/5 #[test] fn issue_5() { assert!(Some(SmallVec::<&u32, 2>::new()).is_some()); } - #[test] fn test_with_capacity() { let v: SmallVec = SmallVec::with_capacity(1); @@ -104,7 +104,6 @@ fn test_with_capacity() { assert!(v.spilled()); assert_eq!(v.capacity(), 10); } - #[test] fn drain() { let mut v: SmallVec = SmallVec::new(); @@ -125,7 +124,6 @@ fn drain() { v.push(2); assert_eq!(v.drain(..1).collect::>(), &[1]); } - #[test] fn drain_rev() { let mut v: SmallVec = SmallVec::new(); @@ -137,14 +135,12 @@ fn drain_rev() { v.push(5); assert_eq!(v.drain(..).rev().collect::>(), &[5, 4, 3]); } - #[test] fn drain_forget() { let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6, 7]; std::mem::forget(v.drain(2..5)); assert_eq!(v.len(), 2); } - #[test] fn splice() { // The range starts right before the end. @@ -166,7 +162,6 @@ fn splice() { assert_eq!(v, [7, 8, 9, 10, 3, 4, 5, 6]); assert_eq!(u, [0, 1, 2]); } - #[test] fn into_iter() { let mut v: SmallVec = SmallVec::new(); @@ -179,7 +174,6 @@ fn into_iter() { v.push(5); assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); } - #[test] fn into_iter_rev() { let mut v: SmallVec = SmallVec::new(); @@ -192,7 +186,6 @@ fn into_iter_rev() { v.push(5); assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); } - #[test] fn into_iter_drop() { use std::cell::Cell; @@ -240,7 +233,6 @@ fn into_iter_drop() { assert_eq!(cell.get(), 3); } } - #[test] fn test_capacity() { let mut v: SmallVec = SmallVec::new(); @@ -256,7 +248,6 @@ fn test_capacity() { v.shrink_to_fit(); assert!(v.capacity() < 0x100); } - #[test] fn test_truncate() { let mut v: SmallVec, 8> = SmallVec::new(); @@ -271,7 +262,6 @@ fn test_truncate() { v.insert(1, Box::new(3)); assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); } - #[test] fn test_truncate_references() { let mut v = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]); @@ -288,7 +278,6 @@ fn test_truncate_references() { &[&mut 0, &mut 8, &mut 2] ); } - #[test] fn test_split_off() { let mut vec: SmallVec = smallvec![1, 2, 3, 4, 5, 6]; @@ -300,7 +289,6 @@ fn test_split_off() { assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); } - #[test] fn test_split_off_take_all() { // Allocate enough capacity that we can tell whether the split-off vector's @@ -319,7 +307,6 @@ fn test_split_off_take_all() { assert!(split_off.capacity() < orig_capacity); assert_ne!(split_off.as_ptr(), orig_ptr); } - #[test] fn test_append() { let mut v: SmallVec = SmallVec::new(); @@ -336,7 +323,6 @@ fn test_append() { &[0, 1, 2, 3, 5, 6] ); } - #[test] #[should_panic] fn test_invalid_grow() { @@ -344,14 +330,12 @@ fn test_invalid_grow() { v.extend(0..8); v.grow(5); } - #[test] #[should_panic] fn drain_overflow() { let mut v: SmallVec = smallvec![0]; v.drain(..=usize::MAX); } - #[test] fn test_extend_from_slice() { let mut v: SmallVec = SmallVec::new(); @@ -365,7 +349,6 @@ fn test_extend_from_slice() { &[0, 1, 2, 3, 5, 6] ); } - #[test] fn test_extend_from_within() { let mut v: SmallVec = smallvec![0, 1, 2, 3]; @@ -375,7 +358,6 @@ fn test_extend_from_within() { &[0, 1, 2, 3, 1, 2], ); } - #[test] #[should_panic] fn test_drop_panic_smallvec() { @@ -390,7 +372,6 @@ fn test_drop_panic_smallvec() { let mut v = SmallVec::<_, 1>::new(); v.push(DropPanic); } - #[test] fn test_eq() { let mut a: SmallVec = SmallVec::new(); @@ -408,7 +389,6 @@ fn test_eq() { assert!(a == b); assert!(a != c); } - #[test] fn test_ord() { let mut a: SmallVec = SmallVec::new(); @@ -427,7 +407,6 @@ fn test_ord() { assert!(b < c); assert!(c > b); } - #[test] fn test_hash() { use std::{collections::hash_map::DefaultHasher, hash::Hash}; @@ -449,7 +428,6 @@ fn test_hash() { assert_eq!(hash(a), hash(b)); } } - #[test] fn test_as_ref() { let mut a: SmallVec = SmallVec::new(); @@ -460,7 +438,6 @@ fn test_as_ref() { a.push(3); assert_eq!(a.as_ref(), [1, 2, 3]); } - #[test] fn test_as_mut() { let mut a: SmallVec = SmallVec::new(); @@ -473,7 +450,6 @@ fn test_as_mut() { a.as_mut()[1] = 4; assert_eq!(a.as_mut(), [1, 4, 3]); } - #[test] fn test_borrow() { use std::borrow::Borrow; @@ -485,7 +461,6 @@ fn test_borrow() { a.push(3); assert_eq!(a.borrow(), [1, 2, 3]); } - #[test] fn test_borrow_mut() { use std::borrow::BorrowMut; @@ -499,7 +474,6 @@ fn test_borrow_mut() { BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; assert_eq!(a.borrow_mut(), [1, 4, 3]); } - #[test] fn test_from() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); @@ -543,13 +517,11 @@ fn test_from() { assert_eq!(&*small_vec, &[99u8]); drop(small_vec); } - #[test] fn test_from_slice() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); } - #[test] fn test_exact_size_iterator() { let mut vec = SmallVec::::from(&[1, 2, 3][..]); @@ -557,7 +529,6 @@ fn test_exact_size_iterator() { assert_eq!(vec.drain(..2).len(), 2); assert_eq!(vec.into_iter().len(), 1); } - #[test] fn test_into_iter_as_slice() { let vec = SmallVec::::from(&[1, 2, 3][..]); @@ -571,7 +542,6 @@ fn test_into_iter_as_slice() { assert_eq!(iter.as_slice(), &[2]); assert_eq!(iter.as_mut_slice(), &[2]); } - #[test] fn test_into_iter_clone() { // Test that the cloned iterator yields identical elements and that it owns its @@ -583,7 +553,6 @@ fn test_into_iter_clone() { } assert_eq!(clone_iter.next(), None); } - #[test] fn test_into_iter_clone_partially_consumed_iterator() { // Test that the cloned iterator only contains the remaining elements of the @@ -595,7 +564,6 @@ fn test_into_iter_clone_partially_consumed_iterator() { } assert_eq!(clone_iter.next(), None); } - #[test] fn test_into_iter_clone_empty_smallvec() { let mut iter = SmallVec::::new().into_iter(); @@ -603,7 +571,6 @@ fn test_into_iter_clone_empty_smallvec() { assert_eq!(iter.next(), None); assert_eq!(clone_iter.next(), None); } - #[test] fn shrink_to_fit_unspill() { let mut vec = SmallVec::::from_iter(0..3); @@ -612,14 +579,12 @@ fn shrink_to_fit_unspill() { vec.shrink_to_fit(); assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible"); } - #[test] fn shrink_after_from_empty_vec() { let mut v = SmallVec::::from_vec(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } - #[test] fn test_into_vec() { let vec = SmallVec::::from_iter(0..2); @@ -627,7 +592,6 @@ fn test_into_vec() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.into_vec(), Vec::from([0, 1, 2])); } - #[test] fn test_into_inner() { let vec = SmallVec::::from_iter(0..2); @@ -637,7 +601,6 @@ fn test_into_inner() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.clone().into_inner(), Err(vec)); } - #[test] fn test_from_vec() { let vec = Vec::new(); @@ -665,7 +628,6 @@ fn test_from_vec() { assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); } - #[test] fn test_retain() { // Test inline data storage @@ -697,7 +659,6 @@ fn test_retain() { sv.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); } - #[test] fn test_dedup() { let mut dupes: SmallVec = SmallVec::from(&[1, 1, 2, 3, 3]); @@ -713,7 +674,6 @@ fn test_dedup() { no_dupes.dedup(); assert_eq!(no_dupes.len(), 5); } - #[test] fn test_resize() { let mut v: SmallVec = SmallVec::new(); @@ -723,7 +683,6 @@ fn test_resize() { v.resize(2, -1); assert_eq!(v[..], [1, 0][..]); } - #[cfg(feature = "std")] #[test] fn test_write() { @@ -737,7 +696,6 @@ fn test_write() { small_vec.write_all(&data[..]).unwrap(); assert_eq!(small_vec.as_ref(), data.as_ref()); } - #[cfg(feature = "serde")] #[test] fn test_serde() { @@ -762,7 +720,6 @@ fn test_serde() { ], ); } - #[test] fn grow_to_shrink() { let mut v: SmallVec = SmallVec::new(); @@ -779,7 +736,6 @@ fn grow_to_shrink() { v.push(4); assert_eq!(v[..], [4]); } - #[test] fn resumable_extend() { let s = "a b c"; @@ -791,14 +747,12 @@ fn resumable_extend() { v.extend(it); assert_eq!(v[..], ['a']); } - // #139 #[test] fn uninhabited() { enum Void {} let _sv = SmallVec::::new(); } - #[test] fn grow_spilled_same_size() { let mut v: SmallVec = SmallVec::new(); @@ -812,12 +766,10 @@ fn grow_spilled_same_size() { assert_eq!(v.capacity(), 4); assert_eq!(v[..], [0, 1, 2]); } - #[test] fn const_generics() { let _v = SmallVec::::default(); } - #[test] fn const_new() { let v = const_new_inner(); @@ -845,17 +797,14 @@ const fn const_new_inline_sized() -> SmallVec { const fn const_new_inline_args() -> SmallVec { crate::smallvec_inline![1, 4] } - #[test] fn empty_macro() { let _v: SmallVec = smallvec![]; } - #[test] fn zero_size_items() { SmallVec::<(), 0>::new().push(()); } - #[test] fn test_clone_from() { let mut a: SmallVec = SmallVec::new(); @@ -873,7 +822,6 @@ fn test_clone_from() { b.clone_from(&c); assert_eq!(&*b, &[20, 21, 22]); } - #[test] fn test_extract_if() { let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; @@ -881,7 +829,6 @@ fn test_extract_if() { assert_eq!(a, SmallVec::::from(&[0, 1u8, 2, 4, 5, 7, 8, 0])); assert_eq!(b, SmallVec::::from(&[3u8, 6])); } - /// This assortment of tests, in combination with miri, verifies we handle UB on /// fishy arguments given to SmallVec. Draining and extending the allocation are /// fairly well-tested earlier, but `smallvec.insert(usize::MAX, val)` once @@ -895,28 +842,24 @@ fn max_dont_panic() { let _ = sv.get(usize::MAX); sv.truncate(usize::MAX); } - #[test] #[should_panic] fn max_remove() { let mut sv: SmallVec = smallvec![0]; sv.remove(usize::MAX); } - #[test] #[should_panic] fn max_swap_remove() { let mut sv: SmallVec = smallvec![0]; sv.swap_remove(usize::MAX); } - #[test] #[should_panic] fn max_insert() { let mut sv: SmallVec = smallvec![0]; sv.insert(usize::MAX, 0); } - #[test] fn collect_from_iter() { // Regression test for https://github.com/servo/rust-smallvec/issues/353 @@ -935,14 +878,12 @@ fn collect_from_iter() { let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); let _y: SmallVec = SmallVec::from_iter(iter); } - #[test] fn test_collect_with_spill() { let input = "0123456"; let collected: SmallVec = input.chars().collect(); assert_eq!(collected, &['0', '1', '2', '3', '4', '5', '6']); } - #[test] fn test_spare_capacity_mut() { let mut v: SmallVec = SmallVec::new(); @@ -966,7 +907,6 @@ fn test_spare_capacity_mut() { assert!(spare.len() >= 1); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(3) }); } - // Adopted from `tests/test_buf_mut.rs` in the `bytes` crate. #[cfg(feature = "bytes")] mod buf_mut { From 16cb61af41cfda7151c29dec41838660102cf860 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 26 Aug 2026 14:08:55 +0200 Subject: [PATCH 15/15] fix: newline amount --- rustfmt.toml | 4 + src/allocationerror.rs | 6 + src/bytes.rs | 6 +- src/comparisons.rs | 9 ++ src/conversions.rs | 26 +++- src/lib.rs | 288 +++++++---------------------------------- src/mallocsizeof.rs | 4 +- src/rawsmallvec.rs | 9 ++ src/references.rs | 6 + src/serde.rs | 11 ++ src/std.rs | 10 ++ src/taggedlen.rs | 3 + src/tests.rs | 71 ++++++++++ 13 files changed, 207 insertions(+), 246 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 05339b2..3c83be1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -5,10 +5,14 @@ format_code_in_doc_comments = true match_arm_blocks = false blank_lines_lower_bound = 0 <<<<<<< HEAD +<<<<<<< HEAD blank_lines_upper_bound = 1 ======= blank_lines_upper_bound = 0 >>>>>>> 239c751 (refactor: conversions file) +======= +blank_lines_upper_bound = 1 +>>>>>>> 716921a (fix: newline amount) condense_wildcard_suffixes = true error_on_unformatted = true error_on_line_overflow = true \ No newline at end of file diff --git a/src/allocationerror.rs b/src/allocationerror.rs index baf2cbb..0392655 100644 --- a/src/allocationerror.rs +++ b/src/allocationerror.rs @@ -7,6 +7,7 @@ use { }, }; <<<<<<< HEAD +<<<<<<< HEAD ======= use alloc::alloc::Layout; use core::error::Error; @@ -15,6 +16,9 @@ use core::fmt::{Display, Formatter, Result as Format}; ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum AllocationError { @@ -26,9 +30,11 @@ pub enum AllocationError { layout: Layout, }, } + impl Display for AllocationError { fn fmt(&self, f: &mut Formatter) -> Format { write!(f, "Allocation error: {:?}", self) } } + impl Error for AllocationError {} diff --git a/src/bytes.rs b/src/bytes.rs index f7ade1a..35acae1 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -4,6 +4,7 @@ use { bytes::{buf::UninitSlice, BufMut}, }; <<<<<<< HEAD +<<<<<<< HEAD ======= use bytes::{buf::UninitSlice, BufMut}; use super::SmallVec; @@ -11,6 +12,9 @@ use super::SmallVec; ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) unsafe impl BufMut for SmallVec { #[inline] fn remaining_mut(&self) -> usize { @@ -130,4 +134,4 @@ unsafe impl BufMut for SmallVec { let new_len = self.len().saturating_add(cnt); self.resize(new_len, val); } -} +} \ No newline at end of file diff --git a/src/comparisons.rs b/src/comparisons.rs index 70b307c..a9019ea 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -1,4 +1,5 @@ use super::SmallVec; + impl PartialEq> for SmallVec where T: PartialEq, @@ -10,6 +11,7 @@ where } impl Eq for SmallVec where T: Eq {} + impl PartialEq<[U; M]> for SmallVec where T: PartialEq, @@ -19,6 +21,7 @@ where self[..] == other[..] } } + impl PartialEq<&[U; M]> for SmallVec where T: PartialEq, @@ -28,6 +31,7 @@ where self[..] == other[..] } } + impl PartialEq<[U]> for SmallVec where T: PartialEq, @@ -37,6 +41,7 @@ where self[..] == other[..] } } + impl PartialEq<&[U]> for SmallVec where T: PartialEq, @@ -46,6 +51,7 @@ where self[..] == other[..] } } + impl PartialEq<&mut [U]> for SmallVec where T: PartialEq, @@ -55,6 +61,7 @@ where self[..] == other[..] } } + impl PartialOrd for SmallVec where T: PartialOrd, @@ -64,6 +71,7 @@ where self.as_slice().partial_cmp(other.as_slice()) } } + impl Ord for SmallVec where T: Ord, @@ -73,3 +81,4 @@ where self.as_slice().cmp(other.as_slice()) } } + diff --git a/src/conversions.rs b/src/conversions.rs index 0cb6289..a738792 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -6,9 +6,13 @@ use { core::{mem::ManuallyDrop, ptr::copy_nonoverlapping}, }; <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From<&mut [T; M]> for SmallVec { #[inline] fn from(slice: &mut [T; M]) -> Self { @@ -16,9 +20,13 @@ impl From<&mut [T; M]> for SmallVec>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From<[T; M]> for SmallVec { fn from(array: [T; M]) -> Self { if M > N { @@ -40,18 +48,26 @@ impl From<[T; M]> for SmallVec { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From> for SmallVec { fn from(array: Vec) -> Self { Self::from_vec(array) } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From<&[T]> for SmallVec { #[inline] fn from(slice: &[T]) -> Self { @@ -74,9 +90,13 @@ impl From<&[T]> for SmallVec { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From<&mut [T]> for SmallVec { #[inline] fn from(slice: &mut [T]) -> Self { @@ -84,12 +104,16 @@ impl From<&mut [T]> for SmallVec { } } <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl From<&[T; M]> for SmallVec { #[inline] fn from(slice: &[T; M]) -> Self { Self::from(slice as &[T]) } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index c949c68..29761a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ use { ptr::{copy, copy_nonoverlapping, NonNull}, }, }; + #[cfg(feature = "internals")] pub use { rawsmallvec::RawSmallVec, @@ -97,6 +98,7 @@ fn infallible(result: Result) -> T { Err(AllocationError::Failure { layout }) => alloc::alloc::handle_alloc_error(layout), } } + #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -127,12 +129,14 @@ where } core::ops::Range { start, end } } + #[repr(C)] pub struct SmallVec { len: TaggedLen, raw: RawSmallVec, _marker: PhantomData, } + unsafe impl Send for SmallVec {} unsafe impl Sync for SmallVec {} impl Default for SmallVec { @@ -141,6 +145,7 @@ impl Default for SmallVec { Self::new() } } + /// An iterator that removes the items from a `SmallVec` and yields them by /// value. /// @@ -160,6 +165,7 @@ pub struct Drain<'a, T: 'a, const N: usize> { iter: core::slice::Iter<'a, T>, vec: core::ptr::NonNull>, } + impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { type Item = T; #[inline] @@ -175,6 +181,7 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { self.iter.size_hint() } } + impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { #[inline] fn next_back(&mut self) -> Option { @@ -184,12 +191,14 @@ impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { .map(|reference| unsafe { core::ptr::read(reference) }) } } + impl ExactSizeIterator for Drain<'_, T, N> { #[inline] fn len(&self) -> usize { self.iter.len() } } + impl core::iter::FusedIterator for Drain<'_, T, N> {} impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { fn drop(&mut self) { @@ -255,6 +264,7 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { } } } + impl Drain<'_, T, N> { #[must_use] pub fn as_slice(&self) -> &[T] { @@ -304,6 +314,7 @@ impl Drain<'_, T, N> { self.tail_start = new_tail_start; } } + /// An iterator which uses a closure to determine if an element should be /// removed. /// @@ -327,6 +338,7 @@ where /// The filter test predicate. pred: F, } + impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -338,6 +350,7 @@ where .finish() } } + impl Iterator for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -370,6 +383,7 @@ where (0, Some(self.end - self.idx)) } } + impl Drop for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -393,10 +407,12 @@ where } } } + pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, replace_with: I, } + impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: Debug + Iterator + 'a, @@ -406,6 +422,7 @@ where f.debug_tuple("Splice").field(&self.drain).finish() } } + impl Iterator for Splice<'_, I, N> { type Item = I::Item; fn next(&mut self) -> Option { @@ -415,11 +432,13 @@ impl Iterator for Splice<'_, I, N> { self.drain.size_hint() } } + impl DoubleEndedIterator for Splice<'_, I, N> { fn next_back(&mut self) -> Option { self.drain.next_back() } } + impl ExactSizeIterator for Splice<'_, I, N> {} impl Drop for Splice<'_, I, N> { fn drop(&mut self) { @@ -466,6 +485,7 @@ impl Drop for Splice<'_, I, N> { // `vec.len`. } } + /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. @@ -482,6 +502,7 @@ pub struct IntoIter { end: TaggedLen, _marker: PhantomData, } + // SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) // an `IntoIter` is equivalent to sending (or sharing) a `SmallVec`. unsafe impl Send for IntoIter where T: Send {} @@ -525,6 +546,7 @@ impl IntoIter { } } } + impl Iterator for IntoIter { type Item = T; #[inline] @@ -547,6 +569,7 @@ impl Iterator for IntoIter { (size, Some(size)) } } + impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { @@ -659,6 +682,7 @@ impl SmallVec { } } } + impl SmallVec { const IS_ZST: bool = size_of::() == 0; #[inline] @@ -1482,6 +1506,7 @@ impl SmallVec { } } } + impl SmallVec { #[inline] pub fn resize(&mut self, len: usize, value: T) { @@ -1588,6 +1613,7 @@ impl SmallVec { result } } + struct DropGuard { ptr: *mut T, len: usize, @@ -1601,11 +1627,13 @@ impl Drop for DropGuard { } } } + struct DropDealloc { ptr: NonNull, size_bytes: usize, align: usize, } + impl Drop for DropDealloc { #[inline] fn drop(&mut self) { @@ -1619,6 +1647,7 @@ impl Drop for DropDealloc { } } } + #[cfg(feature = "may_dangle")] unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { fn drop(&mut self) { @@ -1642,6 +1671,7 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { } } } + #[cfg(not(feature = "may_dangle"))] impl Drop for SmallVec { fn drop(&mut self) { @@ -1664,6 +1694,7 @@ impl Drop for SmallVec { } } } + impl Drop for IntoIter { fn drop(&mut self) { // SAFETY: see above @@ -1686,6 +1717,7 @@ impl Drop for IntoIter { } } } + /// This function is used in the [`smallvec`] macro. /// It is recommended to use the macro instead of using thís function. #[doc(hidden)] @@ -1708,6 +1740,7 @@ pub fn from_elem(elem: T, n: usize) -> SmallVec } } } + #[cfg(feature = "specialization")] mod spec_traits { use super::*; @@ -1977,6 +2010,7 @@ mod spec_traits { } } } + /// Fallback functions for various specialized methods. These are kept in /// a separate implementation block for easy access whenever specialization is /// disabled. @@ -2117,78 +2151,6 @@ impl SmallVec { v } } - -impl From<&[T]> for SmallVec { - #[inline] - fn from(slice: &[T]) -> Self { - if slice.len() > Self::inline_size() { - // Standard Rust vectors are already specialized. - Self::from_vec(Vec::from(slice)) - } else { - // SAFETY: The precondition is checked in the initial comparison above. - unsafe { - #[cfg(feature = "specialization")] - { - >::spec_from(slice) - } - - #[cfg(not(feature = "specialization"))] - { - Self::from_slice_fallback(slice) - } - } - } - } -} - -impl From<&mut [T]> for SmallVec { - #[inline] - fn from(slice: &mut [T]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<&[T; M]> for SmallVec { - #[inline] - fn from(slice: &[T; M]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<&mut [T; M]> for SmallVec { - #[inline] - fn from(slice: &mut [T; M]) -> Self { - Self::from(slice as &[T]) - } -} - -impl From<[T; M]> for SmallVec { - fn from(array: [T; M]) -> Self { - if M > N { - // If M > N, we'd have to heap allocate anyway, - // so delegate for Vec for the allocation. - Self::from(Vec::from(array)) - } else { - // M <= N - let mut this = Self::new(); - debug_assert!(M <= this.capacity()); - let array = ManuallyDrop::new(array); - // SAFETY: M <= this.capacity() - unsafe { - copy_nonoverlapping(array.as_ptr(), this.as_mut_ptr(), M); - this.set_len(M); - } - this - } - } -} - -impl From> for SmallVec { - fn from(array: Vec) -> Self { - Self::from_vec(array) - } -} - impl Clone for SmallVec { #[inline] fn clone(&self) -> SmallVec { @@ -2206,12 +2168,14 @@ impl Clone for SmallVec { } } } + impl Clone for IntoIter { #[inline] fn clone(&self) -> IntoIter { SmallVec::from(self.as_slice()).into_iter() } } + impl Extend for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2225,6 +2189,7 @@ impl Extend for SmallVec { } } } + impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { #[inline] fn extend>(&mut self, iter: I) { @@ -2238,6 +2203,7 @@ impl<'a, T: Clone + 'a, const N: usize> Extend<&'a T> for SmallVec { } } } + impl core::iter::FromIterator for SmallVec { #[inline] fn from_iter>(iter: I) -> Self { @@ -2272,6 +2238,7 @@ macro_rules! smallvec_inline { $crate::SmallVec::from_buf([$($($x),+)?]) }); } + impl IntoIterator for SmallVec { type IntoIter = IntoIter; type Item = T; @@ -2290,6 +2257,7 @@ impl IntoIterator for SmallVec { } } } + impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { type IntoIter = core::slice::Iter<'a, T>; type Item = &'a T; @@ -2297,6 +2265,7 @@ impl<'a, T, const N: usize> IntoIterator for &'a SmallVec { self.iter() } } + impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { type IntoIter = core::slice::IterMut<'a, T>; type Item = &'a mut T; @@ -2304,195 +2273,28 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { self.iter_mut() } } + impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } + impl Debug for SmallVec { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list().entries(self.iter()).finish() } } + impl Debug for IntoIter { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } + impl Debug for Drain<'_, T, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl Serialize for SmallVec -where - T: Serialize, -{ - fn serialize(&self, serializer: S) -> Result { - let mut state = serializer.serialize_seq(Some(self.len()))?; - for item in self { - state.serialize_element(item)?; - } - state.end() - } -} - -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl<'de, T, const N: usize> Deserialize<'de> for SmallVec -where - T: Deserialize<'de>, -{ - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_seq(SmallVecVisitor { - phantom: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -struct SmallVecVisitor { - phantom: PhantomData, -} - -#[cfg(feature = "serde")] -impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor -where - T: Deserialize<'de>, -{ - type Value = SmallVec; - - fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: B) -> Result - where - B: SeqAccess<'de>, - { - use serde_core::de::Error; - let len = seq.size_hint().unwrap_or(0); - let mut values = SmallVec::new(); - values.try_reserve(len).map_err(B::Error::custom)?; - - while let Some(value) = seq.next_element()? { - values.push(value); - } - - Ok(values) - } -} - -#[cfg(feature = "malloc_size_of")] -impl MallocShallowSizeOf for SmallVec { - fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - if self.spilled() { - unsafe { ops.malloc_size_of(self.as_ptr()) } - } else { - 0 - } - } -} - -#[cfg(feature = "malloc_size_of")] -impl MallocSizeOf for SmallVec { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - let mut n = self.shallow_size_of(ops); - for elem in self.iter() { - n += elem.size_of(ops); - } - n - } -} - -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl io::Write for SmallVec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[cfg(feature = "bytes")] -unsafe impl BufMut for SmallVec { - #[inline] - fn remaining_mut(&self) -> usize { - // A vector can never have more than isize::MAX bytes - isize::MAX as usize - self.len() - } - - #[inline] - unsafe fn advance_mut(&mut self, cnt: usize) { - let len = self.len(); - let remaining = self.capacity() - len; - - if remaining < cnt { - panic!("advance out of bounds: the len is {remaining} but advancing by {cnt}"); - } - - // Addition will not overflow since the sum is at most the capacity. - self.set_len(len + cnt); - } - - #[inline] - fn chunk_mut(&mut self) -> &mut UninitSlice { - if self.capacity() == self.len() { - self.reserve(64); // Grow the smallvec - } - - let cap = self.capacity(); - let len = self.len(); - - let ptr = self.as_mut_ptr(); - // SAFETY: Since `ptr` is valid for `cap` bytes, `ptr.add(len)` must be - // valid for `cap - len` bytes. The subtraction will not underflow since - // `len <= cap`. - unsafe { UninitSlice::from_raw_parts_mut(ptr.add(len), cap - len) } - } - - // Specialize these methods so they can skip checking `remaining_mut` - // and `advance_mut`. - #[inline] - fn put(&mut self, mut src: T) - where - Self: Sized, - { - // In case the src isn't contiguous, reserve upfront. - self.reserve(src.remaining()); - - while src.has_remaining() { - let s = src.chunk(); - let l = s.len(); - self.extend_from_slice(s); - src.advance(l); - } - } - - #[inline] - fn put_slice(&mut self, src: &[u8]) { - self.extend_from_slice(src); - } - - #[inline] - fn put_bytes(&mut self, val: u8, cnt: usize) { - // If the addition overflows, then the `resize` will fail. - let new_len = self.len().saturating_add(cnt); - self.resize(new_len, val); - } -} diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs index 7a49d86..1f7677d 100644 --- a/src/mallocsizeof.rs +++ b/src/mallocsizeof.rs @@ -2,6 +2,7 @@ use { super::SmallVec, malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}, }; + impl MallocShallowSizeOf for SmallVec { fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { if self.spilled() { @@ -11,6 +12,7 @@ impl MallocShallowSizeOf for SmallVec { } } } + impl MallocSizeOf for SmallVec { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { let mut n = self.shallow_size_of(ops); @@ -19,4 +21,4 @@ impl MallocSizeOf for SmallVec { } n } -} +} \ No newline at end of file diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index cbff6ae..37ebdf8 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -8,6 +8,7 @@ use { }, }; <<<<<<< HEAD +<<<<<<< HEAD ======= use core::mem::{ManuallyDrop, MaybeUninit}; use core::ptr::NonNull; @@ -19,6 +20,9 @@ use alloc::alloc::Layout; ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. /// @@ -29,6 +33,7 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize), } + impl RawSmallVec { pub const IS_ZST: bool = size_of::() == 0; <<<<<<< HEAD @@ -202,7 +207,11 @@ impl RawSmallVec { Ok(()) } <<<<<<< HEAD +<<<<<<< HEAD } ======= } >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +} +>>>>>>> 716921a (fix: newline amount) diff --git a/src/references.rs b/src/references.rs index a7da355..47f633a 100644 --- a/src/references.rs +++ b/src/references.rs @@ -2,6 +2,7 @@ use { super::SmallVec, core::borrow::{Borrow, BorrowMut}, }; + impl core::ops::Deref for SmallVec { type Target = [T]; #[inline] @@ -16,27 +17,32 @@ impl core::ops::DerefMut for SmallVec { self.as_mut_slice() } } + impl AsRef<[T]> for SmallVec { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } + impl AsMut<[T]> for SmallVec { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } + impl Borrow<[T]> for SmallVec { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } + impl BorrowMut<[T]> for SmallVec { #[inline] fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } + diff --git a/src/serde.rs b/src/serde.rs index 63bc0cd..d61e89b 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -9,6 +9,7 @@ use { }, }; <<<<<<< HEAD +<<<<<<< HEAD ======= use serde_core::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, SeqAccess}, ser::SerializeSeq}; use super::SmallVec; @@ -17,6 +18,9 @@ use core::marker::PhantomData; ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) impl Serialize for SmallVec where T: Serialize, @@ -29,6 +33,7 @@ where state.end() } } + impl<'de, T, const N: usize> Deserialize<'de> for SmallVec where T: Deserialize<'de>, @@ -39,9 +44,11 @@ where }) } } + struct SmallVecVisitor { phantom: PhantomData, } + impl<'de, T, const N: usize> Visitor<'de> for SmallVecVisitor where T: Deserialize<'de>, @@ -80,6 +87,7 @@ where Ok(values) } } +<<<<<<< HEAD ======= ======= @@ -91,3 +99,6 @@ where } } >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= + +>>>>>>> 716921a (fix: newline amount) diff --git a/src/std.rs b/src/std.rs index 2e4a749..38866cf 100644 --- a/src/std.rs +++ b/src/std.rs @@ -1,5 +1,6 @@ extern crate std; <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD use {super::SmallVec, std::io}; @@ -11,6 +12,11 @@ use std::io; ======= use {super::SmallVec, std::io}; >>>>>>> 239c751 (refactor: conversions file) +======= + +use {super::SmallVec, std::io}; + +>>>>>>> 716921a (fix: newline amount) #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl io::Write for SmallVec { @@ -43,7 +49,11 @@ impl io::Write for SmallVec { Ok(()) } <<<<<<< HEAD +<<<<<<< HEAD } ======= } >>>>>>> 7fa0992 (feat: added bytes, serde, std, taggedlen files) +======= +} +>>>>>>> 716921a (fix: newline amount) diff --git a/src/taggedlen.rs b/src/taggedlen.rs index 8a3fae5..750b928 100644 --- a/src/taggedlen.rs +++ b/src/taggedlen.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; + /// Vec guarantees that its length is always less than [`isize::MAX`] in /// *bytes*. /// @@ -36,7 +37,9 @@ impl Clone for TaggedLen { self.0 = source.0; } } + impl Copy for TaggedLen {} + impl TaggedLen { const IS_ZST: bool = size_of::() == 0; #[inline] diff --git a/src/tests.rs b/src/tests.rs index 451de90..314bef3 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -9,6 +9,7 @@ use { core::{hash::Hasher, iter::FromIterator}, }; <<<<<<< HEAD +<<<<<<< HEAD ======= use crate::{smallvec, SmallVec}; @@ -22,6 +23,9 @@ use core::iter::FromIterator; ======= >>>>>>> 239c751 (refactor: conversions file) +======= + +>>>>>>> 716921a (fix: newline amount) #[test] pub fn test_zero() { let mut v = SmallVec::<_, 0>::new(); @@ -30,6 +34,7 @@ pub fn test_zero() { assert!(v.spilled()); assert_eq!(&*v, &[0]); } + // We heap allocate all these strings so that double frees will show up under // valgrind. #[test] @@ -39,6 +44,7 @@ pub fn test_inline() { v.push("there".to_owned()); assert_eq!(&*v, &["hello".to_owned(), "there".to_owned(),][..]); } + #[test] pub fn test_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -58,6 +64,7 @@ pub fn test_spill() { ][..] ); } + #[test] pub fn test_double_spill() { let mut v = SmallVec::<_, 2>::new(); @@ -83,16 +90,19 @@ pub fn test_double_spill() { ][..] ); } + // https://github.com/servo/rust-smallvec/issues/4 #[test] fn issue_4() { SmallVec::, 2>::new(); } + // https://github.com/servo/rust-smallvec/issues/5 #[test] fn issue_5() { assert!(Some(SmallVec::<&u32, 2>::new()).is_some()); } + #[test] fn test_with_capacity() { let v: SmallVec = SmallVec::with_capacity(1); @@ -104,6 +114,7 @@ fn test_with_capacity() { assert!(v.spilled()); assert_eq!(v.capacity(), 10); } + #[test] fn drain() { let mut v: SmallVec = SmallVec::new(); @@ -124,6 +135,7 @@ fn drain() { v.push(2); assert_eq!(v.drain(..1).collect::>(), &[1]); } + #[test] fn drain_rev() { let mut v: SmallVec = SmallVec::new(); @@ -135,12 +147,14 @@ fn drain_rev() { v.push(5); assert_eq!(v.drain(..).rev().collect::>(), &[5, 4, 3]); } + #[test] fn drain_forget() { let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6, 7]; std::mem::forget(v.drain(2..5)); assert_eq!(v.len(), 2); } + #[test] fn splice() { // The range starts right before the end. @@ -162,6 +176,7 @@ fn splice() { assert_eq!(v, [7, 8, 9, 10, 3, 4, 5, 6]); assert_eq!(u, [0, 1, 2]); } + #[test] fn into_iter() { let mut v: SmallVec = SmallVec::new(); @@ -174,6 +189,7 @@ fn into_iter() { v.push(5); assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); } + #[test] fn into_iter_rev() { let mut v: SmallVec = SmallVec::new(); @@ -186,6 +202,7 @@ fn into_iter_rev() { v.push(5); assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); } + #[test] fn into_iter_drop() { use std::cell::Cell; @@ -233,6 +250,7 @@ fn into_iter_drop() { assert_eq!(cell.get(), 3); } } + #[test] fn test_capacity() { let mut v: SmallVec = SmallVec::new(); @@ -248,6 +266,7 @@ fn test_capacity() { v.shrink_to_fit(); assert!(v.capacity() < 0x100); } + #[test] fn test_truncate() { let mut v: SmallVec, 8> = SmallVec::new(); @@ -262,6 +281,7 @@ fn test_truncate() { v.insert(1, Box::new(3)); assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); } + #[test] fn test_truncate_references() { let mut v = Vec::from([0, 1, 2, 3, 4, 5, 6, 7]); @@ -278,6 +298,7 @@ fn test_truncate_references() { &[&mut 0, &mut 8, &mut 2] ); } + #[test] fn test_split_off() { let mut vec: SmallVec = smallvec![1, 2, 3, 4, 5, 6]; @@ -289,6 +310,7 @@ fn test_split_off() { assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); } + #[test] fn test_split_off_take_all() { // Allocate enough capacity that we can tell whether the split-off vector's @@ -307,6 +329,7 @@ fn test_split_off_take_all() { assert!(split_off.capacity() < orig_capacity); assert_ne!(split_off.as_ptr(), orig_ptr); } + #[test] fn test_append() { let mut v: SmallVec = SmallVec::new(); @@ -323,6 +346,7 @@ fn test_append() { &[0, 1, 2, 3, 5, 6] ); } + #[test] #[should_panic] fn test_invalid_grow() { @@ -330,12 +354,14 @@ fn test_invalid_grow() { v.extend(0..8); v.grow(5); } + #[test] #[should_panic] fn drain_overflow() { let mut v: SmallVec = smallvec![0]; v.drain(..=usize::MAX); } + #[test] fn test_extend_from_slice() { let mut v: SmallVec = SmallVec::new(); @@ -349,6 +375,7 @@ fn test_extend_from_slice() { &[0, 1, 2, 3, 5, 6] ); } + #[test] fn test_extend_from_within() { let mut v: SmallVec = smallvec![0, 1, 2, 3]; @@ -358,6 +385,7 @@ fn test_extend_from_within() { &[0, 1, 2, 3, 1, 2], ); } + #[test] #[should_panic] fn test_drop_panic_smallvec() { @@ -372,6 +400,7 @@ fn test_drop_panic_smallvec() { let mut v = SmallVec::<_, 1>::new(); v.push(DropPanic); } + #[test] fn test_eq() { let mut a: SmallVec = SmallVec::new(); @@ -389,6 +418,7 @@ fn test_eq() { assert!(a == b); assert!(a != c); } + #[test] fn test_ord() { let mut a: SmallVec = SmallVec::new(); @@ -407,6 +437,7 @@ fn test_ord() { assert!(b < c); assert!(c > b); } + #[test] fn test_hash() { use std::{collections::hash_map::DefaultHasher, hash::Hash}; @@ -428,6 +459,7 @@ fn test_hash() { assert_eq!(hash(a), hash(b)); } } + #[test] fn test_as_ref() { let mut a: SmallVec = SmallVec::new(); @@ -438,6 +470,7 @@ fn test_as_ref() { a.push(3); assert_eq!(a.as_ref(), [1, 2, 3]); } + #[test] fn test_as_mut() { let mut a: SmallVec = SmallVec::new(); @@ -450,6 +483,7 @@ fn test_as_mut() { a.as_mut()[1] = 4; assert_eq!(a.as_mut(), [1, 4, 3]); } + #[test] fn test_borrow() { use std::borrow::Borrow; @@ -461,6 +495,7 @@ fn test_borrow() { a.push(3); assert_eq!(a.borrow(), [1, 2, 3]); } + #[test] fn test_borrow_mut() { use std::borrow::BorrowMut; @@ -474,6 +509,7 @@ fn test_borrow_mut() { BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; assert_eq!(a.borrow_mut(), [1, 4, 3]); } + #[test] fn test_from() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); @@ -517,11 +553,13 @@ fn test_from() { assert_eq!(&*small_vec, &[99u8]); drop(small_vec); } + #[test] fn test_from_slice() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); } + #[test] fn test_exact_size_iterator() { let mut vec = SmallVec::::from(&[1, 2, 3][..]); @@ -529,6 +567,7 @@ fn test_exact_size_iterator() { assert_eq!(vec.drain(..2).len(), 2); assert_eq!(vec.into_iter().len(), 1); } + #[test] fn test_into_iter_as_slice() { let vec = SmallVec::::from(&[1, 2, 3][..]); @@ -542,6 +581,7 @@ fn test_into_iter_as_slice() { assert_eq!(iter.as_slice(), &[2]); assert_eq!(iter.as_mut_slice(), &[2]); } + #[test] fn test_into_iter_clone() { // Test that the cloned iterator yields identical elements and that it owns its @@ -553,6 +593,7 @@ fn test_into_iter_clone() { } assert_eq!(clone_iter.next(), None); } + #[test] fn test_into_iter_clone_partially_consumed_iterator() { // Test that the cloned iterator only contains the remaining elements of the @@ -564,6 +605,7 @@ fn test_into_iter_clone_partially_consumed_iterator() { } assert_eq!(clone_iter.next(), None); } + #[test] fn test_into_iter_clone_empty_smallvec() { let mut iter = SmallVec::::new().into_iter(); @@ -571,6 +613,7 @@ fn test_into_iter_clone_empty_smallvec() { assert_eq!(iter.next(), None); assert_eq!(clone_iter.next(), None); } + #[test] fn shrink_to_fit_unspill() { let mut vec = SmallVec::::from_iter(0..3); @@ -579,12 +622,14 @@ fn shrink_to_fit_unspill() { vec.shrink_to_fit(); assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible"); } + #[test] fn shrink_after_from_empty_vec() { let mut v = SmallVec::::from_vec(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } + #[test] fn test_into_vec() { let vec = SmallVec::::from_iter(0..2); @@ -592,6 +637,7 @@ fn test_into_vec() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.into_vec(), Vec::from([0, 1, 2])); } + #[test] fn test_into_inner() { let vec = SmallVec::::from_iter(0..2); @@ -601,6 +647,7 @@ fn test_into_inner() { let vec = SmallVec::::from_iter(0..3); assert_eq!(vec.clone().into_inner(), Err(vec)); } + #[test] fn test_from_vec() { let vec = Vec::new(); @@ -628,6 +675,7 @@ fn test_from_vec() { assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); } + #[test] fn test_retain() { // Test inline data storage @@ -659,6 +707,7 @@ fn test_retain() { sv.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); } + #[test] fn test_dedup() { let mut dupes: SmallVec = SmallVec::from(&[1, 1, 2, 3, 3]); @@ -674,6 +723,7 @@ fn test_dedup() { no_dupes.dedup(); assert_eq!(no_dupes.len(), 5); } + #[test] fn test_resize() { let mut v: SmallVec = SmallVec::new(); @@ -683,6 +733,7 @@ fn test_resize() { v.resize(2, -1); assert_eq!(v[..], [1, 0][..]); } + #[cfg(feature = "std")] #[test] fn test_write() { @@ -696,6 +747,7 @@ fn test_write() { small_vec.write_all(&data[..]).unwrap(); assert_eq!(small_vec.as_ref(), data.as_ref()); } + #[cfg(feature = "serde")] #[test] fn test_serde() { @@ -720,6 +772,7 @@ fn test_serde() { ], ); } + #[test] fn grow_to_shrink() { let mut v: SmallVec = SmallVec::new(); @@ -736,6 +789,7 @@ fn grow_to_shrink() { v.push(4); assert_eq!(v[..], [4]); } + #[test] fn resumable_extend() { let s = "a b c"; @@ -747,12 +801,14 @@ fn resumable_extend() { v.extend(it); assert_eq!(v[..], ['a']); } + // #139 #[test] fn uninhabited() { enum Void {} let _sv = SmallVec::::new(); } + #[test] fn grow_spilled_same_size() { let mut v: SmallVec = SmallVec::new(); @@ -766,10 +822,12 @@ fn grow_spilled_same_size() { assert_eq!(v.capacity(), 4); assert_eq!(v[..], [0, 1, 2]); } + #[test] fn const_generics() { let _v = SmallVec::::default(); } + #[test] fn const_new() { let v = const_new_inner(); @@ -797,14 +855,17 @@ const fn const_new_inline_sized() -> SmallVec { const fn const_new_inline_args() -> SmallVec { crate::smallvec_inline![1, 4] } + #[test] fn empty_macro() { let _v: SmallVec = smallvec![]; } + #[test] fn zero_size_items() { SmallVec::<(), 0>::new().push(()); } + #[test] fn test_clone_from() { let mut a: SmallVec = SmallVec::new(); @@ -822,6 +883,7 @@ fn test_clone_from() { b.clone_from(&c); assert_eq!(&*b, &[20, 21, 22]); } + #[test] fn test_extract_if() { let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; @@ -829,6 +891,7 @@ fn test_extract_if() { assert_eq!(a, SmallVec::::from(&[0, 1u8, 2, 4, 5, 7, 8, 0])); assert_eq!(b, SmallVec::::from(&[3u8, 6])); } + /// This assortment of tests, in combination with miri, verifies we handle UB on /// fishy arguments given to SmallVec. Draining and extending the allocation are /// fairly well-tested earlier, but `smallvec.insert(usize::MAX, val)` once @@ -842,24 +905,28 @@ fn max_dont_panic() { let _ = sv.get(usize::MAX); sv.truncate(usize::MAX); } + #[test] #[should_panic] fn max_remove() { let mut sv: SmallVec = smallvec![0]; sv.remove(usize::MAX); } + #[test] #[should_panic] fn max_swap_remove() { let mut sv: SmallVec = smallvec![0]; sv.swap_remove(usize::MAX); } + #[test] #[should_panic] fn max_insert() { let mut sv: SmallVec = smallvec![0]; sv.insert(usize::MAX, 0); } + #[test] fn collect_from_iter() { // Regression test for https://github.com/servo/rust-smallvec/issues/353 @@ -878,12 +945,14 @@ fn collect_from_iter() { let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); let _y: SmallVec = SmallVec::from_iter(iter); } + #[test] fn test_collect_with_spill() { let input = "0123456"; let collected: SmallVec = input.chars().collect(); assert_eq!(collected, &['0', '1', '2', '3', '4', '5', '6']); } + #[test] fn test_spare_capacity_mut() { let mut v: SmallVec = SmallVec::new(); @@ -907,6 +976,7 @@ fn test_spare_capacity_mut() { assert!(spare.len() >= 1); assert_eq!(spare.as_ptr().cast::(), unsafe { v.as_ptr().add(3) }); } + // Adopted from `tests/test_buf_mut.rs` in the `bytes` crate. #[cfg(feature = "bytes")] mod buf_mut { @@ -981,3 +1051,4 @@ mod buf_mut { } } } +