From 6045e601a89797db82fb958d5e8f539625bae9e2 Mon Sep 17 00:00:00 2001 From: mematthias <107192630+mematthias@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:22:25 +0200 Subject: [PATCH 1/3] - added push_mut - applied cargo fmt --- src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++---------------- src/tests.rs | 19 +++++++++--- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e6bc8c7..f8e5de8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ impl Clone for TaggedLen { fn clone(&self) -> Self { Self(self.0, PhantomData) } - + #[inline] fn clone_from(&mut self, source: &Self) { self.0 = source.0; @@ -508,7 +508,10 @@ impl Drain<'_, T, N> { let range_start = vec.len(); let range_end = self.tail_start; let range_slice = unsafe { - core::slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) + core::slice::from_raw_parts_mut( + vec.as_mut_ptr().add(range_start), + range_end - range_start, + ) }; for place in range_slice { @@ -708,7 +711,11 @@ impl Drop for Splice<'_, I, N> { } // Collect any remaining elements. - let mut collected = self.replace_with.by_ref().collect::>().into_iter(); + let mut collected = self + .replace_with + .by_ref() + .collect::>() + .into_iter(); // Now we have an exact count. if collected.len() > 0 { self.drain.move_tail(collected.len()); @@ -744,7 +751,6 @@ 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 { let on_heap = self.end.on_heap(); @@ -773,10 +779,7 @@ impl IntoIter { // So the pointer arithmetic is valid, and so is the construction of the slice unsafe { let ptr = self.as_ptr(); - core::slice::from_raw_parts( - ptr.add(self.begin), - self.end.value() - self.begin, - ) + core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) } } @@ -785,10 +788,7 @@ impl IntoIter { // SAFETY: see above unsafe { let ptr = self.as_mut_ptr(); - core::slice::from_raw_parts_mut( - ptr.add(self.begin), - self.end.value() - self.begin, - ) + core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin) } } } @@ -861,7 +861,9 @@ impl SmallVec { #[inline] pub const fn from_buf(elements: [T; S]) -> Self { - const { assert!(S <= N); } + 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 ) @@ -1218,21 +1220,34 @@ impl SmallVec { R: core::ops::RangeBounds, I: IntoIterator, { - Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } } #[inline] pub fn push(&mut self, value: T) { + _ = self.push_mut(value); + } + + #[inline] + #[must_use] + pub fn push_mut(&mut self, value: T) -> &mut T { let len = self.len(); if len == self.capacity() { self.reserve(1); } + // 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. unsafe { ptr.write(value) }; unsafe { self.set_len(len + 1) } + + let result = unsafe { ptr.as_mut() }; + unsafe { result.unwrap_unchecked() } } #[inline] @@ -1253,7 +1268,11 @@ 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] @@ -1418,7 +1437,10 @@ 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 target < self.capacity() { @@ -1449,7 +1471,10 @@ impl SmallVec { #[inline] pub fn swap_remove(&mut self, index: usize) -> T { let len = self.len(); - assert!(index < len, "swap_remove index (is {index}) should be < len (is {len})"); + assert!( + index < len, + "swap_remove index (is {index}) should be < len (is {len})" + ); // This can't overflow since `len > index >= 0` let new_len = len - 1; unsafe { @@ -1481,7 +1506,10 @@ impl SmallVec { #[inline] pub fn remove(&mut self, index: usize) -> T { let len = self.len(); - assert!(index < len, "removal index (is {index}) should be < len (is {len})"); + assert!( + index < len, + "removal index (is {index}) should be < len (is {len})" + ); let new_len = len - 1; unsafe { // SAFETY: new_len < len @@ -1498,7 +1526,10 @@ impl SmallVec { #[inline] pub fn insert(&mut self, index: usize, value: T) { let len = self.len(); - assert!(index <= len, "insertion index (is {index}) should be <= len (is {len})"); + assert!( + index <= len, + "insertion index (is {index}) should be <= len (is {len})" + ); self.reserve(1); let ptr = self.as_mut_ptr(); unsafe { @@ -1694,7 +1725,9 @@ impl SmallVec { pub fn leak<'a>(self) -> &'a mut [T] { if !self.spilled() { - panic!("SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked"); + panic!( + "SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked" + ); } let mut me = ManuallyDrop::new(self); unsafe { core::slice::from_raw_parts_mut(me.as_mut_ptr(), me.len()) } @@ -1827,12 +1860,11 @@ impl SmallVec { #[inline] pub fn extend_from_slice_copy(&mut self, other: &[T]) where - T: Copy + T: Copy, { - let len = other.len(); let src = other.as_ptr(); - + let l = self.len(); self.reserve(len); @@ -1848,7 +1880,7 @@ 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; @@ -1867,7 +1899,7 @@ impl SmallVec { pub fn insert_from_slice_copy(&mut self, index: usize, other: &[T]) where - T: Copy + T: Copy, { let l = self.len(); let len = other.len(); @@ -1891,7 +1923,7 @@ impl SmallVec { /// for types with the [`Copy`] trait. pub fn from_slice_copy(slice: &[T]) -> Self where - T: Copy + T: Copy, { let src = slice.as_ptr(); let len = slice.len(); diff --git a/src/tests.rs b/src/tests.rs index 2082f96..47722d5 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -19,6 +19,20 @@ pub fn test_zero() { // We heap allocate all these strings so that double frees will show up under valgrind. +#[test] +pub fn test_push_mut() { + let mut v = SmallVec::<_, 16>::new(); + + let first_elem = v.push_mut("hello".to_owned()); + assert_eq!(&*first_elem, &"hello".to_owned()); + + *first_elem = "hi".to_owned(); + assert_eq!(&*first_elem, &"hi".to_owned()); + + v.push("there".to_owned()); + assert_eq!(&*v, &["hi".to_owned(), "there".to_owned(),][..]); +} + #[test] pub fn test_inline() { let mut v = SmallVec::<_, 16>::new(); @@ -587,10 +601,7 @@ fn test_from() { #[test] fn test_from_slice() { assert_eq!(&SmallVec::::from(&[1][..])[..], [1]); - assert_eq!( - &SmallVec::::from(&[1, 2, 3][..])[..], - [1, 2, 3] - ); + assert_eq!(&SmallVec::::from(&[1, 2, 3][..])[..], [1, 2, 3]); } #[test] From 4efb7a312944e334e8583926e44361cb7df4a336 Mon Sep 17 00:00:00 2001 From: mematthias <107192630+mematthias@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:34:13 +0200 Subject: [PATCH 2/3] added insert_mut --- src/lib.rs | 13 +++++++++++-- src/tests.rs | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f8e5de8..c282686 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1525,24 +1525,33 @@ impl SmallVec { #[inline] pub fn insert(&mut self, index: usize, value: T) { + _ = self.insert_mut(index, value); + } + + #[inline] + #[must_use] + pub fn insert_mut(&mut self, index: usize, value: T) -> &mut T { let len = self.len(); assert!( index <= len, "insertion index (is {index}) should be <= len (is {len})" ); self.reserve(1); - let ptr = self.as_mut_ptr(); + let mut ptr = self.as_mut_ptr(); unsafe { // the elements at `index + 1..len + 1` are now initialized if index < len { copy(ptr.add(index), ptr.add(index + 1), len - index); } // the element at `index` is now initialized - ptr.add(index).write(value); + ptr = ptr.add(index); + ptr.write(value); // SAFETY: all the elements are initialized self.set_len(len + 1); } + let result = unsafe { ptr.as_mut() }; + unsafe { result.unwrap_unchecked() } } #[inline] diff --git a/src/tests.rs b/src/tests.rs index 47722d5..d8098f0 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -33,6 +33,24 @@ pub fn test_push_mut() { assert_eq!(&*v, &["hi".to_owned(), "there".to_owned(),][..]); } +#[test] +pub fn test_insert_mut() { + let mut v = SmallVec::<_, 16>::new(); + v.push("hello".to_owned()); + v.push("there".to_owned()); + + let second_elem = v.insert_mut(1, ",".to_owned()); + assert_eq!(&*second_elem, &",".to_owned()); + + *second_elem = ";".to_owned(); + assert_eq!(&*second_elem, &";".to_owned()); + + assert_eq!( + &*v, + &["hello".to_owned(), ";".to_owned(), "there".to_owned(),][..] + ); +} + #[test] pub fn test_inline() { let mut v = SmallVec::<_, 16>::new(); From a96b2f74265d3e279b0e038868e7b9bcb4362cf6 Mon Sep 17 00:00:00 2001 From: mematthias <107192630+mematthias@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:08:42 +0200 Subject: [PATCH 3/3] Review changes applied Reverted cargo fmt changes --- src/lib.rs | 83 +++++++++++++++++++----------------------------------- 1 file changed, 29 insertions(+), 54 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c282686..8f92164 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ impl Clone for TaggedLen { fn clone(&self) -> Self { Self(self.0, PhantomData) } - + #[inline] fn clone_from(&mut self, source: &Self) { self.0 = source.0; @@ -508,10 +508,7 @@ impl Drain<'_, T, N> { let range_start = vec.len(); let range_end = self.tail_start; let range_slice = unsafe { - core::slice::from_raw_parts_mut( - vec.as_mut_ptr().add(range_start), - range_end - range_start, - ) + core::slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) }; for place in range_slice { @@ -711,11 +708,7 @@ impl Drop for Splice<'_, I, N> { } // Collect any remaining elements. - let mut collected = self - .replace_with - .by_ref() - .collect::>() - .into_iter(); + let mut collected = self.replace_with.by_ref().collect::>().into_iter(); // Now we have an exact count. if collected.len() > 0 { self.drain.move_tail(collected.len()); @@ -751,6 +744,7 @@ 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 { let on_heap = self.end.on_heap(); @@ -779,7 +773,10 @@ impl IntoIter { // So the pointer arithmetic is valid, and so is the construction of the slice unsafe { let ptr = self.as_ptr(); - core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) + core::slice::from_raw_parts( + ptr.add(self.begin), + self.end.value() - self.begin, + ) } } @@ -788,7 +785,10 @@ impl IntoIter { // SAFETY: see above unsafe { let ptr = self.as_mut_ptr(); - core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin) + core::slice::from_raw_parts_mut( + ptr.add(self.begin), + self.end.value() - self.begin, + ) } } } @@ -861,9 +861,7 @@ impl SmallVec { #[inline] pub const fn from_buf(elements: [T; S]) -> Self { - const { - assert!(S <= N); - } + 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 ) @@ -1220,10 +1218,7 @@ impl SmallVec { R: core::ops::RangeBounds, I: IntoIterator, { - Splice { - drain: self.drain(range), - replace_with: replace_with.into_iter(), - } + Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } #[inline] @@ -1238,16 +1233,13 @@ impl SmallVec { if len == self.capacity() { self.reserve(1); } - // 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. unsafe { ptr.write(value) }; unsafe { self.set_len(len + 1) } - - let result = unsafe { ptr.as_mut() }; - unsafe { result.unwrap_unchecked() } + unsafe { &mut *ptr } } #[inline] @@ -1268,11 +1260,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] @@ -1437,10 +1425,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 target < self.capacity() { @@ -1471,10 +1456,7 @@ impl SmallVec { #[inline] pub fn swap_remove(&mut self, index: usize) -> T { let len = self.len(); - assert!( - index < len, - "swap_remove index (is {index}) should be < len (is {len})" - ); + assert!(index < len, "swap_remove index (is {index}) should be < len (is {len})"); // This can't overflow since `len > index >= 0` let new_len = len - 1; unsafe { @@ -1506,10 +1488,7 @@ impl SmallVec { #[inline] pub fn remove(&mut self, index: usize) -> T { let len = self.len(); - assert!( - index < len, - "removal index (is {index}) should be < len (is {len})" - ); + assert!(index < len, "removal index (is {index}) should be < len (is {len})"); let new_len = len - 1; unsafe { // SAFETY: new_len < len @@ -1532,10 +1511,7 @@ impl SmallVec { #[must_use] pub fn insert_mut(&mut self, index: usize, value: T) -> &mut T { let len = self.len(); - assert!( - index <= len, - "insertion index (is {index}) should be <= len (is {len})" - ); + assert!(index <= len, "insertion index (is {index}) should be <= len (is {len})"); self.reserve(1); let mut ptr = self.as_mut_ptr(); unsafe { @@ -1549,9 +1525,9 @@ impl SmallVec { // SAFETY: all the elements are initialized self.set_len(len + 1); + + &mut *ptr } - let result = unsafe { ptr.as_mut() }; - unsafe { result.unwrap_unchecked() } } #[inline] @@ -1734,9 +1710,7 @@ impl SmallVec { pub fn leak<'a>(self) -> &'a mut [T] { if !self.spilled() { - panic!( - "SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked" - ); + panic!("SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked"); } let mut me = ManuallyDrop::new(self); unsafe { core::slice::from_raw_parts_mut(me.as_mut_ptr(), me.len()) } @@ -1869,11 +1843,12 @@ impl SmallVec { #[inline] pub fn extend_from_slice_copy(&mut self, other: &[T]) where - T: Copy, + T: Copy { + let len = other.len(); let src = other.as_ptr(); - + let l = self.len(); self.reserve(len); @@ -1889,7 +1864,7 @@ 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; @@ -1908,7 +1883,7 @@ impl SmallVec { pub fn insert_from_slice_copy(&mut self, index: usize, other: &[T]) where - T: Copy, + T: Copy { let l = self.len(); let len = other.len(); @@ -1932,7 +1907,7 @@ impl SmallVec { /// for types with the [`Copy`] trait. pub fn from_slice_copy(slice: &[T]) -> Self where - T: Copy, + T: Copy { let src = slice.as_ptr(); let len = slice.len();