@@ -82,7 +82,7 @@ use core::hash::{Hash, Hasher};
8282#[ cfg( not( no_global_oom_handling) ) ]
8383use core:: iter;
8484use core:: marker:: PhantomData ;
85- use core:: mem:: { self , ManuallyDrop , MaybeUninit , SizedTypeProperties } ;
85+ use core:: mem:: { self , Assume , ManuallyDrop , MaybeUninit , SizedTypeProperties , TransmuteFrom } ;
8686use core:: ops:: { self , Index , IndexMut , Range , RangeBounds } ;
8787use core:: ptr:: { self , NonNull } ;
8888use core:: slice:: { self , SliceIndex } ;
@@ -3243,6 +3243,92 @@ impl<T, A: Allocator> Vec<T, A> {
32433243 // - `cap / N` fits the size of the allocated memory after shrinking
32443244 unsafe { Vec :: from_raw_parts_in ( ptr. cast ( ) , len / N , cap / N , alloc) }
32453245 }
3246+
3247+ /// This clears out this `Vec` and recycles the allocation into a new `Vec`.
3248+ /// The item type of the resulting `Vec` needs to have the same size and
3249+ /// alignment as the item type of the original `Vec`.
3250+ ///
3251+ /// # Examples
3252+ ///
3253+ /// ```
3254+ /// #![feature(vec_recycle, transmutability)]
3255+ /// let a: Vec<u8> = vec![0; 100];
3256+ /// let capacity = a.capacity();
3257+ /// let addr = a.as_ptr().addr();
3258+ /// let b: Vec<i8> = a.recycle();
3259+ /// assert_eq!(b.len(), 0);
3260+ /// assert_eq!(b.capacity(), capacity);
3261+ /// assert_eq!(b.as_ptr().addr(), addr);
3262+ /// ```
3263+ ///
3264+ /// The `Recyclable` bound prevents this method from being called when `T` and `U` have different sizes; e.g.:
3265+ ///
3266+ /// ```compile_fail,E0277
3267+ /// #![feature(vec_recycle, transmutability)]
3268+ /// let vec: Vec<[u8; 2]> = Vec::new();
3269+ /// let _: Vec<[u8; 1]> = vec.recycle();
3270+ /// ```
3271+ /// ...or different alignments:
3272+ ///
3273+ /// ```compile_fail,E0277
3274+ /// #![feature(vec_recycle, transmutability)]
3275+ /// let vec: Vec<[u16; 0]> = Vec::new();
3276+ /// let _: Vec<[u8; 0]> = vec.recycle();
3277+ /// ```
3278+ ///
3279+ /// However, due to temporary implementation limitations of `Recyclable`,
3280+ /// this method is not yet callable when `T` or `U` are slices, trait objects,
3281+ /// or other exotic types; e.g.:
3282+ ///
3283+ /// ```compile_fail,E0277
3284+ /// #![feature(vec_recycle, transmutability)]
3285+ /// # let inputs = ["a b c", "d e f"];
3286+ /// # fn process(_: &[&str]) {}
3287+ /// let mut storage: Vec<&[&str]> = Vec::new();
3288+ ///
3289+ /// for input in inputs {
3290+ /// let mut buffer: Vec<&str> = storage.recycle();
3291+ /// buffer.extend(input.split(" "));
3292+ /// process(&buffer);
3293+ /// storage = buffer.recycle();
3294+ /// }
3295+ /// ```
3296+ #[ unstable( feature = "vec_recycle" , issue = "148227" ) ]
3297+ #[ expect( private_bounds) ]
3298+ pub fn recycle < U > ( mut self ) -> Vec < U , A >
3299+ where
3300+ U : Recyclable < T > ,
3301+ {
3302+ self . clear ( ) ;
3303+ const {
3304+ // FIXME(const-hack, 146097): compare `Layout`s
3305+ assert ! ( size_of:: <T >( ) == size_of:: <U >( ) ) ;
3306+ assert ! ( align_of:: <T >( ) == align_of:: <U >( ) ) ;
3307+ } ;
3308+ let ( ptr, length, capacity, alloc) = self . into_parts_with_alloc ( ) ;
3309+ debug_assert_eq ! ( length, 0 ) ;
3310+ // SAFETY:
3311+ // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3312+ // - `T` & `U` have the same layout, so `capacity` does not need to be changed and we can safely use `alloc.dealloc` later
3313+ // - the original vector was cleared, so there is no problem with "transmuting" the stored values
3314+ unsafe { Vec :: from_parts_in ( ptr. cast :: < U > ( ) , length, capacity, alloc) }
3315+ }
3316+ }
3317+
3318+ /// Denotes that an allocation of `From` can be recycled into an allocation of `Self`.
3319+ ///
3320+ /// # Safety
3321+ ///
3322+ /// `Self` is `Recyclable<From>` if `Layout::new::<Self>() == Layout::new::<From>()`.
3323+ unsafe trait Recyclable < From : Sized > : Sized { }
3324+
3325+ #[ unstable_feature_bound( transmutability) ]
3326+ // SAFETY: enforced by `TransmuteFrom`
3327+ unsafe impl < From , To > Recyclable < From > for To
3328+ where
3329+ for < ' a > & ' a MaybeUninit < To > : TransmuteFrom < & ' a MaybeUninit < From > , { Assume :: SAFETY } > ,
3330+ for < ' a > & ' a MaybeUninit < From > : TransmuteFrom < & ' a MaybeUninit < To > , { Assume :: SAFETY } > ,
3331+ {
32463332}
32473333
32483334impl < T : Clone , A : Allocator > Vec < T , A > {
0 commit comments