From effad389a5a1dbcccdf75dedd968ff8567063dd6 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Thu, 27 Aug 2026 16:24:48 +0200 Subject: [PATCH 1/5] refactor: initial modularization --- Cargo.lock | 7 + Cargo.toml | 1 + benches/bench.rs | 133 ++++---- rustfmt.toml | 18 +- src/bytes.rs | 64 ++++ src/lib.rs | 751 +++++++++++++++----------------------------- src/mallocsizeof.rs | 28 ++ src/rawsmallvec.rs | 11 +- src/serde.rs | 65 ++++ src/tests.rs | 150 ++++----- 10 files changed, 574 insertions(+), 654 deletions(-) create mode 100644 src/bytes.rs create mode 100644 src/mallocsizeof.rs create mode 100644 src/serde.rs diff --git a/Cargo.lock b/Cargo.lock index cc011d59..9375d9ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "add-syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6415d4d71daf492fee3ffe63ab90322db5ebf7122d7bd46d09dbcd336fae34" + [[package]] name = "aho-corasick" version = "1.1.5" @@ -500,6 +506,7 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" name = "smallvec" version = "2.0.0-alpha.12" dependencies = [ + "add-syntax", "bytes", "criterion", "malloc_size_of", diff --git a/Cargo.toml b/Cargo.toml index 4dbbc234..acfb20be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ internals = [] bytes = { version = "1", optional = true, default-features = false } serde_core = { version = "1.0.221", optional = true, default-features = false } malloc_size_of = { version = "0.1.1", optional = true, default-features = false } +add-syntax = "0.1.0" [dev-dependencies] serde_test = "1.0" diff --git a/benches/bench.rs b/benches/bench.rs index e881130a..3d3001e6 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,9 +1,21 @@ #![allow(deprecated)] -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; -use smallvec::{smallvec, SmallVec}; -use std::hint::black_box; -use std::time::Duration; +use { + criterion::{ + Bencher, + Criterion, + criterion_group, + criterion_main + }, + smallvec::{ + SmallVec, + smallvec + }, + std::{ + hint::black_box, + time::Duration + } +}; const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; @@ -18,72 +30,51 @@ trait Vector: for<'a> From<&'a [T]> + Extend { fn from_elems(val: &[T]) -> Self; fn extend_from_slice(&mut self, other: &[T]); fn retain_mut(&mut self, f: F) - where - F: FnMut(&mut T) -> bool; + where F: FnMut(&mut T) -> bool; } 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) - } + 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) } + fn retain_mut(&mut self, f: F) - where - F: FnMut(&mut T) -> bool, - { + where F: FnMut(&mut T) -> bool { self.retain_mut(f) } } 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) - } + 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) } + fn retain_mut(&mut self, f: F) - where - F: FnMut(&mut T) -> bool, - { + where F: FnMut(&mut T) -> bool { self.retain_mut(f) } } @@ -100,8 +91,8 @@ macro_rules! make_benches { } } -/* ---------- Bench generation (same list, just using the new macro) - * ---------- */ +// ---------- Bench generation (same list, just using the new macro) +// ---------- make_benches! { SmallVec { bench_push => gen_push(SPILLED_SIZE as _), @@ -168,9 +159,7 @@ make_benches! { fn gen_push>(n: u64, b: &mut Bencher) { #[inline(never)] - fn push_noinline>(vec: &mut V, x: u64) { - vec.push(black_box(x)); - } + fn push_noinline>(vec: &mut V, x: u64) { vec.push(black_box(x)); } b.iter(|| { let n = black_box(n); @@ -216,15 +205,13 @@ fn gen_insert>(n: u64, b: &mut Bencher) { insert_noinline(&mut vec, 0, x); } vec - }, + } ); } fn gen_remove>(n: usize, b: &mut Bencher) { #[inline(never)] - fn remove_noinline>(vec: &mut V, p: usize) -> u64 { - vec.remove(black_box(p)) - } + fn remove_noinline>(vec: &mut V, p: usize) -> u64 { vec.remove(black_box(p)) } b.iter_with_setup( || V::from_elem(0, black_box(n)), @@ -233,7 +220,7 @@ fn gen_remove>(n: usize, b: &mut Bencher) { black_box(remove_noinline(&mut vec, 0)); } vec - }, + } ); } @@ -309,7 +296,7 @@ fn gen_retain_mut_half>(n: usize, b: &mut Bencher) { |mut vec| { vec.retain_mut(|x| black_box(*x) % 2 == 0); vec - }, + } ); } @@ -319,7 +306,7 @@ fn gen_retain_mut_all>(n: usize, b: &mut Bencher) { |mut vec| { vec.retain_mut(|_| true); vec - }, + } ); } @@ -329,7 +316,7 @@ fn gen_retain_mut_none>(n: usize, b: &mut Bencher) { |mut vec| { vec.retain_mut(|_| false); vec - }, + } ); } diff --git a/rustfmt.toml b/rustfmt.toml index 5171db17..0235f78e 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,18 @@ wrap_comments = true -imports_granularity = "Preserve" +imports_granularity = "One" group_imports = "One" -format_code_in_doc_comments = true \ No newline at end of file +format_code_in_doc_comments = true +error_on_line_overflow = true +error_on_unformatted = true +blank_lines_lower_bound = 0 +blank_lines_upper_bound = 1 +float_literal_trailing_zero = "IfNoPostfix" +fn_single_line = true +imports_layout = "Vertical" +normalize_comments = true +reorder_impl_items = true +struct_lit_single_line = false +style_edition = "2024" +trailing_comma = "Never" +use_try_shorthand = true +where_single_line = true \ No newline at end of file diff --git a/src/bytes.rs b/src/bytes.rs new file mode 100644 index 00000000..621cdcc3 --- /dev/null +++ b/src/bytes.rs @@ -0,0 +1,64 @@ +use { + super::SmallVec, + bytes::{ + BufMut, + buf::UninitSlice + } +}; + +unsafe impl BufMut for SmallVec { + fn remaining_mut(&self) -> usize { + // A vector can never have more than isize::MAX bytes + isize::MAX as usize - self.len() + } + + 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); + } + + 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`. + 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); + } + } + + fn put_slice(&mut self, src: &[u8]) { self.extend_from_slice(src); } + + 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 af120445..b70fffa7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,41 +65,55 @@ pub extern crate alloc; #[cfg(any(test, feature = "std"))] extern crate std; +#[cfg(feature = "bytes")] +mod bytes; +#[cfg(feature = "malloc_size_of")] +mod mallocsizeof; mod rawsmallvec; +#[cfg(feature = "serde")] +mod serde; #[cfg(test)] mod tests; -use alloc::alloc::Layout; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -#[cfg(feature = "bytes")] -use bytes::{buf::UninitSlice, BufMut}; -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; -#[cfg(not(feature = "internals"))] +#[cfg_attr(feature = "internals", prepend(pub))] use rawsmallvec::RawSmallVec; -#[cfg(feature = "serde")] -use serde_core::{ - de::{Deserialize, Deserializer, SeqAccess, Visitor}, - ser::{Serialize, SerializeSeq, Serializer}, -}; #[cfg(feature = "std")] -use std::io; +use std::io::{ + Result as IoResult, + Write +}; +use { + alloc::{ + alloc::Layout, + boxed::Box, + vec::Vec + }, + core::{ + borrow::{ + Borrow, + BorrowMut + }, + fmt::Debug, + hash::{ + Hash, + Hasher + }, + iter::repeat_n, + marker::PhantomData, + mem::{ + ManuallyDrop, + MaybeUninit, + align_of, + size_of + }, + ptr::{ + NonNull, + copy, + copy_nonoverlapping + } + }, + add_syntax::prepend +}; /// Error type for APIs with fallible heap allocation #[derive(Debug)] @@ -109,8 +123,8 @@ pub enum CollectionAllocErr { /// The allocator return an error AllocErr { /// The layout that was passed to the allocator - layout: Layout, - }, + layout: Layout + } } impl core::fmt::Display for CollectionAllocErr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -125,23 +139,21 @@ 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(CollectionAllocErr::AllocErr { + 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 } -} +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. fn slice_range(range: R, bounds: core::ops::RangeTo) -> core::ops::Range -where - R: core::ops::RangeBounds, -{ +where R: core::ops::RangeBounds { let len = bounds.end; let start = match range.start_bound() { @@ -149,7 +161,7 @@ where core::ops::Bound::Excluded(start) => start .checked_add(1) .unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")), - core::ops::Bound::Unbounded => 0, + core::ops::Bound::Unbounded => 0 }; let end = match range.end_bound() { @@ -157,7 +169,7 @@ where .checked_add(1) .unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")), core::ops::Bound::Excluded(&end) => end, - core::ops::Bound::Unbounded => len, + core::ops::Bound::Unbounded => len }; if start > end { @@ -167,26 +179,29 @@ where panic!("range end index {end} out of range for slice of length {len}"); } - core::ops::Range { start, end } + core::ops::Range { + start, + end + } } impl RawSmallVec { const IS_ZST: bool = is_zst::(); #[inline] - const fn new() -> Self { - Self::new_inline(MaybeUninit::uninit()) - } + 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: ManuallyDrop::new(inline) } } + #[inline] const fn new_heap(ptr: NonNull, capacity: usize) -> Self { Self { - heap: (ptr, capacity), + heap: (ptr, capacity) } } @@ -195,30 +210,28 @@ impl RawSmallVec { // 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 + #[allow(unused_unsafe, reason = "Unsafe in MSRV 1.83.0")] + (unsafe { &raw const self.inline }).cast() } #[inline] const fn as_mut_ptr_inline(&mut self) -> *mut T { // SAFETY: same as above - (unsafe { &raw mut self.inline }) as *mut T + #[allow(unused_unsafe, reason = "Unsafe in MSRV 1.83.0")] + (unsafe { &raw mut self.inline }).cast() } /// # Safety /// /// The vector must be on the heap #[inline] - const unsafe fn as_ptr_heap(&self) -> *const T { - self.heap.0.as_ptr() - } + 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() - } + const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { self.heap.0.as_ptr() } /// # Safety /// @@ -227,9 +240,12 @@ impl RawSmallVec { unsafe fn try_grow_raw( &mut self, len: TaggedLen, - new_capacity: usize, + new_capacity: usize ) -> Result<(), CollectionAllocErr> { - use alloc::alloc::{alloc, realloc}; + use alloc::alloc::{ + alloc, + realloc + }; debug_assert!(!Self::IS_ZST); debug_assert!(new_capacity > 0); debug_assert!(new_capacity >= len.value()); @@ -251,8 +267,9 @@ impl RawSmallVec { let new_ptr = if !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 })?; + 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 { @@ -269,7 +286,9 @@ impl RawSmallVec { // 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 })? + NonNull::new(new_ptr).ok_or(CollectionAllocErr::AllocErr { + layout: new_layout + })? }; *self = Self::new_heap(new_ptr, new_capacity); Ok(()) @@ -292,20 +311,17 @@ struct TaggedLen(usize, PhantomData); // with the derive attribute implementations. impl Clone for TaggedLen { #[inline] - fn clone(&self) -> Self { - Self(self.0, PhantomData) - } + fn clone(&self) -> Self { Self(self.0, PhantomData) } #[inline] - fn clone_from(&mut self, source: &Self) { - self.0 = source.0; - } + 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 { @@ -328,20 +344,14 @@ impl TaggedLen { } #[inline] - pub const fn value(self) -> usize { - if Self::IS_ZST { - self.0 - } else { - self.0 >> 1 - } - } + pub const fn value(self) -> usize { if Self::IS_ZST { self.0 } else { self.0 >> 1 } } } #[repr(C)] pub struct SmallVec { len: TaggedLen, raw: RawSmallVec, - _marker: PhantomData, + _marker: PhantomData } unsafe impl Send for SmallVec {} @@ -349,9 +359,7 @@ unsafe impl Sync for SmallVec {} impl Default for SmallVec { #[inline] - fn default() -> Self { - Self::new() - } + fn default() -> Self { Self::new() } } /// An iterator that removes the items from a `SmallVec` and yields them by @@ -371,7 +379,7 @@ pub struct Drain<'a, T: 'a, const N: usize> { tail_start: usize, tail_len: usize, iter: core::slice::Iter<'a, T>, - vec: core::ptr::NonNull>, + vec: core::ptr::NonNull> } impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { @@ -387,9 +395,7 @@ impl<'a, T: 'a, const N: usize> Iterator for Drain<'a, T, N> { } #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { @@ -404,9 +410,7 @@ impl<'a, T: 'a, const N: usize> DoubleEndedIterator for Drain<'a, T, N> { impl ExactSizeIterator for Drain<'_, T, N> { #[inline] - fn len(&self) -> usize { - self.iter.len() - } + fn len(&self) -> usize { self.iter.len() } } impl core::iter::FusedIterator for Drain<'_, T, N> {} @@ -477,7 +481,7 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { // 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); + // let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr); let drop_offset = drop_ptr.offset_from(vec_ptr) as usize; let to_drop = core::ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); core::ptr::drop_in_place(to_drop); @@ -487,9 +491,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] { - self.iter.as_slice() - } + 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. @@ -503,7 +505,7 @@ impl Drain<'_, T, N> { let range_slice = unsafe { core::slice::from_raw_parts_mut( vec.as_mut_ptr().add(range_start), - range_end - range_start, + range_end - range_start ) }; @@ -547,8 +549,7 @@ impl Drain<'_, T, N> { /// /// [1]: struct.SmallVec.html#method.extract_if pub struct ExtractIf<'a, T, const N: usize, F> -where - F: FnMut(&mut T) -> bool, +where F: FnMut(&mut T) -> bool { vec: &'a mut SmallVec, /// The index of the item that will be inspected by the next call to `next`. @@ -561,13 +562,13 @@ where /// The original length of `vec` prior to draining. old_len: usize, /// The filter test predicate. - pred: F, + pred: F } impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, - T: core::fmt::Debug, + T: core::fmt::Debug { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("ExtractIf") @@ -577,8 +578,7 @@ where } impl Iterator for ExtractIf<'_, T, N, F> -where - F: FnMut(&mut T) -> bool, +where F: FnMut(&mut T) -> bool { type Item = T; @@ -606,14 +606,11 @@ where } } - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.end - self.idx)) - } + 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, +where F: FnMut(&mut T) -> bool { fn drop(&mut self) { unsafe { @@ -637,13 +634,13 @@ where pub struct Splice<'a, I: Iterator + 'a, const N: usize> { drain: Drain<'a, I::Item, N>, - replace_with: I, + replace_with: I } impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: Debug + Iterator + 'a, - ::Item: Debug, + ::Item: Debug { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Splice").field(&self.drain).finish() @@ -653,19 +650,13 @@ where impl Iterator for Splice<'_, I, N> { type Item = I::Item; - fn next(&mut self) -> Option { - self.drain.next() - } + fn next(&mut self) -> Option { self.drain.next() } - fn size_hint(&self) -> (usize, Option) { - self.drain.size_hint() - } + 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() - } + fn next_back(&mut self) -> Option { self.drain.next_back() } } impl ExactSizeIterator for Splice<'_, I, N> {} @@ -734,7 +725,7 @@ pub struct IntoIter { raw: RawSmallVec, begin: usize, end: TaggedLen, - _marker: PhantomData, + _marker: PhantomData } // SAFETY: IntoIter has unique ownership of its contents. Sending (or sharing) @@ -838,7 +829,7 @@ impl SmallVec { Self { len: TaggedLen::new(0, false), raw: RawSmallVec::new(), - _marker: PhantomData, + _marker: PhantomData } } @@ -876,7 +867,7 @@ impl SmallVec { Self { len: TaggedLen::new(S, false), raw: RawSmallVec::new_inline(buf), - _marker: PhantomData, + _marker: PhantomData } } @@ -887,7 +878,7 @@ impl SmallVec { let mut vec = Self { len: TaggedLen::new(len, false), raw: RawSmallVec::new_inline(MaybeUninit::new(buf)), - _marker: PhantomData, + _marker: PhantomData }; // Deallocate the remaining elements so no memory is leaked. unsafe { @@ -899,7 +890,7 @@ impl SmallVec { // 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, + remainder_len )); } @@ -913,8 +904,10 @@ 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) }; @@ -931,7 +924,7 @@ impl SmallVec { Self { len: TaggedLen::new(len, false), raw: RawSmallVec::new_inline(buf), - _marker: PhantomData, + _marker: PhantomData } } } @@ -959,7 +952,7 @@ impl SmallVec { Self { len: TaggedLen::new(len, false), raw: RawSmallVec::new(), - _marker: PhantomData, + _marker: PhantomData } } else { let mut vec = ManuallyDrop::new(vec); @@ -972,7 +965,7 @@ impl SmallVec { Self { len: TaggedLen::new(len, true), raw: RawSmallVec::new_heap(ptr, cap), - _marker: PhantomData, + _marker: PhantomData } } } @@ -983,9 +976,7 @@ impl SmallVec { /// /// The active union member must be the self.raw.heap #[inline] - unsafe fn set_on_heap(&mut self) { - self.len = TaggedLen::new(self.len(), true); - } + unsafe fn set_on_heap(&mut self) { self.len = TaggedLen::new(self.len(), true); } /// Sets the tag to be inline /// @@ -993,9 +984,7 @@ impl SmallVec { /// /// The active union member must be the self.raw.inline #[inline] - unsafe fn set_inline(&mut self) { - self.len = TaggedLen::new(self.len(), false); - } + unsafe fn set_inline(&mut self) { self.len = TaggedLen::new(self.len(), false); } /// Sets the length of a vector. /// @@ -1015,24 +1004,14 @@ impl SmallVec { } #[inline] - pub const fn inline_size() -> usize { - if Self::IS_ZST { - usize::MAX - } else { - N - } - } + pub const fn inline_size() -> usize { if Self::IS_ZST { usize::MAX } else { N } } #[inline] - pub const fn len(&self) -> usize { - self.len.value() - } + pub const fn len(&self) -> usize { self.len.value() } #[must_use] #[inline] - pub const fn is_empty(&self) -> bool { - self.len() == 0 - } + pub const fn is_empty(&self) -> bool { self.len() == 0 } #[inline] pub const fn capacity(&self) -> usize { @@ -1045,9 +1024,7 @@ impl SmallVec { } #[inline] - pub const fn spilled(&self) -> bool { - self.len.on_heap() - } + pub const fn spilled(&self) -> bool { self.len.on_heap() } /// Splits the collection into two at the given index. /// @@ -1094,11 +1071,12 @@ impl SmallVec { } pub fn drain(&mut self, range: R) -> Drain<'_, T, N> - where - R: core::ops::RangeBounds, - { + where R: core::ops::RangeBounds { let len = self.len(); - let core::ops::Range { start, end } = slice_range(range, ..len); + let core::ops::Range { + start, + end + } = slice_range(range, ..len); unsafe { // SAFETY: `start <= len` @@ -1114,8 +1092,7 @@ impl SmallVec { iter: range_slice.iter(), // 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), + vec: core::ptr::NonNull::new_unchecked(self as *mut _) } } } @@ -1207,10 +1184,13 @@ impl SmallVec { pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, - R: core::ops::RangeBounds, + R: core::ops::RangeBounds { let old_len = self.len(); - let core::ops::Range { start, end } = slice_range(range, ..old_len); + let core::ops::Range { + start, + end + } = slice_range(range, ..old_len); // Guard against us getting leaked (leak amplification) unsafe { @@ -1223,25 +1203,23 @@ impl SmallVec { end, del: 0, old_len, - pred: filter, + pred: filter } } pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> where R: core::ops::RangeBounds, - I: IntoIterator, + I: IntoIterator { Splice { drain: self.drain(range), - replace_with: replace_with.into_iter(), + replace_with: replace_with.into_iter() } } #[inline] - pub fn push(&mut self, value: T) { - _ = self.push_mut(value); - } + pub fn push(&mut self, value: T) { _ = self.push_mut(value); } #[inline] #[must_use] @@ -1293,11 +1271,7 @@ impl SmallVec { #[inline] pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let last = self.last_mut()?; - if predicate(last) { - self.pop() - } else { - None - } + if predicate(last) { self.pop() } else { None } } #[inline] @@ -1321,9 +1295,7 @@ impl SmallVec { } #[inline] - pub fn grow(&mut self, new_capacity: usize) { - infallible(self.try_grow(new_capacity)); - } + 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<(), CollectionAllocErr> { @@ -1357,7 +1329,7 @@ impl SmallVec { drop(DropDealloc { ptr: ptr.cast(), size_bytes: old_cap * size_of::(), - align: align_of::(), + align: align_of::() }); self.set_inline(); } @@ -1374,7 +1346,7 @@ impl SmallVec { self.len() .checked_add(additional) .and_then(usize::checked_next_power_of_two) - .ok_or(CollectionAllocErr::CapacityOverflow), + .ok_or(CollectionAllocErr::CapacityOverflow) ); self.grow(new_capacity); } @@ -1401,7 +1373,7 @@ impl SmallVec { let new_capacity = infallible( self.len() .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow), + .ok_or(CollectionAllocErr::CapacityOverflow) ); self.grow(new_capacity); } @@ -1435,7 +1407,7 @@ impl SmallVec { self.set_inline(); alloc::alloc::dealloc( ptr.cast().as_ptr(), - Layout::from_size_align_unchecked(capacity * size_of::(), align_of::()), + Layout::from_size_align_unchecked(capacity * size_of::(), align_of::()) ); } } else if len < self.capacity() { @@ -1465,8 +1437,8 @@ impl SmallVec { ptr.cast().as_ptr(), Layout::from_size_align_unchecked( capacity * size_of::(), - align_of::(), - ), + align_of::() + ) ); } } else if target < self.capacity() { @@ -1488,7 +1460,7 @@ impl SmallVec { self.set_len(len); core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( self.as_mut_ptr().add(len), - old_len - len, + old_len - len )) } } @@ -1524,7 +1496,7 @@ impl SmallVec { self.set_len(0); core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( self.as_mut_ptr(), - old_len, + old_len )); } } @@ -1550,9 +1522,7 @@ impl SmallVec { } #[inline] - pub fn insert(&mut self, index: usize, value: T) { - _ = self.insert_mut(index, value); - } + pub fn insert(&mut self, index: usize, value: T) { _ = self.insert_mut(index, value); } #[inline] #[must_use] @@ -1663,9 +1633,7 @@ impl SmallVec { } #[inline] - pub fn into_boxed_slice(self) -> Box<[T]> { - self.into_vec().into_boxed_slice() - } + pub fn into_boxed_slice(self) -> Box<[T]> { self.into_vec().into_boxed_slice() } #[inline] pub fn into_inner(self) -> Result<[T; N], Self> { @@ -1685,9 +1653,7 @@ impl SmallVec { } #[inline] - pub fn retain bool>(&mut self, mut f: F) { - self.retain_mut(|elem| f(elem)) - } + 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) { @@ -1717,9 +1683,7 @@ impl SmallVec { #[inline] pub fn dedup(&mut self) - where - T: PartialEq, - { + where T: PartialEq { self.dedup_by(|a, b| a == b); } @@ -1727,16 +1691,14 @@ impl SmallVec { pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut T) -> K, - K: PartialEq, + K: PartialEq { self.dedup_by(|a, b| key(a) == key(b)); } #[inline] pub fn dedup_by(&mut self, mut same_bucket: F) - where - F: FnMut(&mut T, &mut T) -> bool, - { + where F: FnMut(&mut T, &mut T) -> bool { // See the implementation of Vec::dedup_by in the // standard library for an explanation of this algorithm. let len = self.len(); @@ -1765,9 +1727,7 @@ impl SmallVec { } pub fn resize_with(&mut self, new_len: usize, f: F) - where - F: FnMut() -> T, - { + where F: FnMut() -> T { let old_len = self.len(); if old_len < new_len { let mut f = f; @@ -1802,7 +1762,7 @@ impl SmallVec { unsafe { core::slice::from_raw_parts_mut( self.as_mut_ptr().add(self.len()) as *mut MaybeUninit, - self.capacity() - self.len(), + self.capacity() - self.len() ) } } @@ -1839,7 +1799,10 @@ impl SmallVec { /// # Examples /// /// ``` - /// use smallvec::{smallvec, SmallVec}; + /// use smallvec::{ + /// SmallVec, + /// smallvec + /// }; /// /// let mut v: SmallVec<_, 1> = smallvec![1, 2, 3]; /// @@ -1884,7 +1847,7 @@ impl SmallVec { SmallVec { len: TaggedLen::new(length, true), raw: RawSmallVec::new_heap(ptr, capacity), - _marker: PhantomData, + _marker: PhantomData } } } @@ -1901,14 +1864,10 @@ impl SmallVec { } #[inline] - pub fn extend_from_slice(&mut self, other: &[T]) { - self.extend(other.iter()) - } + 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, - { + where R: core::ops::RangeBounds { let src = slice_range(src, ..self.len()); self.reserve(src.len()); @@ -1929,9 +1888,7 @@ impl SmallVec { #[inline] pub fn extend_from_slice_copy(&mut self, other: &[T]) - where - T: Copy, - { + where T: Copy { let len = other.len(); let src = other.as_ptr(); @@ -1950,10 +1907,13 @@ impl SmallVec { pub fn extend_from_within_copy(&mut self, src: R) where R: core::ops::RangeBounds, - T: Copy, + T: Copy { let src = slice_range(src, ..self.len()); - let core::ops::Range { start, end } = src; + let core::ops::Range { + start, + end + } = src; let len = end - start; self.reserve(len); @@ -1968,9 +1928,7 @@ impl SmallVec { } pub fn insert_from_slice_copy(&mut self, index: usize, other: &[T]) - where - T: Copy, - { + where T: Copy { let l = self.len(); let len = other.len(); assert!(index <= l); @@ -1992,9 +1950,7 @@ impl SmallVec { /// A function for creating [`SmallVec`] values out of slices /// for types with the [`Copy`] trait. pub fn from_slice_copy(slice: &[T]) -> Self - where - T: Copy, - { + where T: Copy { let src = slice.as_ptr(); let len = slice.len(); let mut result = Self::with_capacity(len); @@ -2012,7 +1968,7 @@ impl SmallVec { struct DropGuard { ptr: *mut T, - len: usize, + len: usize } impl Drop for DropGuard { #[inline] @@ -2026,7 +1982,7 @@ impl Drop for DropGuard { struct DropDealloc { ptr: NonNull, size_bytes: usize, - align: usize, + align: usize } impl Drop for DropDealloc { @@ -2036,7 +1992,7 @@ impl Drop for DropDealloc { if self.size_bytes > 0 { alloc::alloc::dealloc( self.ptr.as_ptr(), - Layout::from_size_align_unchecked(self.size_bytes, self.align), + Layout::from_size_align_unchecked(self.size_bytes, self.align) ); } } @@ -2057,7 +2013,7 @@ unsafe impl<#[may_dangle] T, const N: usize> Drop for SmallVec { Some(DropDealloc { ptr: NonNull::new_unchecked(ptr as *mut u8), size_bytes: capacity * size_of::(), - align: align_of::(), + align: align_of::() }) } else { None @@ -2080,7 +2036,7 @@ impl Drop for SmallVec { Some(DropDealloc { ptr: NonNull::new_unchecked(ptr as *mut u8), size_bytes: capacity * size_of::(), - align: align_of::(), + align: align_of::() }) } else { None @@ -2103,7 +2059,7 @@ impl Drop for IntoIter { Some(DropDealloc { ptr: NonNull::new_unchecked(ptr as *mut u8), size_bytes: capacity * size_of::(), - align: align_of::(), + align: align_of::() }) } else { None @@ -2117,15 +2073,11 @@ impl core::ops::Deref for SmallVec { type Target = [T]; #[inline] - fn deref(&self) -> &Self::Target { - self.as_slice() - } + 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() - } + fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } /// This function is used in the [`smallvec`] macro. @@ -2134,8 +2086,8 @@ impl core::ops::DerefMut for SmallVec { #[track_caller] 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]) + // Standard Rust iterators are already specialized. + repeat_n(elem, n).collect() } else { #[cfg(feature = "specialization")] { @@ -2211,18 +2163,14 @@ mod spec_traits { } impl SpecExtend for SmallVec - where - I: Iterator, + where I: Iterator { #[inline] - default fn spec_extend(&mut self, iter: I) { - self.extend_fallback(iter); - } + default fn spec_extend(&mut self, iter: I) { self.extend_fallback(iter); } } impl SpecExtend for SmallVec - where - I: core::iter::TrustedLen, + where I: core::iter::TrustedLen { fn spec_extend(&mut self, iter: I) { let (_, Some(additional)) = iter.size_hint() else { @@ -2237,7 +2185,10 @@ mod spec_traits { unsafe { let len = self.len(); let ptr = self.as_mut_ptr().add(len); - let mut guard = DropGuard { ptr, len: 0 }; + let mut guard = DropGuard { + ptr, + len: 0 + }; for x in iter { ptr.add(guard.len).write(x); @@ -2280,17 +2231,14 @@ mod spec_traits { impl<'a, T: 'a, const N: usize, I> SpecExtend<&'a T, I> for SmallVec where I: Iterator, - T: Clone, + T: Clone { #[inline] - default fn spec_extend(&mut self, iterator: I) { - self.spec_extend(iterator.cloned()) - } + default fn spec_extend(&mut self, iterator: I) { 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, + where T: Copy { fn spec_extend(&mut self, iter: core::slice::Iter<'a, T>) { let slice = iter.as_slice(); @@ -2371,18 +2319,14 @@ mod spec_traits { } impl SpecFromIterator for SmallVec - where - I: Iterator, + where I: Iterator { #[inline] - default fn spec_from_iter(iter: I) -> Self { - Self::from_iter_fallback(iter) - } + default fn spec_from_iter(iter: I) -> Self { Self::from_iter_fallback(iter) } } impl SpecFromIterator for SmallVec - where - I: core::iter::TrustedLen, + where I: core::iter::TrustedLen { fn spec_from_iter(iter: I) -> Self { let mut v = match iter.size_hint() { @@ -2391,7 +2335,7 @@ mod spec_traits { // are more than `usize::MAX` elements. // Since the previous branch would eagerly panic if the capacity is too large // (via `with_capacity`) we do the same here. - _ => panic!("capacity overflow"), + _ => panic!("capacity overflow") }; // Reuse the extend specialization for TrustedLen. v.spec_extend(iter); @@ -2408,9 +2352,7 @@ mod spec_traits { impl SpecCloneFrom for SmallVec { #[inline] - default fn spec_clone_from(&mut self, source: &[T]) { - self.clone_from_fallback(source); - } + default fn spec_clone_from(&mut self, source: &[T]) { self.clone_from_fallback(source); } } impl SpecCloneFrom for SmallVec { @@ -2474,14 +2416,15 @@ impl SmallVec { /// /// The caller must ensure that `n <= Self::inline_size()`. unsafe fn from_elem_fallback(elem: T, n: usize) -> Self - where - T: Clone, - { + where 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 }; + let mut guard = DropGuard { + ptr, + len: 0 + }; // SAFETY: The caller ensures that the first `n` // is smaller than the inline size. @@ -2505,9 +2448,7 @@ impl SmallVec { } fn extend_fallback(&mut self, iter: I) - where - I: IntoIterator, - { + where I: IntoIterator { let iter = iter.into_iter(); let (size, _) = iter.size_hint(); self.reserve(size); @@ -2526,9 +2467,7 @@ impl SmallVec { /// /// [`extend_from_within`]: SmallVec::extend_from_within unsafe fn extend_from_within_fallback(&mut self, src: core::ops::Range) - where - T: Clone, - { + where T: Clone { let old_len = self.len(); let start = src.start; @@ -2542,7 +2481,10 @@ impl SmallVec { let dst = ptr.add(old_len); let src = ptr.add(start); - let mut guard = DropGuard { ptr: dst, len: 0 }; + let mut guard = DropGuard { + ptr: dst, + len: 0 + }; for i in 0..len { let val = (*src.add(i)).clone(); dst.add(i).write(val); @@ -2558,9 +2500,7 @@ impl SmallVec { } fn from_iter_fallback(iter: I) -> Self - where - I: Iterator, - { + where I: Iterator { let (size, _) = iter.size_hint(); let mut v = Self::with_capacity(size); for x in iter { @@ -2570,9 +2510,7 @@ impl SmallVec { } fn clone_from_fallback(&mut self, source: &[T]) - where - T: Clone, - { + where T: Clone { // Inspired from `impl Clone for Vec`. // Drop anything that will not be overwritten. @@ -2594,9 +2532,7 @@ impl SmallVec { /// /// The caller must ensure that `slice.len() <= Self::inline_size()`. unsafe fn from_slice_fallback(slice: &[T]) -> Self - where - T: Clone, - { + where T: Clone { let mut v = Self::new(); let src = slice.as_ptr(); @@ -2606,7 +2542,10 @@ impl SmallVec { // SAFETY: The caller ensures that the slice length is smaller // than or equal to the inline length. unsafe { - let mut guard = DropGuard { ptr: dst, len: 0 }; + let mut guard = DropGuard { + ptr: dst, + len: 0 + }; for i in 0..len { let val = (*src.add(i)).clone(); dst.add(i).write(val); @@ -2649,23 +2588,17 @@ impl From<&[T]> for SmallVec { impl From<&mut [T]> for SmallVec { #[inline] - fn from(slice: &mut [T]) -> Self { - Self::from(slice as &[T]) - } + 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]) - } + 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]) - } + fn from(slice: &mut [T; M]) -> Self { Self::from(slice as &[T]) } } impl From<[T; M]> for SmallVec { @@ -2690,16 +2623,12 @@ impl From<[T; M]> for SmallVec { } impl From> for SmallVec { - fn from(array: Vec) -> Self { - Self::from_vec(array) - } + fn from(array: Vec) -> Self { Self::from_vec(array) } } impl Clone for SmallVec { #[inline] - fn clone(&self) -> SmallVec { - SmallVec::from(self.as_slice()) - } + fn clone(&self) -> SmallVec { SmallVec::from(self.as_slice()) } #[inline] fn clone_from(&mut self, source: &Self) { @@ -2717,9 +2646,7 @@ impl Clone for SmallVec { impl Clone for IntoIter { #[inline] - fn clone(&self) -> IntoIter { - SmallVec::from(self.as_slice()).into_iter() - } + fn clone(&self) -> IntoIter { SmallVec::from(self.as_slice()).into_iter() } } impl Extend for SmallVec { @@ -2792,6 +2719,7 @@ macro_rules! smallvec_inline { 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 @@ -2802,7 +2730,7 @@ impl IntoIterator for SmallVec { raw: (&this.raw as *const RawSmallVec).read(), begin: 0, end: this.len, - _marker: PhantomData, + _marker: PhantomData } } } @@ -2811,83 +2739,62 @@ 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; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } + + fn into_iter(self) -> Self::IntoIter { 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; - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } + + fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl PartialEq> for SmallVec -where - T: PartialEq, +where T: PartialEq { #[inline] - fn eq(&self, other: &SmallVec) -> bool { - self.as_slice().eq(other.as_slice()) - } + 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, +where T: PartialEq { #[inline] - fn eq(&self, other: &[U; M]) -> bool { - self[..] == other[..] - } + fn eq(&self, other: &[U; M]) -> bool { self[..] == other[..] } } impl PartialEq<&[U; M]> for SmallVec -where - T: PartialEq, +where T: PartialEq { #[inline] - fn eq(&self, other: &&[U; M]) -> bool { - self[..] == other[..] - } + fn eq(&self, other: &&[U; M]) -> bool { self[..] == other[..] } } impl PartialEq<[U]> for SmallVec -where - T: PartialEq, +where T: PartialEq { #[inline] - fn eq(&self, other: &[U]) -> bool { - self[..] == other[..] - } + fn eq(&self, other: &[U]) -> bool { self[..] == other[..] } } impl PartialEq<&[U]> for SmallVec -where - T: PartialEq, +where T: PartialEq { #[inline] - fn eq(&self, other: &&[U]) -> bool { - self[..] == other[..] - } + fn eq(&self, other: &&[U]) -> bool { self[..] == other[..] } } impl PartialEq<&mut [U]> for SmallVec -where - T: PartialEq, +where T: PartialEq { #[inline] - fn eq(&self, other: &&mut [U]) -> bool { - self[..] == other[..] - } + fn eq(&self, other: &&mut [U]) -> bool { self[..] == other[..] } } impl PartialOrd for SmallVec -where - T: PartialOrd, +where T: PartialOrd { #[inline] fn partial_cmp(&self, other: &SmallVec) -> Option { @@ -2896,8 +2803,7 @@ where } impl Ord for SmallVec -where - T: Ord, +where T: Ord { #[inline] fn cmp(&self, other: &SmallVec) -> core::cmp::Ordering { @@ -2906,37 +2812,27 @@ where } impl Hash for SmallVec { - fn hash(&self, state: &mut H) { - self.as_slice().hash(state) - } + fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } impl Borrow<[T]> for SmallVec { #[inline] - fn borrow(&self) -> &[T] { - self.as_slice() - } + fn borrow(&self) -> &[T] { self.as_slice() } } impl BorrowMut<[T]> for SmallVec { #[inline] - fn borrow_mut(&mut self) -> &mut [T] { - self.as_mut_slice() - } + 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() - } + 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() - } + fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl Debug for SmallVec { @@ -2957,174 +2853,17 @@ 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 { - 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 { +impl Write for SmallVec { + fn write(&mut self, buf: &[u8]) -> IoResult { self.extend_from_slice(buf); Ok(buf.len()) } - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { 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); - } + fn flush(&mut self) -> IoResult<()> { Ok(()) } } diff --git a/src/mallocsizeof.rs b/src/mallocsizeof.rs new file mode 100644 index 00000000..50c84b4a --- /dev/null +++ b/src/mallocsizeof.rs @@ -0,0 +1,28 @@ +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 dadbf958..d0192efc 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,5 +1,10 @@ -use core::mem::{ManuallyDrop, MaybeUninit}; -use core::ptr::NonNull; +use core::{ + mem::{ + ManuallyDrop, + MaybeUninit + }, + ptr::NonNull +}; /// Either a stack array with `length <= N` or a heap array /// whose pointer and capacity are stored here. @@ -9,5 +14,5 @@ use core::ptr::NonNull; #[repr(C)] pub union RawSmallVec { pub inline: ManuallyDrop>, - pub heap: (NonNull, usize), + pub heap: (NonNull, usize) } diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 00000000..1c7d92b0 --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,65 @@ +use { + super::SmallVec, + core::marker::PhantomData, + serde_core::{ + Deserialize, + Deserializer, + Serialize, + Serializer, + de::{ + SeqAccess, + Visitor + }, + ser::SerializeSeq + } +}; + +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) + } +} diff --git a/src/tests.rs b/src/tests.rs index e05f24d4..73aab6d1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,10 +1,16 @@ -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, + alloc::{ + borrow::ToOwned, + boxed::Box, + rc::Rc, + vec::Vec + }, + core::{ + hash::Hasher, + iter::FromIterator + } +}; #[test] pub fn test_zero() { @@ -106,9 +112,7 @@ pub fn test_double_spill() { // https://github.com/servo/rust-smallvec/issues/4 #[test] -fn issue_4() { - SmallVec::, 2>::new(); -} +fn issue_4() { SmallVec::, 2>::new(); } // https://github.com/servo/rust-smallvec/issues/5 #[test] @@ -167,7 +171,7 @@ fn drain_rev() { #[test] fn drain_forget() { - let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut v: SmallVec = SmallVec::from([0, 1, 2, 3, 4, 5, 6, 7]); std::mem::forget(v.drain(2..5)); assert_eq!(v.len(), 2); } @@ -175,21 +179,21 @@ fn drain_forget() { #[test] fn splice() { // The range starts right before the end. - let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6]; + let mut v: SmallVec = SmallVec::from([0, 1, 2, 3, 4, 5, 6]); let new = [7, 8, 9, 10]; 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 mut v: SmallVec = SmallVec::from([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 mut v: SmallVec = SmallVec::from([0, 1, 2, 3, 4, 5, 6]); let new = [7, 8, 9, 10]; let u: SmallVec = v.splice(..3, new).collect(); assert_eq!(v, [7, 8, 9, 10, 3, 4, 5, 6]); @@ -231,9 +235,7 @@ fn into_iter_drop() { struct DropCounter<'a>(&'a Cell); impl<'a> Drop for DropCounter<'a> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } + fn drop(&mut self) { self.0.set(self.0.get() + 1); } } { @@ -317,7 +319,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(); @@ -338,7 +340,7 @@ fn test_truncate_references() { #[test] fn test_split_off() { - let mut vec: SmallVec = smallvec![1, 2, 3, 4, 5, 6]; + let mut vec: SmallVec = SmallVec::from([1, 2, 3, 4, 5, 6]); let orig_ptr = vec.as_ptr(); let orig_capacity = vec.capacity(); @@ -400,7 +402,7 @@ fn test_invalid_grow() { #[test] #[should_panic] fn drain_overflow() { - let mut v: SmallVec = smallvec![0]; + let mut v: SmallVec = SmallVec::from([0]); v.drain(..=usize::MAX); } @@ -420,7 +422,7 @@ fn test_extend_from_slice() { #[test] fn test_extend_from_within() { - let mut v: SmallVec = smallvec![0, 1, 2, 3]; + let mut v: SmallVec = SmallVec::from([0, 1, 2, 3]); v.extend_from_within(1..3); assert_eq!( &v.iter().map(|v| *v).collect::>(), @@ -486,8 +488,10 @@ 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(); @@ -567,17 +571,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); @@ -589,7 +593,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)] @@ -599,14 +603,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]; @@ -686,7 +690,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()) } @@ -694,10 +698,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] @@ -714,32 +718,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); @@ -830,25 +834,44 @@ fn test_write() { #[cfg(feature = "serde")] #[test] fn test_serde() { - use serde_test::{assert_tokens, Token}; + use serde_test::{ + Token, + assert_tokens + }; let mut small_vec: SmallVec = SmallVec::new(); - assert_tokens(&small_vec, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); + assert_tokens( + &small_vec, + &[ + Token::Seq { + len: Some(0) + }, + Token::SeqEnd + ] + ); small_vec.push(1); assert_tokens( &small_vec, - &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], + &[ + Token::Seq { + len: Some(1) + }, + Token::I32(1), + Token::SeqEnd + ] ); small_vec.extend([2, 3, 4]); assert_tokens( &small_vec, &[ - Token::Seq { len: Some(4) }, + Token::Seq { + len: Some(4) + }, Token::I32(1), Token::I32(2), Token::I32(3), Token::I32(4), - Token::SeqEnd, - ], + Token::SeqEnd + ] ); } @@ -903,9 +926,7 @@ fn grow_spilled_same_size() { } #[test] -fn const_generics() { - let _v = SmallVec::::default(); -} +fn const_generics() { let _v = SmallVec::::default(); } #[test] fn const_new() { @@ -922,25 +943,15 @@ 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] -} +const fn const_new_inner() -> SmallVec { SmallVec::::new() } +const fn const_new_inline_sized() -> SmallVec { SmallVec::from_buf([1; 4]) } +const fn const_new_inline_args() -> SmallVec { SmallVec::from_buf([1, 4]) } #[test] -fn empty_macro() { - let _v: SmallVec = smallvec![]; -} +fn empty_macro() { let _v: SmallVec = SmallVec::new(); } #[test] -fn zero_size_items() { - SmallVec::<(), 0>::new().push(()); -} +fn zero_size_items() { SmallVec::<(), 0>::new().push(()); } #[test] fn test_clone_from() { @@ -966,7 +977,7 @@ fn test_clone_from() { #[test] fn test_extract_if() { - let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; + let mut a: SmallVec = SmallVec::from([0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]); let b: SmallVec = a.extract_if(1..9, |x| *x % 3 == 0).collect(); @@ -983,7 +994,7 @@ fn test_extract_if() { /// wrong" args. #[test] fn max_dont_panic() { - let mut sv: SmallVec = smallvec![0]; + let mut sv: SmallVec = SmallVec::from([0]); let _ = sv.get(usize::MAX); sv.truncate(usize::MAX); } @@ -991,21 +1002,21 @@ fn max_dont_panic() { #[test] #[should_panic] fn max_remove() { - let mut sv: SmallVec = smallvec![0]; + let mut sv: SmallVec = SmallVec::from([0]); sv.remove(usize::MAX); } #[test] #[should_panic] fn max_swap_remove() { - let mut sv: SmallVec = smallvec![0]; + let mut sv: SmallVec = SmallVec::from([0]); sv.swap_remove(usize::MAX); } #[test] #[should_panic] fn max_insert() { - let mut sv: SmallVec = smallvec![0]; + let mut sv: SmallVec = SmallVec::from([0]); sv.insert(usize::MAX, 0); } @@ -1016,9 +1027,8 @@ fn collect_from_iter() { impl Iterator for IterNoHint { type Item = I::Item; - fn next(&mut self) -> Option { - self.0.next() - } + + 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. From a50d8b302664a53c0339630d80c4355436fd4183 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Thu, 27 Aug 2026 16:29:59 +0200 Subject: [PATCH 2/5] fix: ran rustfmt --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b70fffa7..4d63a8be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,6 +83,7 @@ use std::io::{ Write }; use { + add_syntax::prepend, alloc::{ alloc::Layout, boxed::Box, @@ -111,8 +112,7 @@ use { copy, copy_nonoverlapping } - }, - add_syntax::prepend + } }; /// Error type for APIs with fallible heap allocation From 713ec9005d9ebc1e805cb90885805191e5f38c0c Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Thu, 27 Aug 2026 16:36:56 +0200 Subject: [PATCH 3/5] refactor: added references.rs --- src/lib.rs | 36 +----------------------------------- src/references.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 src/references.rs diff --git a/src/lib.rs b/src/lib.rs index 4d63a8be..323cf279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,6 +70,7 @@ mod bytes; #[cfg(feature = "malloc_size_of")] mod mallocsizeof; mod rawsmallvec; +mod references; #[cfg(feature = "serde")] mod serde; #[cfg(test)] @@ -90,10 +91,6 @@ use { vec::Vec }, core::{ - borrow::{ - Borrow, - BorrowMut - }, fmt::Debug, hash::{ Hash, @@ -2069,17 +2066,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)] @@ -2815,26 +2801,6 @@ impl Hash for SmallVec { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } -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 00000000..de0dffde --- /dev/null +++ b/src/references.rs @@ -0,0 +1,39 @@ +use { + super::SmallVec, + core::borrow::{ + Borrow, + BorrowMut + } +}; + +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 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() } +} From 73354f07339a2adea050f3273937fa179be17dee Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Thu, 27 Aug 2026 16:42:34 +0200 Subject: [PATCH 4/5] refactor: added comparisons.rs --- src/comparisons.rs | 40 ++++++++++++++++++++++++++++++ src/lib.rs | 62 +--------------------------------------------- src/references.rs | 22 ++++++++-------- 3 files changed, 52 insertions(+), 72 deletions(-) create mode 100644 src/comparisons.rs diff --git a/src/comparisons.rs b/src/comparisons.rs new file mode 100644 index 00000000..97bd6db6 --- /dev/null +++ b/src/comparisons.rs @@ -0,0 +1,40 @@ +use super::SmallVec; + +impl, U, const N: usize, const M: usize> PartialEq> + for SmallVec +{ + fn eq(&self, other: &SmallVec) -> bool { self.as_slice().eq(other.as_slice()) } +} +impl Eq for SmallVec where T: Eq {} + +impl, U, const N: usize, const M: usize> PartialEq<[U; M]> for SmallVec { + fn eq(&self, other: &[U; M]) -> bool { self[..] == other[..] } +} + +impl, U, const N: usize, const M: usize> PartialEq<&[U; M]> for SmallVec { + fn eq(&self, other: &&[U; M]) -> bool { self[..] == other[..] } +} + +impl, U, const N: usize> PartialEq<[U]> for SmallVec { + fn eq(&self, other: &[U]) -> bool { self[..] == other[..] } +} + +impl, U, const N: usize> PartialEq<&[U]> for SmallVec { + fn eq(&self, other: &&[U]) -> bool { self[..] == other[..] } +} + +impl, U, const N: usize> PartialEq<&mut [U]> for SmallVec { + fn eq(&self, other: &&mut [U]) -> bool { self[..] == other[..] } +} + +impl PartialOrd for SmallVec { + fn partial_cmp(&self, other: &SmallVec) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl Ord for SmallVec { + 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 323cf279..d6058193 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ extern crate std; #[cfg(feature = "bytes")] mod bytes; +mod comparisons; #[cfg(feature = "malloc_size_of")] mod mallocsizeof; mod rawsmallvec; @@ -2736,67 +2737,6 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec { fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } -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) } } diff --git a/src/references.rs b/src/references.rs index de0dffde..9fb77aa1 100644 --- a/src/references.rs +++ b/src/references.rs @@ -1,39 +1,39 @@ use { super::SmallVec, - core::borrow::{ - Borrow, - BorrowMut + core::{ + borrow::{ + Borrow, + BorrowMut + }, + ops::{ + Deref, + DerefMut + } } }; 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 core::ops::Deref for SmallVec { +impl Deref for SmallVec { type Target = [T]; - #[inline] fn deref(&self) -> &Self::Target { self.as_slice() } } -impl core::ops::DerefMut for SmallVec { - #[inline] +impl DerefMut for SmallVec { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } From 8e721b2c9a1fe18be3bf4f913165161b21c4b77a Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Thu, 27 Aug 2026 16:58:35 +0200 Subject: [PATCH 5/5] refactor: taggedlen && full rawsmallvec --- src/lib.rs | 176 ++------------------------------------------- src/rawsmallvec.rs | 123 +++++++++++++++++++++++++++++-- src/taggedlen.rs | 46 ++++++++++++ 3 files changed, 171 insertions(+), 174 deletions(-) create mode 100644 src/taggedlen.rs diff --git a/src/lib.rs b/src/lib.rs index d6058193..5a0c81f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,11 +74,10 @@ mod rawsmallvec; mod references; #[cfg(feature = "serde")] mod serde; +mod taggedlen; #[cfg(test)] mod tests; -#[cfg_attr(feature = "internals", prepend(pub))] -use rawsmallvec::RawSmallVec; #[cfg(feature = "std")] use std::io::{ Result as IoResult, @@ -112,6 +111,11 @@ use { } } }; +#[cfg_attr(feature = "internals", prepend(pub))] +use { + rawsmallvec::RawSmallVec, + taggedlen::TaggedLen +}; /// Error type for APIs with fallible heap allocation #[derive(Debug)] @@ -143,10 +147,6 @@ fn infallible(result: Result) -> T { } } -/// 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. @@ -183,168 +183,6 @@ where R: core::ops::RangeBounds { } } -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 - #[allow(unused_unsafe, reason = "Unsafe in MSRV 1.83.0")] - (unsafe { &raw const self.inline }).cast() - } - - #[inline] - const fn as_mut_ptr_inline(&mut self) -> *mut T { - // SAFETY: same as above - #[allow(unused_unsafe, reason = "Unsafe in MSRV 1.83.0")] - (unsafe { &raw mut self.inline }).cast() - } - - /// # 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 !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, @@ -928,7 +766,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 { diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index d0192efc..8b3d5375 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,9 +1,19 @@ -use core::{ - mem::{ - ManuallyDrop, - MaybeUninit +use { + super::{ + CollectionAllocErr, + TaggedLen }, - ptr::NonNull + core::{ + alloc::Layout, + mem::{ + ManuallyDrop, + MaybeUninit + }, + ptr::{ + NonNull, + copy_nonoverlapping + } + } }; /// Either a stack array with `length <= N` or a heap array @@ -16,3 +26,106 @@ pub union RawSmallVec { pub inline: ManuallyDrop>, pub heap: (NonNull, usize) } + +impl RawSmallVec { + const IS_ZST: bool = size_of::() == 0; + + pub const fn new() -> Self { Self::new_inline(MaybeUninit::uninit()) } + + pub const fn new_inline(inline: MaybeUninit<[T; N]>) -> Self { + Self { + inline: ManuallyDrop::new(inline) + } + } + + pub const fn new_heap(ptr: NonNull, capacity: usize) -> Self { + Self { + heap: (ptr, capacity) + } + } + + 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 = "Unsafe in MSRV 1.83.0")] + (unsafe { &raw const self.inline }).cast() + } + + pub const fn as_mut_ptr_inline(&mut self) -> *mut T { + // SAFETY: same as above + #[allow(unused_unsafe, reason = "Unsafe in MSRV 1.83.0")] + (unsafe { &raw mut self.inline }).cast() + } + + /// # Safety + /// + /// The vector must be on the heap + pub const unsafe fn as_ptr_heap(&self) -> *const T { self.heap.0.as_ptr() } + + /// # Safety + /// + /// The vector must be on the heap + 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<(), 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 !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(()) + } +} diff --git a/src/taggedlen.rs b/src/taggedlen.rs new file mode 100644 index 00000000..45be2afa --- /dev/null +++ b/src/taggedlen.rs @@ -0,0 +1,46 @@ +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 { + fn clone(&self) -> Self { Self(self.0, PhantomData) } + + fn clone_from(&mut self, source: &Self) { self.0 = source.0; } +} + +impl Copy for TaggedLen {} + +impl TaggedLen { + pub const fn new(len: usize, on_heap: bool) -> Self { + if size_of::() == 0 { + debug_assert!(!on_heap); + Self(len, PhantomData) + } else { + debug_assert!(len < isize::MAX as usize); + Self((len << 1) | on_heap as usize, PhantomData) + } + } + + #[must_use] + pub const fn on_heap(self) -> bool { return (size_of::() != 0) && ((self.0 & 1usize) == 1); } + + pub const fn value(self) -> usize { + return if size_of::() == 0 { + self.0 + } else { + self.0 >> 1 + }; + } +}