Skip to content

Commit 9eb5e67

Browse files
committed
vec_recycle: implementation
1 parent 6a884ad commit 9eb5e67

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
#![feature(std_internals)]
145145
#![feature(str_internals)]
146146
#![feature(temporary_niche_types)]
147+
#![feature(transmutability)]
147148
#![feature(trusted_fused)]
148149
#![feature(trusted_len)]
149150
#![feature(trusted_random_access)]

library/alloc/src/vec/mod.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ use core::hash::{Hash, Hasher};
8080
#[cfg(not(no_global_oom_handling))]
8181
use core::iter;
8282
use core::marker::PhantomData;
83-
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
83+
use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom};
8484
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
8585
use core::ptr::{self, NonNull};
8686
use core::slice::{self, SliceIndex};
@@ -3259,6 +3259,65 @@ impl<T, A: Allocator> Vec<T, A> {
32593259
// - `cap / N` fits the size of the allocated memory after shrinking
32603260
unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) }
32613261
}
3262+
3263+
/// This clears out this `Vec` and recycles the allocation into a new `Vec`.
3264+
/// The item type of the resulting `Vec` needs to have the same size and
3265+
/// alignment as the item type of the original `Vec`.
3266+
///
3267+
/// # Examples
3268+
///
3269+
/// ```
3270+
/// #![feature(vec_recycle)]
3271+
/// #![feature(transmutability)]
3272+
/// let a: Vec<u8> = vec![0; 100];
3273+
/// let capacity = a.capacity();
3274+
/// let addr = a.as_ptr().addr();
3275+
/// let b: Vec<i8> = a.recycle();
3276+
/// assert_eq!(b.len(), 0);
3277+
/// assert_eq!(b.capacity(), capacity);
3278+
/// assert_eq!(b.as_ptr().addr(), addr);
3279+
/// ```
3280+
///
3281+
/// ```ignore // FIXME(transmutability): https://github.com/rust-lang/rust/issues/148227#issuecomment-3478099591
3282+
/// #![feature(vec_recycle)]
3283+
/// # let inputs = ["a b c", "d e f"];
3284+
/// # fn process(_: &[&str]) {}
3285+
/// let mut storage: Vec<&[&str]> = Vec::new();
3286+
///
3287+
/// for input in inputs {
3288+
/// let mut buffer: Vec<&str> = storage.recycle();
3289+
/// buffer.extend(input.split(" "));
3290+
/// process(&buffer);
3291+
/// storage = buffer.recycle();
3292+
/// }
3293+
/// ```
3294+
#[unstable(feature = "vec_recycle", issue = "148227")]
3295+
#[expect(private_bounds)]
3296+
pub fn recycle<U>(mut self) -> Vec<U, A>
3297+
where
3298+
U: Recyclable<T>,
3299+
{
3300+
self.clear();
3301+
const {
3302+
assert!(size_of::<T>() == size_of::<U>());
3303+
assert!(align_of::<T>() >= align_of::<U>());
3304+
};
3305+
let (ptr, length, capacity, alloc) = self.into_parts_with_alloc();
3306+
debug_assert_eq!(length, 0);
3307+
// SAFETY:
3308+
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3309+
// - `T` & `U` have the same size (so `capacity` is valid) & alignment (so `ptr` is valid)
3310+
// - the original vector was cleared, so there is no problem with "transmuting" the stored values
3311+
unsafe { Vec::from_parts_in(ptr.cast::<U>(), length, capacity, alloc) }
3312+
}
3313+
}
3314+
3315+
trait Recyclable<From>: Sized {}
3316+
3317+
#[unstable_feature_bound(transmutability)]
3318+
impl<From, To> Recyclable<From> for To where
3319+
for<'a> &'a MaybeUninit<To>: TransmuteFrom<&'a MaybeUninit<From>, { Assume::SAFETY }>
3320+
{
32623321
}
32633322

32643323
impl<T: Clone, A: Allocator> Vec<T, A> {

0 commit comments

Comments
 (0)