From d5012c8fcc8a5225964d4f41989c9c5f5dd70a5c Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Fri, 28 Aug 2026 20:07:35 +0200 Subject: [PATCH 1/2] Add `SmallVec::into_raw_parts` --- src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index c54900a..8603d7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1821,6 +1821,67 @@ impl SmallVec { _marker: PhantomData } } + + /// Decomposes a `SmallVec` into its raw components: `(pointer, + /// length, capacity)`. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `SmallVec`. Most often, one does + /// this by converting the raw pointer, length, and capacity back + /// into a `SmallVec` with the [`from_raw_parts`] function; more generally, + /// if `T` is non-zero-sized and the capacity is nonzero, one may use + /// any method that calls [`dealloc`] with a layout of + /// `Layout::array::(capacity)`; if `T` is zero-sized or the + /// capacity is zero, nothing needs to be done. + /// + /// [`from_raw_parts`]: SmallVec::from_raw_parts + /// [`dealloc`]: alloc::alloc::GlobalAlloc::dealloc + /// + /// # Panics + /// + /// This function will panic if the contents are not spilled on the heap. + /// + /// # Examples + /// + /// ``` + /// # use smallvec::SmallVec; + /// + /// let v: SmallVec = SmallVec::from([-1, 0, 1]); + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// SmallVec::::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[inline] + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + #[cold] + #[inline(never)] + #[track_caller] + fn assert_failed() -> ! { + panic!( + "SmallVec::into_raw_parts() called on inline (stack) SmallVec, \ + which cannot be safely leaked" + ); + } + if !self.spilled() { + assert_failed(); + } + + let mut me = ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } } impl SmallVec { From b999bc594c2b3550c3e37adeb179e57fbe78978b Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Mon, 7 Sep 2026 21:27:20 +0200 Subject: [PATCH 2/2] Add tests for `SmallVec::into_raw_parts` --- tests/main.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/main.rs b/tests/main.rs index 2bd6ff8..b8ab7cf 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -704,6 +704,25 @@ fn shrink_after_from_empty_vec() { assert!(!v.spilled()) } +#[test] +#[should_panic] +fn into_raw_parts_inline() { + let v: SmallVec = SmallVec::from([1, 2, 3]); + v.into_raw_parts(); +} + +#[test] +fn into_raw_parts_heap() { + let v: SmallVec = SmallVec::from([1, 2, 3]); + let (ptr, length, capacity) = v.into_raw_parts(); + + // It should be safe to create a standard `Vec` from the result. + // SAFETY: allocated using `Global`, no changes to the element type. + unsafe { + Vec::from_raw_parts(ptr, length, capacity); + } +} + #[test] fn into_vec() { let vec = SmallVec::::from_iter(0..2);