From aee0d00899772c09ddf5c22c2e354653c84fcfb8 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 5 Oct 2026 14:24:38 +0200 Subject: [PATCH 01/14] feat: allocator extension for splice --- src/iterators/splice/allocref.rs | 32 ++++++++++++++++++++++ src/iterators/{splice.rs => splice/mod.rs} | 26 ++++++++++-------- 2 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/iterators/splice/allocref.rs rename src/iterators/{splice.rs => splice/mod.rs} (88%) diff --git a/src/iterators/splice/allocref.rs b/src/iterators/splice/allocref.rs new file mode 100644 index 00000000..a61e22b6 --- /dev/null +++ b/src/iterators/splice/allocref.rs @@ -0,0 +1,32 @@ +use { + super::Allocator, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +pub struct Allocref<'valid, Heap: Allocator>(pub &'valid Heap); + +impl<'valid, Heap: Allocator> Allocator for Allocref<'valid, Heap> { + fn allocate(&self, layout: Layout) -> Option> { + self.0.allocate(layout) + } + + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { self.0.deallocate(pointer, layout) }; + } + + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { self.0.grow(pointer, old, new) } + } + + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { self.0.shrink(pointer, old, new) } + } +} diff --git a/src/iterators/splice.rs b/src/iterators/splice/mod.rs similarity index 88% rename from src/iterators/splice.rs rename to src/iterators/splice/mod.rs index 2f231d17..7cd407a0 100644 --- a/src/iterators/splice.rs +++ b/src/iterators/splice/mod.rs @@ -1,8 +1,15 @@ -use crate::{ - Allocator, - Drain, - Global, - SmallVec +mod allocref; + +use { + allocref::Allocref, + super::{ + super::{ + Allocator, + Global, + SmallVec + }, + drain::Drain + } }; pub struct Splice<'a, I: Iterator + 'a, const N: usize, A: Allocator = Global> { @@ -81,12 +88,9 @@ impl Drop for Splice<'_, I, N, A> { } } - // Collect any remaining elements. - let mut collected = self - .replace_with - .by_ref() - .collect::>() - .into_iter(); + let mut smallvec = SmallVec::<_, N, _>::new_in(Allocref(&self.drain.vec.as_ref().allocator)); + smallvec.extend(self.replace_with.by_ref()); + let mut collected = smallvec.into_iter(); // Now we have an exact count. if collected.len() > 0 { From f457c6b644a18f9e61563a6497c577341b63f1ef Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 5 Oct 2026 14:27:52 +0200 Subject: [PATCH 02/14] chore: inline methods --- src/iterators/splice/allocref.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/iterators/splice/allocref.rs b/src/iterators/splice/allocref.rs index a61e22b6..1959b78b 100644 --- a/src/iterators/splice/allocref.rs +++ b/src/iterators/splice/allocref.rs @@ -9,18 +9,22 @@ use { pub struct Allocref<'valid, Heap: Allocator>(pub &'valid Heap); impl<'valid, Heap: Allocator> Allocator for Allocref<'valid, Heap> { + #[inline] fn allocate(&self, layout: Layout) -> Option> { self.0.allocate(layout) } + #[inline] unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { unsafe { self.0.deallocate(pointer, layout) }; } + #[inline] unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { unsafe { self.0.grow(pointer, old, new) } } + #[inline] unsafe fn shrink( &self, pointer: NonNull, From 54f15078a9ac6e0844c84c4f27e43620aae61cfb Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 5 Oct 2026 14:28:31 +0200 Subject: [PATCH 03/14] style: formatting --- src/iterators/splice/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/iterators/splice/mod.rs b/src/iterators/splice/mod.rs index 7cd407a0..281a61aa 100644 --- a/src/iterators/splice/mod.rs +++ b/src/iterators/splice/mod.rs @@ -1,7 +1,6 @@ mod allocref; use { - allocref::Allocref, super::{ super::{ Allocator, @@ -9,7 +8,8 @@ use { SmallVec }, drain::Drain - } + }, + allocref::Allocref }; pub struct Splice<'a, I: Iterator + 'a, const N: usize, A: Allocator = Global> { @@ -88,7 +88,8 @@ impl Drop for Splice<'_, I, N, A> { } } - let mut smallvec = SmallVec::<_, N, _>::new_in(Allocref(&self.drain.vec.as_ref().allocator)); + let mut smallvec = + SmallVec::<_, N, _>::new_in(Allocref(&self.drain.vec.as_ref().allocator)); smallvec.extend(self.replace_with.by_ref()); let mut collected = smallvec.into_iter(); From 594a982206dac2ed73106c9d06573c89a4065dc0 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 5 Oct 2026 14:32:43 +0200 Subject: [PATCH 04/14] chore: add repr transparent --- src/iterators/splice/allocref.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/iterators/splice/allocref.rs b/src/iterators/splice/allocref.rs index 1959b78b..ca5acd0a 100644 --- a/src/iterators/splice/allocref.rs +++ b/src/iterators/splice/allocref.rs @@ -6,6 +6,7 @@ use { } }; +#[repr(transparent)] pub struct Allocref<'valid, Heap: Allocator>(pub &'valid Heap); impl<'valid, Heap: Allocator> Allocator for Allocref<'valid, Heap> { From 3f91a9d39e3945005ef87a185588aaa1fcfe7d68 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 12:34:00 +0200 Subject: [PATCH 05/14] refactor: rename to proxy --- src/allocator/mod.rs | 1 + .../splice/allocref.rs => allocator/proxy.rs} | 4 ++-- src/iterators/{splice/mod.rs => splice.rs} | 10 ++++------ 3 files changed, 7 insertions(+), 8 deletions(-) rename src/{iterators/splice/allocref.rs => allocator/proxy.rs} (85%) rename src/iterators/{splice/mod.rs => splice.rs} (95%) diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 2e212219..5e67a3a8 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -4,6 +4,7 @@ mod base; mod external; #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] mod native; +pub mod proxy; use core::{ alloc::Layout, diff --git a/src/iterators/splice/allocref.rs b/src/allocator/proxy.rs similarity index 85% rename from src/iterators/splice/allocref.rs rename to src/allocator/proxy.rs index ca5acd0a..9628da89 100644 --- a/src/iterators/splice/allocref.rs +++ b/src/allocator/proxy.rs @@ -7,9 +7,9 @@ use { }; #[repr(transparent)] -pub struct Allocref<'valid, Heap: Allocator>(pub &'valid Heap); +pub struct Proxy<'valid, Heap: Allocator>(pub &'valid Heap); -impl<'valid, Heap: Allocator> Allocator for Allocref<'valid, Heap> { +impl<'valid, Heap: Allocator> Allocator for Proxy<'valid, Heap> { #[inline] fn allocate(&self, layout: Layout) -> Option> { self.0.allocate(layout) diff --git a/src/iterators/splice/mod.rs b/src/iterators/splice.rs similarity index 95% rename from src/iterators/splice/mod.rs rename to src/iterators/splice.rs index 281a61aa..0cee6c1c 100644 --- a/src/iterators/splice/mod.rs +++ b/src/iterators/splice.rs @@ -1,15 +1,13 @@ -mod allocref; - use { super::{ super::{ Allocator, Global, - SmallVec + SmallVec, + allocator::proxy::Proxy }, drain::Drain - }, - allocref::Allocref + } }; pub struct Splice<'a, I: Iterator + 'a, const N: usize, A: Allocator = Global> { @@ -89,7 +87,7 @@ impl Drop for Splice<'_, I, N, A> { } let mut smallvec = - SmallVec::<_, N, _>::new_in(Allocref(&self.drain.vec.as_ref().allocator)); + SmallVec::<_, N, _>::new_in(Proxy(&self.drain.vec.as_ref().allocator)); smallvec.extend(self.replace_with.by_ref()); let mut collected = smallvec.into_iter(); From 3cfbd2f85b86e1de4582a52cc4d6770a3b875cf8 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 12:56:45 +0200 Subject: [PATCH 06/14] refactor: better allocator org --- src/allocator/base.rs | 35 ---------------- src/allocator/boxed.rs | 4 ++ src/allocator/external.rs | 26 ------------ src/allocator/global.rs | 7 ++++ src/allocator/implementations/base.rs | 51 +++++++++++++++++++++++ src/allocator/implementations/external.rs | 35 ++++++++++++++++ src/allocator/implementations/mod.rs | 6 +++ src/allocator/implementations/native.rs | 35 ++++++++++++++++ src/allocator/mod.rs | 37 ++-------------- src/allocator/vec.rs | 13 ++++++ src/iterators/mod.rs | 3 +- src/iterators/splice.rs | 16 ++++--- src/lib.rs | 10 +++-- 13 files changed, 169 insertions(+), 109 deletions(-) create mode 100644 src/allocator/boxed.rs create mode 100644 src/allocator/global.rs create mode 100644 src/allocator/implementations/base.rs create mode 100644 src/allocator/implementations/external.rs create mode 100644 src/allocator/implementations/mod.rs create mode 100644 src/allocator/implementations/native.rs create mode 100644 src/allocator/vec.rs diff --git a/src/allocator/base.rs b/src/allocator/base.rs index 76ec54e8..8eac6cc7 100644 --- a/src/allocator/base.rs +++ b/src/allocator/base.rs @@ -14,38 +14,3 @@ use { #[derive(Clone)] pub struct Global; -impl Allocator for Global { - #[inline] - fn allocate(&self, layout: Layout) -> Option> { - Some(NonNull::slice_from_raw_parts( - NonNull::new(unsafe { alloc(layout) })?, - layout.size() - )) - } - - #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { dealloc(pointer.as_ptr(), layout) }; - } - - #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - Some(NonNull::slice_from_raw_parts( - NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?, - new.size() - )) - } - - #[inline] - unsafe fn shrink( - &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - Some(NonNull::slice_from_raw_parts( - NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?, - new.size() - )) - } -} diff --git a/src/allocator/boxed.rs b/src/allocator/boxed.rs new file mode 100644 index 00000000..9d27af95 --- /dev/null +++ b/src/allocator/boxed.rs @@ -0,0 +1,4 @@ +#[cfg(not(feature = "allocator-api2"))] +pub use alloc::boxed::Box; +#[cfg(feature = "allocator-api2")] +pub use allocator_api2::boxed::Box; diff --git a/src/allocator/external.rs b/src/allocator/external.rs index 635a8697..4c5bb96b 100644 --- a/src/allocator/external.rs +++ b/src/allocator/external.rs @@ -7,29 +7,3 @@ use { } }; -impl Allocator for Type { - #[inline] - fn allocate(&self, layout: Layout) -> Option> { - External::allocate(&self, layout).ok() - } - - #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { External::deallocate(&self, pointer, layout) } - } - - #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - unsafe { External::grow(&self, pointer, old, new).ok() } - } - - #[inline] - unsafe fn shrink( - &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - unsafe { External::shrink(&self, pointer, old, new).ok() } - } -} diff --git a/src/allocator/global.rs b/src/allocator/global.rs new file mode 100644 index 00000000..403abd76 --- /dev/null +++ b/src/allocator/global.rs @@ -0,0 +1,7 @@ +#[cfg(not(feature = "allocator-api"))] +pub struct Global; + +#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] +pub use alloc::alloc::Global; +#[cfg(feature = "allocator-api2")] +pub use allocator_api2::alloc::Global; diff --git a/src/allocator/implementations/base.rs b/src/allocator/implementations/base.rs new file mode 100644 index 00000000..996586fd --- /dev/null +++ b/src/allocator/implementations/base.rs @@ -0,0 +1,51 @@ +use { + super::super::{ + Allocator, + global::Global + }, + alloc::alloc::{ + alloc, + dealloc, + realloc + }, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + Some(NonNull::slice_from_raw_parts( + NonNull::new(unsafe { alloc(layout) })?, + layout.size() + )) + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { dealloc(pointer.as_ptr(), layout) }; + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + Some(NonNull::slice_from_raw_parts( + NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?, + new.size() + )) + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + Some(NonNull::slice_from_raw_parts( + NonNull::new(unsafe { realloc(pointer.as_ptr(), old, new.size()) })?, + new.size() + )) + } +} diff --git a/src/allocator/implementations/external.rs b/src/allocator/implementations/external.rs new file mode 100644 index 00000000..72083f23 --- /dev/null +++ b/src/allocator/implementations/external.rs @@ -0,0 +1,35 @@ +use { + super::super::Allocator, + allocator_api2::alloc::Allocator as External, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +impl Allocator for Type { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + External::allocate(&self, layout).ok() + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { External::deallocate(&self, pointer, layout) } + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { External::grow(&self, pointer, old, new).ok() } + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { External::shrink(&self, pointer, old, new).ok() } + } +} diff --git a/src/allocator/implementations/mod.rs b/src/allocator/implementations/mod.rs new file mode 100644 index 00000000..59ab2e1e --- /dev/null +++ b/src/allocator/implementations/mod.rs @@ -0,0 +1,6 @@ +#[cfg(not(feature = "allocator-api"))] +mod base; +#[cfg(feature = "allocator-api2")] +mod external; +#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] +mod native; diff --git a/src/allocator/implementations/native.rs b/src/allocator/implementations/native.rs new file mode 100644 index 00000000..70ef0866 --- /dev/null +++ b/src/allocator/implementations/native.rs @@ -0,0 +1,35 @@ +use { + super::super::Allocator, + alloc::alloc::Allocator as Native, + core::{ + alloc::Layout, + ptr::NonNull + } +}; + +impl Allocator for Type { + #[inline] + fn allocate(&self, layout: Layout) -> Option> { + Native::allocate(&self, layout).ok() + } + + #[inline] + unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { + unsafe { Native::deallocate(&self, pointer, layout) } + } + + #[inline] + unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { + unsafe { Native::grow(&self, pointer, old, new).ok() } + } + + #[inline] + unsafe fn shrink( + &self, + pointer: NonNull, + old: Layout, + new: Layout + ) -> Option> { + unsafe { Native::shrink(&self, pointer, old, new).ok() } + } +} diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 5e67a3a8..46927df0 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,43 +1,14 @@ -#[cfg(not(feature = "allocator-api"))] -mod base; -#[cfg(feature = "allocator-api2")] -mod external; -#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] -mod native; +pub mod boxed; +pub mod global; +mod implementations; pub mod proxy; +pub mod vec; use core::{ alloc::Layout, ptr::NonNull }; -#[cfg(not(feature = "allocator-api"))] -#[rustfmt::skip] -pub use { - alloc::{ - boxed::Box, - vec::Vec, - vec - }, - base::Global -}; -#[cfg(feature = "allocator-api2")] -#[rustfmt::skip] -pub use allocator_api2::{ - alloc::Global, - boxed::Box, - vec::Vec, - vec -}; -#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] -#[rustfmt::skip] -pub use alloc::{ - alloc::Global, - boxed::Box, - vec::Vec, - vec -}; - pub trait Allocator { fn allocate(&self, layout: Layout) -> Option>; unsafe fn deallocate(&self, pointer: NonNull, layout: Layout); diff --git a/src/allocator/vec.rs b/src/allocator/vec.rs new file mode 100644 index 00000000..a1181229 --- /dev/null +++ b/src/allocator/vec.rs @@ -0,0 +1,13 @@ +#[cfg(not(feature = "allocator-api2"))] +#[rustfmt::skip] +pub use alloc::{ + vec, + vec::Vec +}; + +#[cfg(feature = "allocator-api2")] +#[rustfmt::skip] +pub use allocator_api2::{ + vec, + vec::Vec +}; diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs index 40585e0c..78953514 100644 --- a/src/iterators/mod.rs +++ b/src/iterators/mod.rs @@ -1,7 +1,6 @@ pub mod drain; pub mod extractif; pub mod intoiter; -pub mod splice; - #[cfg(feature = "rayon")] mod rayon; +pub mod splice; diff --git a/src/iterators/splice.rs b/src/iterators/splice.rs index 0cee6c1c..f827b6f0 100644 --- a/src/iterators/splice.rs +++ b/src/iterators/splice.rs @@ -1,13 +1,11 @@ -use { +use super::{ super::{ - super::{ - Allocator, - Global, - SmallVec, - allocator::proxy::Proxy - }, - drain::Drain - } + Allocator, + Global, + SmallVec, + allocator::proxy::Proxy + }, + drain::Drain }; pub struct Splice<'a, I: Iterator + 'a, const N: usize, A: Allocator = Global> { diff --git a/src/lib.rs b/src/lib.rs index 3e3a624d..4b651d7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,10 +58,12 @@ use std::io; use { allocator::{ Allocator, - Box, - Global, - Vec, - vec + boxed::Box, + global::Global, + vec::{ + Vec, + vec + } }, core::{ alloc::Layout, From 287f323bde2b9007adcff525c5d58ad3a619280e Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 13:03:45 +0200 Subject: [PATCH 07/14] style: reorder --- src/allocator/implementations/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allocator/implementations/mod.rs b/src/allocator/implementations/mod.rs index 59ab2e1e..1eee772e 100644 --- a/src/allocator/implementations/mod.rs +++ b/src/allocator/implementations/mod.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "allocator-api"))] mod base; -#[cfg(feature = "allocator-api2")] -mod external; #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] mod native; +#[cfg(feature = "allocator-api2")] +mod external; \ No newline at end of file From 991aebf8a5d6e16321e976ce2388071d25ae60ad Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 13:06:53 +0200 Subject: [PATCH 08/14] fix: clonable --- src/allocator/base.rs | 16 ---------------- src/allocator/external.rs | 9 --------- src/allocator/global.rs | 2 +- src/allocator/native.rs | 35 ----------------------------------- 4 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 src/allocator/base.rs delete mode 100644 src/allocator/external.rs delete mode 100644 src/allocator/native.rs diff --git a/src/allocator/base.rs b/src/allocator/base.rs deleted file mode 100644 index 8eac6cc7..00000000 --- a/src/allocator/base.rs +++ /dev/null @@ -1,16 +0,0 @@ -use { - super::Allocator, - alloc::alloc::{ - alloc, - dealloc, - realloc - }, - core::{ - alloc::Layout, - ptr::NonNull - } -}; - -#[derive(Clone)] -pub struct Global; - diff --git a/src/allocator/external.rs b/src/allocator/external.rs deleted file mode 100644 index 4c5bb96b..00000000 --- a/src/allocator/external.rs +++ /dev/null @@ -1,9 +0,0 @@ -use { - super::Allocator, - allocator_api2::alloc::Allocator as External, - core::{ - alloc::Layout, - ptr::NonNull - } -}; - diff --git a/src/allocator/global.rs b/src/allocator/global.rs index 403abd76..67af50c6 100644 --- a/src/allocator/global.rs +++ b/src/allocator/global.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "allocator-api"))] +#[derive(Clone)] pub struct Global; - #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] pub use alloc::alloc::Global; #[cfg(feature = "allocator-api2")] diff --git a/src/allocator/native.rs b/src/allocator/native.rs deleted file mode 100644 index 77603616..00000000 --- a/src/allocator/native.rs +++ /dev/null @@ -1,35 +0,0 @@ -use { - super::Allocator, - alloc::alloc::Allocator as Native, - core::{ - alloc::Layout, - ptr::NonNull - } -}; - -impl Allocator for Type { - #[inline] - fn allocate(&self, layout: Layout) -> Option> { - Native::allocate(&self, layout).ok() - } - - #[inline] - unsafe fn deallocate(&self, pointer: NonNull, layout: Layout) { - unsafe { Native::deallocate(&self, pointer, layout) } - } - - #[inline] - unsafe fn grow(&self, pointer: NonNull, old: Layout, new: Layout) -> Option> { - unsafe { Native::grow(&self, pointer, old, new).ok() } - } - - #[inline] - unsafe fn shrink( - &self, - pointer: NonNull, - old: Layout, - new: Layout - ) -> Option> { - unsafe { Native::shrink(&self, pointer, old, new).ok() } - } -} From d86600d0f98674b38b39a52ee38bc388b328c993 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 13:07:39 +0200 Subject: [PATCH 09/14] style: formatting --- src/allocator/implementations/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allocator/implementations/mod.rs b/src/allocator/implementations/mod.rs index 1eee772e..59ab2e1e 100644 --- a/src/allocator/implementations/mod.rs +++ b/src/allocator/implementations/mod.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "allocator-api"))] mod base; +#[cfg(feature = "allocator-api2")] +mod external; #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] mod native; -#[cfg(feature = "allocator-api2")] -mod external; \ No newline at end of file From ee58199e71129aa486eacc61a14375962e9722a8 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 15:48:25 +0200 Subject: [PATCH 10/14] refactor: allocator like trait --- src/allocator/boxed.rs | 26 ++++++++++++++++++++++---- src/allocator/like.rs | 3 +++ src/allocator/mod.rs | 2 ++ src/allocator/requirement.rs | 6 ++++++ src/allocator/vec.rs | 33 +++++++++++++++++++++++---------- src/conversions.rs | 21 +++++++++++---------- src/lib.rs | 16 ++++++++++------ src/rawsmallvec.rs | 7 +++---- 8 files changed, 80 insertions(+), 34 deletions(-) create mode 100644 src/allocator/like.rs create mode 100644 src/allocator/requirement.rs diff --git a/src/allocator/boxed.rs b/src/allocator/boxed.rs index 9d27af95..89c8773a 100644 --- a/src/allocator/boxed.rs +++ b/src/allocator/boxed.rs @@ -1,4 +1,22 @@ -#[cfg(not(feature = "allocator-api2"))] -pub use alloc::boxed::Box; -#[cfg(feature = "allocator-api2")] -pub use allocator_api2::boxed::Box; +use { + super::{ + Allocator, + like::Like, + requirement::Requirement + }, + core::{ + convert::Infallible, + marker::PhantomData + } +}; + +pub struct Box(Infallible, PhantomData<(Heap, Item)>); + +impl Like for Box { + #[cfg(not(feature = "allocator-api"))] + type Type = alloc::boxed::Box; + #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] + type Type = alloc::boxed::Box; + #[cfg(feature = "allocator-api2")] + type Type = allocator_api2::boxed::Box; +} diff --git a/src/allocator/like.rs b/src/allocator/like.rs new file mode 100644 index 00000000..593bdbef --- /dev/null +++ b/src/allocator/like.rs @@ -0,0 +1,3 @@ +pub trait Like { + type Type; +} diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 46927df0..074f7190 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,7 +1,9 @@ pub mod boxed; pub mod global; mod implementations; +pub mod like; pub mod proxy; +mod requirement; pub mod vec; use core::{ diff --git a/src/allocator/requirement.rs b/src/allocator/requirement.rs new file mode 100644 index 00000000..23529e2c --- /dev/null +++ b/src/allocator/requirement.rs @@ -0,0 +1,6 @@ +#[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] +pub use alloc::alloc::Allocator as Requirement; +#[cfg(feature = "allocator-api2")] +pub use allocator_api2::alloc::Allocator as Requirement; +#[cfg(not(feature = "allocator-api"))] +pub use core::marker::Sized as Requirement; diff --git a/src/allocator/vec.rs b/src/allocator/vec.rs index a1181229..88e79603 100644 --- a/src/allocator/vec.rs +++ b/src/allocator/vec.rs @@ -1,13 +1,26 @@ #[cfg(not(feature = "allocator-api2"))] -#[rustfmt::skip] -pub use alloc::{ - vec, - vec::Vec -}; - +pub use alloc::vec; #[cfg(feature = "allocator-api2")] -#[rustfmt::skip] -pub use allocator_api2::{ - vec, - vec::Vec +pub use allocator_api2::vec; +use { + super::{ + Allocator, + like::Like, + requirement::Requirement + }, + core::{ + convert::Infallible, + marker::PhantomData + } }; + +pub struct Vec(Infallible, PhantomData<(Heap, Item)>); + +impl Like for Vec { + #[cfg(not(feature = "allocator-api"))] + type Type = alloc::vec::Vec; + #[cfg(all(feature = "allocator-api", not(feature = "allocator-api2")))] + type Type = alloc::vec::Vec; + #[cfg(feature = "allocator-api2")] + type Type = allocator_api2::vec::Vec; +} diff --git a/src/conversions.rs b/src/conversions.rs index 13cde585..4f60800a 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -4,7 +4,8 @@ use { Box, Global, SmallVec, - Vec + Vec, + allocator::like::Like }, core::{ mem::ManuallyDrop, @@ -17,7 +18,7 @@ impl From<&[T]> for SmallVec { fn from(slice: &[T]) -> Self { if slice.len() > Self::inline_size() { // Standard Rust vectors are already specialized. - Self::from_vec(Vec::from(slice)) + Self::from_vec( as Like>::Type::from(slice)) } else { // SAFETY: The precondition is checked in the initial comparison // above. @@ -62,7 +63,7 @@ impl From<[T; M]> for SmallVec if M > N { // If M > N, we'd have to heap allocate anyway, // so delegate for Vec for the allocation. - Self::from(Vec::from(array)) + Self::from( as Like>::Type::from(array)) } else { // M <= N let mut this = Self::new(); @@ -97,17 +98,17 @@ impl TryFrom> } } -impl From> for SmallVec { - fn from(array: Vec) -> Self { +impl From< as Like>::Type> for SmallVec { + fn from(array: as Like>::Type) -> Self { Self::from_vec(array) } } -impl From> for Vec { +impl From> for as Like>::Type { fn from(this: SmallVec) -> Self { let (length, on_heap) = this.length.parts(); if !on_heap { - let mut vec = Vec::with_capacity(length); + let mut vec = as Like>::Type::with_capacity(length); let this = ManuallyDrop::new(this); // SAFETY: we create a new vector with sufficient capacity, copy our // elements into it to transfer ownership and then set @@ -129,14 +130,14 @@ impl From> for Vec { // - the allocation is not larger than `isize::MAX` unsafe { let (ptr, cap) = this.raw.heap; - Vec::from_raw_parts(ptr.as_ptr(), length, cap) + as Like>::Type::from_raw_parts(ptr.as_ptr(), length, cap) } } } } -impl From> for Box<[T]> { +impl From> for as Like>::Type { fn from(this: SmallVec) -> Self { - Vec::from(this).into_boxed_slice() + as Like>::Type::from(this).into_boxed_slice() } } diff --git a/src/lib.rs b/src/lib.rs index e487ac98..cb4c3ff7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,7 @@ use { Allocator, boxed::Box, global::Global, + like::Like, vec::{ Vec, vec @@ -222,7 +223,7 @@ impl SmallVec { } #[inline] - pub fn from_vec(vec: Vec) -> Self { + pub fn from_vec(vec: as Like>::Type) -> Self { if vec.capacity() == 0 { return Self::new(); } @@ -759,7 +760,8 @@ impl SmallVec { let (ptr, capacity) = self.raw.heap; copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), length); self.length.set_location::(); - self.allocator.deallocate( + Allocator::deallocate( + &self.allocator, ptr.cast(), Layout::from_size_align_unchecked(capacity * size_of::(), align_of::()) ); @@ -793,7 +795,8 @@ impl SmallVec { let (ptr, capacity) = self.raw.heap; copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), length); self.length.set_location::(); - self.allocator.deallocate( + Allocator::deallocate( + &self.allocator, ptr.cast(), Layout::from_size_align_unchecked( capacity * size_of::(), @@ -982,13 +985,13 @@ impl SmallVec { #[inline] #[deprecated(since = "2.0.0", note = "use `Into::>::into` instead")] - pub fn into_vec(self) -> Vec { + pub fn into_vec(self) -> as Like>::Type { self.into() } #[inline] #[deprecated(since = "2.0.0", note = "use `Into::>::into` instead")] - pub fn into_boxed_slice(self) -> Box<[T]> { + pub fn into_boxed_slice(self) -> as Like>::Type { self.into() } @@ -1468,7 +1471,8 @@ impl Drop for DropDealloc<'_, A> { fn drop(&mut self) { unsafe { if self.size_bytes > 0 { - self.allocator.deallocate( + Allocator::deallocate( + self.allocator, self.ptr, Layout::from_size_align_unchecked(self.size_bytes, self.align) ); diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 0330bc2e..45f21aab 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -126,8 +126,7 @@ impl RawSmallVec { let new_ptr = if !was_on_heap { // get a fresh allocation // `new_layout` has nonzero size. - let new_ptr = allocator - .allocate(new_layout) + let new_ptr = Allocator::allocate(allocator, new_layout) .ok_or(SmallVecError::AllocationError(new_layout))? .cast(); unsafe { copy_nonoverlapping(ptr, new_ptr.as_ptr(), length) }; @@ -149,9 +148,9 @@ impl RawSmallVec { // with Layout::array unsafe { (if self.heap.1 < new_capacity { - A::grow + ::grow } else { - A::shrink + ::shrink })( allocator, NonNull::new(ptr as *mut u8).unwrap(), From a940350d692e99f14ebbe4f60ae5777b8743459d Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 6 Oct 2026 17:57:15 +0200 Subject: [PATCH 11/14] refactor: remove infallible --- src/allocator/boxed.rs | 7 ++----- src/allocator/vec.rs | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/allocator/boxed.rs b/src/allocator/boxed.rs index 89c8773a..7fa4cf9a 100644 --- a/src/allocator/boxed.rs +++ b/src/allocator/boxed.rs @@ -4,13 +4,10 @@ use { like::Like, requirement::Requirement }, - core::{ - convert::Infallible, - marker::PhantomData - } + core::marker::PhantomData }; -pub struct Box(Infallible, PhantomData<(Heap, Item)>); +pub struct Box(PhantomData<(Heap, Item)>); impl Like for Box { #[cfg(not(feature = "allocator-api"))] diff --git a/src/allocator/vec.rs b/src/allocator/vec.rs index 88e79603..a7801449 100644 --- a/src/allocator/vec.rs +++ b/src/allocator/vec.rs @@ -8,13 +8,10 @@ use { like::Like, requirement::Requirement }, - core::{ - convert::Infallible, - marker::PhantomData - } + core::marker::PhantomData }; -pub struct Vec(Infallible, PhantomData<(Heap, Item)>); +pub struct Vec(PhantomData<(Heap, Item)>); impl Like for Vec { #[cfg(not(feature = "allocator-api"))] From bd2428df510d7d4ea32fee3b8af351ea4078ae60 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 14 Oct 2026 15:10:24 +0200 Subject: [PATCH 12/14] fix: errors --- src/conversions.rs | 74 +++++++++++++++++++++++++++++++++++++++------- src/lib.rs | 43 +-------------------------- src/rawsmallvec.rs | 4 +-- tests/main.rs | 14 ++++----- 4 files changed, 73 insertions(+), 62 deletions(-) diff --git a/src/conversions.rs b/src/conversions.rs index b036c50a..3aaaad0f 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -5,11 +5,16 @@ use { Global, SmallVec, Vec, - allocator::like::Like + allocator::like::Like, + LocatedLength, + RawSmallVec }, core::{ mem::ManuallyDrop, - ptr::copy_nonoverlapping + ptr::{ + copy_nonoverlapping, + NonNull + } } }; @@ -67,7 +72,7 @@ impl From<[Item; M]> for SmallVec INLINE { // If M > INLINE, we'd have to heap allocate anyway, // so delegate for Vec for the allocation. - Self::from( as Like>::Type::from(array)) + Self::from( as Like>::Type::from(array)) } else { // M <= INLINE let mut this = Self::new(); @@ -106,17 +111,62 @@ impl } } -impl From< as Like>::Type> for SmallVec { +impl From< as Like>::Type> + for SmallVec +{ fn from(array: as Like>::Type) -> Self { - Self::from_vec(array) + if array.capacity() == 0 { + return Self::new(); + } + + if Self::IS_ZST { + // "Move" elements to stack buffer. They're ZST so we don't actually + // have to do anything. Just make sure they're not + // dropped. We don't wrap the vector in ManuallyDrop so + // that when it's dropped, the memory is deallocated, if + // it needs to be. + let mut vec = array; + let length = vec.len(); + + // SAFETY: `0` is less than the vector's capacity. + // old_len..new_len is an empty range. So there are no uninitialized + // elements + unsafe { vec.set_len(0) }; + Self { + length: LocatedLength::new(length, false), + raw: RawSmallVec::new(), + allocator: Global + } + } else { + let mut vec = ManuallyDrop::new(array); + let length = vec.len(); + + // A heap-allocated `SmallVec` must always observe the invariant + // that `cap > INLINE`. + if vec.capacity() <= INLINE { + vec.reserve(INLINE + 1 - length); + } + let cap = vec.capacity(); + // SAFETY: vec.capacity is not `0` (checked above), so the pointer + // can not dangle and thus specifically cannot be null. + let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; + + Self { + length: LocatedLength::new(length, true), + raw: RawSmallVec::new_heap(ptr, cap), + allocator: Global + } + } } } -impl From> for as Like>::Type { +impl From> + for as Like>::Type +{ fn from(this: SmallVec) -> Self { let (length, on_heap) = this.length.parts(); if !on_heap { - let mut vec = as Like>::Type::with_capacity(length); + let mut vec = as Like>::Type::with_capacity(length); let this = ManuallyDrop::new(this); // SAFETY: we create a new vector with sufficient capacity, copy our // elements into it to transfer ownership and then set @@ -138,20 +188,22 @@ impl From as Like>::Type::from_raw_parts(ptr.as_ptr(), length, cap) + as Like>::Type::from_raw_parts(ptr.as_ptr(), length, cap) } } } } -impl From> for as Like>::Type { +impl From> + for as Like>::Type +{ fn from(this: SmallVec) -> Self { as Like>::Type::from(this).into_boxed_slice() } } -impl From> for SmallVec { - fn from(boxed: Box<[T]>) -> Self { +impl From< as Like>::Type> for SmallVec { + fn from(boxed: as Like>::Type) -> Self { boxed.into_vec().into() } } diff --git a/src/lib.rs b/src/lib.rs index 169d73b5..0dae9e38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,48 +233,7 @@ impl SmallVec { #[inline] #[deprecated(since = "2.0.0-beta.3", note = "use `From::>::from` instead")] pub fn from_vec(vec: as Like>::Type) -> Self { - if vec.capacity() == 0 { - return Self::new(); - } - - if Self::IS_ZST { - // "Move" elements to stack buffer. They're ZST so we don't actually - // have to do anything. Just make sure they're not - // dropped. We don't wrap the vector in ManuallyDrop so - // that when it's dropped, the memory is deallocated, if - // it needs to be. - let mut vec = vec; - let length = vec.len(); - - // SAFETY: `0` is less than the vector's capacity. - // old_len..new_len is an empty range. So there are no uninitialized - // elements - unsafe { vec.set_len(0) }; - Self { - length: LocatedLength::new(length, false), - raw: RawSmallVec::new(), - allocator: Global - } - } else { - let mut vec = ManuallyDrop::new(vec); - let length = vec.len(); - - // A heap-allocated `SmallVec` must always observe the invariant - // that `cap > INLINE`. - if vec.capacity() <= INLINE { - vec.reserve(INLINE + 1 - length); - } - let cap = vec.capacity(); - // SAFETY: vec.capacity is not `0` (checked above), so the pointer - // can not dangle and thus specifically cannot be null. - let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; - - Self { - length: LocatedLength::new(length, true), - raw: RawSmallVec::new_heap(ptr, cap), - allocator: Global - } - } + vec.into() } /// Creates a `SmallVec` directly from the raw components of another diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index ed7cba0b..90c593cb 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -151,9 +151,9 @@ impl RawSmallVec { // with Layout::array unsafe { (if self.heap.1 < new_capacity { - ::grow + ::grow } else { - ::shrink + ::shrink })( allocator, NonNull::new(ptr as *mut u8).unwrap(), diff --git a/tests/main.rs b/tests/main.rs index 22ecfb9f..7e6462d7 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -766,7 +766,7 @@ fn shrink_to_fit_unspill() { #[test] fn shrink_after_from_empty_vec() { - let mut v = SmallVec::::from_vec(Vec::new()); + let mut v = SmallVec::::from(Vec::new()); v.shrink_to_fit(); assert!(!v.spilled()) } @@ -835,32 +835,32 @@ fn try_into_array() { #[test] fn from_vec() { let vec = Vec::new(); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); let vec = Vec::new(); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[0u8; 0]); drop(small_vec); let vec = Vec::from([1]); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1]); drop(small_vec); let vec = Vec::from([1, 2, 3]); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3]); drop(small_vec); let vec = Vec::from([1, 2, 3, 4, 5]); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); let vec = Vec::from([1, 2, 3, 4, 5]); - let small_vec: SmallVec = SmallVec::from_vec(vec); + let small_vec: SmallVec = SmallVec::from(vec); assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); drop(small_vec); } From 97f44c21ab809b5676fa9bfb9de9357603672efb Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 14 Oct 2026 15:19:56 +0200 Subject: [PATCH 13/14] style: formatting --- src/conversions.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/conversions.rs b/src/conversions.rs index 3aaaad0f..672b95da 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -3,17 +3,17 @@ use { Allocator, Box, Global, + LocatedLength, + RawSmallVec, SmallVec, Vec, - allocator::like::Like, - LocatedLength, - RawSmallVec + allocator::like::Like }, core::{ mem::ManuallyDrop, ptr::{ - copy_nonoverlapping, - NonNull + NonNull, + copy_nonoverlapping } } }; From ba0760d691dfdb8b47bab9e0b608f6d6fc1f2322 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Wed, 14 Oct 2026 15:24:21 +0200 Subject: [PATCH 14/14] fix: remove warning --- fuzz/fuzz_targets/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/main.rs b/fuzz/fuzz_targets/main.rs index 71fb83c9..9d60676f 100644 --- a/fuzz/fuzz_targets/main.rs +++ b/fuzz/fuzz_targets/main.rs @@ -162,7 +162,7 @@ fn test_with_inline_cap( std_vec = Vec::with_capacity(cap.0); } Op::FromVec => { - small_vec = SmallVec::from_vec(small_vec.into()); + small_vec = SmallVec::from(Into::>::into(small_vec)); // No-op on `Vec` } Op::FromSlice(data) => {