@@ -7,6 +7,7 @@ use std::{
77 fmt:: { self , Debug , Display , Formatter } ,
88 hash:: { Hash , Hasher } ,
99 marker:: PhantomData ,
10+ mem,
1011 ops:: { Deref , DerefMut } ,
1112 ptr:: { self , NonNull } ,
1213} ;
@@ -149,20 +150,77 @@ impl<T: ?Sized> Box<'_, T> {
149150 }
150151}
151152
153+ impl < T > Box < ' static , [ T ] > {
154+ /// Create a new empty `Box<[T]>`.
155+ ///
156+ /// This method does not allocate. The returned boxed slice is represented by a dangling,
157+ /// correctly-aligned pointer with length 0, similar to how `Vec::new_in` produces an empty vector.
158+ #[ inline]
159+ pub fn new_empty_boxed_slice ( ) -> Self {
160+ const { Self :: ASSERT_T_IS_NOT_DROP } ;
161+
162+ // `NonNull::<T>::dangling()` yields a non-null, properly aligned pointer.
163+ // We pair it with length 0 to construct a `NonNull<[T]>` representing an empty slice.
164+ // Correct alignment is the only requirement for it to be sound to dereference this pointer
165+ // to a slice, because the slice is empty.
166+ // See: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
167+ let ptr = NonNull :: dangling ( ) ;
168+ let slice_ptr = NonNull :: slice_from_raw_parts ( ptr, 0 ) ;
169+
170+ Self ( slice_ptr, PhantomData )
171+ }
172+ }
173+
174+ impl < ' a , T > Box < ' a , [ T ] > {
175+ /// Convert a boxed slice [`Box<[T]>`] into slice [`&'a [T]`].
176+ ///
177+ /// The returned slice has the same lifetime as the allocator.
178+ //
179+ // `#[inline(always)]` because this is a no-op. `Box<[T]>` and `&[T]` have the same layout.
180+ #[ expect( clippy:: inline_always) ]
181+ #[ inline( always) ]
182+ pub fn into_bump_slice ( self ) -> & ' a [ T ] {
183+ let r = self . as_ref ( ) ;
184+ // Extend lifetime of reference to lifetime of the allocator.
185+ // SAFETY: `self` is consumed by this method, so there cannot be any mutable references to it.
186+ // The reference lives until the allocator is dropped or reset (`'a` lifetime).
187+ // Don't need `mem::forget(self)` here, because `Box` does not implement `Drop`.
188+ unsafe { mem:: transmute :: < & [ T ] , & ' a [ T ] > ( r) }
189+ }
190+
191+ /// Convert a boxed slice [`Box<[T]>`] into mutable slice [`&'a mut [T]`].
192+ ///
193+ /// The returned slice has the same lifetime as the allocator.
194+ //
195+ // `#[inline(always)]` because this is a no-op. `Box<[T]>` and `&mut [T]` have the same layout.
196+ #[ expect( clippy:: inline_always) ]
197+ #[ inline( always) ]
198+ pub fn into_bump_slice_mut ( mut self ) -> & ' a mut [ T ] {
199+ let r = self . as_mut ( ) ;
200+ // Extend lifetime of reference to lifetime of the allocator.
201+ // SAFETY: `self` is consumed by this method, so there cannot be any other references to it.
202+ // The reference lives until the allocator is dropped or reset (`'a` lifetime).
203+ // Don't need `mem::forget(self)` here, because `Box` does not implement `Drop`.
204+ unsafe { mem:: transmute :: < & mut [ T ] , & ' a mut [ T ] > ( r) }
205+ }
206+ }
207+
152208impl < T : ?Sized > Deref for Box < ' _ , T > {
153209 type Target = T ;
154210
155211 #[ inline]
156212 fn deref ( & self ) -> & T {
157- // SAFETY: self.0 is always a unique reference allocated from a Bump in Box::new_in
213+ // SAFETY: `self.0` is always a unique reference allocated from a `Bump` in `Box::new_in`,
214+ // or an empty slice allocated from `Box::new_empty_boxed_slice`
158215 unsafe { self . 0 . as_ref ( ) }
159216 }
160217}
161218
162219impl < T : ?Sized > DerefMut for Box < ' _ , T > {
163220 #[ inline]
164221 fn deref_mut ( & mut self ) -> & mut T {
165- // SAFETY: self.0 is always a unique reference allocated from a Bump in Box::new_in
222+ // SAFETY: `self.0` is always a unique reference allocated from a `Bump` in `Box::new_in`,
223+ // or an empty slice allocated from `Box::new_empty_boxed_slice`
166224 unsafe { self . 0 . as_mut ( ) }
167225 }
168226}
@@ -230,8 +288,9 @@ impl<T: Hash> Hash for Box<'_, T> {
230288mod test {
231289 use std:: hash:: { DefaultHasher , Hash , Hasher } ;
232290
291+ use crate :: { Allocator , Vec } ;
292+
233293 use super :: Box ;
234- use crate :: Allocator ;
235294
236295 #[ test]
237296 fn box_deref_mut ( ) {
@@ -242,6 +301,33 @@ mod test {
242301 assert_eq ! ( * b, "v" ) ;
243302 }
244303
304+ #[ test]
305+ fn new_empty_boxed_slice ( ) {
306+ let b = Box :: < [ u32 ] > :: new_empty_boxed_slice ( ) ;
307+ assert ! ( b. is_empty( ) ) ;
308+ assert_eq ! ( b. len( ) , 0 ) ;
309+ assert_eq ! ( & * b, & [ ] as & [ u32 ] ) ;
310+ }
311+
312+ #[ test]
313+ fn boxed_slice_into_bump_slice ( ) {
314+ let allocator = Allocator :: default ( ) ;
315+ let v = Vec :: from_iter_in ( [ 1 , 2 , 3 ] , & allocator) ;
316+ let b = v. into_boxed_slice ( ) ;
317+ let slice = b. into_bump_slice ( ) ;
318+ assert_eq ! ( slice, & [ 1 , 2 , 3 ] ) ;
319+ }
320+
321+ #[ test]
322+ fn boxed_slice_into_bump_slice_mut ( ) {
323+ let allocator = Allocator :: default ( ) ;
324+ let v = Vec :: from_iter_in ( [ 10 , 20 , 30 ] , & allocator) ;
325+ let b = v. into_boxed_slice ( ) ;
326+ let slice = b. into_bump_slice_mut ( ) ;
327+ slice[ 1 ] = 99 ;
328+ assert_eq ! ( slice, & [ 10 , 99 , 30 ] ) ;
329+ }
330+
245331 #[ test]
246332 fn box_debug ( ) {
247333 let allocator = Allocator :: default ( ) ;
0 commit comments