From 4d2d337329f4fc30ff38a76042e99b319961c1af Mon Sep 17 00:00:00 2001 From: Mahidul Haque <114881854+Kxrma47@users.noreply.github.com> Date: Wed, 23 Sep 2026 23:58:56 +0300 Subject: [PATCH 1/2] Move Splice into its own module Signed-off-by: Mahidul Haque <114881854+Kxrma47@users.noreply.github.com> --- src/iterators/mod.rs | 1 + src/iterators/splice.rs | 104 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 100 +------------------------------------- 3 files changed, 107 insertions(+), 98 deletions(-) create mode 100644 src/iterators/splice.rs diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 76d773da..81cf7c17 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1,5 +1,6 @@ pub mod drain; pub mod extractif; +pub mod splice; #[cfg(feature = "rayon")] mod rayon; diff --git a/src/iterators/splice.rs b/src/iterators/splice.rs new file mode 100644 index 00000000..b8b0c076 --- /dev/null +++ b/src/iterators/splice.rs @@ -0,0 +1,104 @@ +use crate::{ + Drain, + Global, + SmallVec +}; + +pub struct Splice<'a, I: Iterator + 'a, const N: usize> { + drain: Drain<'a, I::Item, N, Global>, + replace_with: I +} + +impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> +where + I: core::fmt::Debug + Iterator + 'a, + ::Item: core::fmt::Debug +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Splice").field(&self.drain).finish() + } +} + +impl Iterator for Splice<'_, I, N> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +impl DoubleEndedIterator for Splice<'_, I, N> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +impl ExactSizeIterator for Splice<'_, I, N> {} + +impl Drop for Splice<'_, I, N> { + fn drop(&mut self) { + self.drain.by_ref().for_each(drop); + // At this point draining is done and the only remaining tasks are + // splicing and moving things into the final place. + // Which means we can replace the slice::Iter with pointers that won't + // point to deallocated memory, so that Drain::drop is still + // allowed to call iter.len(), otherwise it would break the + // ptr.sub_ptr contract. + self.drain.iter = [].iter(); + + unsafe { + if self.drain.tail_len == 0 { + self.drain.vec.as_mut().extend(self.replace_with.by_ref()); + return; + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return; + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return; + } + } + + // Collect any remaining elements. + 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()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore + // `vec.length`. + } +} + +impl SmallVec { + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> + where + R: core::ops::RangeBounds, + I: IntoIterator + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter() + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 92c26563..64493ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,8 @@ mod errors; mod iterators; pub use iterators::{ drain::Drain, - extractif::ExtractIf + extractif::ExtractIf, + splice::Splice }; mod macros; #[cfg(feature = "malloc_size_of")] @@ -153,92 +154,6 @@ impl Default for SmallVec { } } -pub struct Splice<'a, I: Iterator + 'a, const N: usize> { - drain: Drain<'a, I::Item, N, Global>, - replace_with: I -} - -impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> -where - I: Debug + Iterator + 'a, - ::Item: Debug -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("Splice").field(&self.drain).finish() - } -} - -impl Iterator for Splice<'_, I, N> { - type Item = I::Item; - - fn next(&mut self) -> Option { - self.drain.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.drain.size_hint() - } -} - -impl DoubleEndedIterator for Splice<'_, I, N> { - fn next_back(&mut self) -> Option { - self.drain.next_back() - } -} - -impl ExactSizeIterator for Splice<'_, I, N> {} - -impl Drop for Splice<'_, I, N> { - fn drop(&mut self) { - self.drain.by_ref().for_each(drop); - // At this point draining is done and the only remaining tasks are - // splicing and moving things into the final place. - // Which means we can replace the slice::Iter with pointers that won't - // point to deallocated memory, so that Drain::drop is still - // allowed to call iter.len(), otherwise it would break the - // ptr.sub_ptr contract. - self.drain.iter = [].iter(); - - unsafe { - if self.drain.tail_len == 0 { - self.drain.vec.as_mut().extend(self.replace_with.by_ref()); - return; - } - - // First fill the range left by drain(). - if !self.drain.fill(&mut self.replace_with) { - return; - } - - // There may be more elements. Use the lower bound as an estimate. - // FIXME: Is the upper bound a better guess? Or something else? - let (lower_bound, _upper_bound) = self.replace_with.size_hint(); - if lower_bound > 0 { - self.drain.move_tail(lower_bound); - if !self.drain.fill(&mut self.replace_with) { - return; - } - } - - // Collect any remaining elements. - 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()); - let filled = self.drain.fill(&mut collected); - debug_assert!(filled); - debug_assert_eq!(collected.len(), 0); - } - } - // Let `Drain::drop` move the tail back if necessary and restore - // `vec.length`. - } -} - /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. @@ -477,17 +392,6 @@ impl SmallVec { } } - pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> - where - R: core::ops::RangeBounds, - I: IntoIterator - { - Splice { - drain: self.drain(range), - replace_with: replace_with.into_iter() - } - } - /// Creates a `SmallVec` directly from the raw components of another /// `SmallVec`. /// From 0058fef76c53343e5ac1d99e419a49eeb7c10719 Mon Sep 17 00:00:00 2001 From: Mahidul Haque <114881854+Kxrma47@users.noreply.github.com> Date: Thu, 24 Sep 2026 00:08:06 +0300 Subject: [PATCH 2/2] Keep SmallVec splice method in lib Signed-off-by: Mahidul Haque <114881854+Kxrma47@users.noreply.github.com> --- src/iterators/splice.rs | 22 +++++++++------------- src/lib.rs | 8 ++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/iterators/splice.rs b/src/iterators/splice.rs index b8b0c076..4f99e2f3 100644 --- a/src/iterators/splice.rs +++ b/src/iterators/splice.rs @@ -9,6 +9,15 @@ pub struct Splice<'a, I: Iterator + 'a, const N: usize> { replace_with: I } +impl<'a, I: Iterator + 'a, const N: usize> Splice<'a, I, N> { + pub(crate) fn new(drain: Drain<'a, I::Item, N, Global>, replace_with: I) -> Self { + Self { + drain, + replace_with + } + } +} + impl<'a, I, const N: usize> core::fmt::Debug for Splice<'a, I, N> where I: core::fmt::Debug + Iterator + 'a, @@ -89,16 +98,3 @@ impl Drop for Splice<'_, I, N> { // `vec.length`. } } - -impl SmallVec { - pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> - where - R: core::ops::RangeBounds, - I: IntoIterator - { - Splice { - drain: self.drain(range), - replace_with: replace_with.into_iter() - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 64493ffd..14b04256 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -392,6 +392,14 @@ impl SmallVec { } } + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, N> + where + R: core::ops::RangeBounds, + I: IntoIterator + { + Splice::new(self.drain(range), replace_with.into_iter()) + } + /// Creates a `SmallVec` directly from the raw components of another /// `SmallVec`. ///