@@ -80,7 +80,7 @@ use core::hash::{Hash, Hasher};
8080#[ cfg( not( no_global_oom_handling) ) ]
8181use core:: iter;
8282use core:: marker:: PhantomData ;
83- use core:: mem:: { self , ManuallyDrop , MaybeUninit , SizedTypeProperties } ;
83+ use core:: mem:: { self , Assume , ManuallyDrop , MaybeUninit , SizedTypeProperties , TransmuteFrom } ;
8484use core:: ops:: { self , Index , IndexMut , Range , RangeBounds } ;
8585use core:: ptr:: { self , NonNull } ;
8686use core:: slice:: { self , SliceIndex } ;
@@ -3259,6 +3259,66 @@ 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+ // FIXME(transmutability)
3282+ /// ```ignore (https://github.com/rust-lang/rust/issues/148227#issuecomment-3478099591)
3283+ /// #![feature(vec_recycle)]
3284+ /// # let inputs = ["a b c", "d e f"];
3285+ /// # fn process(_: &[&str]) {}
3286+ /// let mut storage: Vec<&[&str]> = Vec::new();
3287+ ///
3288+ /// for input in inputs {
3289+ /// let mut buffer: Vec<&str> = storage.recycle();
3290+ /// buffer.extend(input.split(" "));
3291+ /// process(&buffer);
3292+ /// storage = buffer.recycle();
3293+ /// }
3294+ /// ```
3295+ #[ unstable( feature = "vec_recycle" , issue = "148227" ) ]
3296+ #[ expect( private_bounds) ]
3297+ pub fn recycle < U > ( mut self ) -> Vec < U , A >
3298+ where
3299+ U : Recyclable < T > ,
3300+ {
3301+ self . clear ( ) ;
3302+ const {
3303+ assert ! ( size_of:: <T >( ) == size_of:: <U >( ) ) ;
3304+ assert ! ( align_of:: <T >( ) >= align_of:: <U >( ) ) ;
3305+ } ;
3306+ let ( ptr, length, capacity, alloc) = self . into_parts_with_alloc ( ) ;
3307+ debug_assert_eq ! ( length, 0 ) ;
3308+ // SAFETY:
3309+ // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3310+ // - `T` & `U` have the same size (so `capacity` is valid) & alignment (so `ptr` is valid)
3311+ // - the original vector was cleared, so there is no problem with "transmuting" the stored values
3312+ unsafe { Vec :: from_parts_in ( ptr. cast :: < U > ( ) , length, capacity, alloc) }
3313+ }
3314+ }
3315+
3316+ trait Recyclable < From > : Sized { }
3317+
3318+ #[ unstable_feature_bound( transmutability) ]
3319+ impl < From , To > Recyclable < From > for To where
3320+ for < ' a > & ' a MaybeUninit < To > : TransmuteFrom < & ' a MaybeUninit < From > , { Assume :: SAFETY } >
3321+ {
32623322}
32633323
32643324impl < T : Clone , A : Allocator > Vec < T , A > {
0 commit comments