@@ -69,6 +69,27 @@ impl<T> ThinBox<T> {
6969 }
7070}
7171
72+ #[ unstable( feature = "thin_box" , issue = "92791" ) ]
73+ impl < T > ThinBox < T > {
74+ /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
75+ /// the stack. Returns an error if allocation fails, instead of aborting.
76+ ///
77+ /// # Examples
78+ ///
79+ /// ```
80+ /// #![feature(thin_box)]
81+ /// use std::boxed::ThinBox;
82+ ///
83+ /// let five = ThinBox::new(5);
84+ /// ```
85+ ///
86+ /// [`Metadata`]: core::ptr::Pointee::Metadata
87+ pub fn try_new ( value : T ) -> Result < Self , core:: alloc:: AllocError > {
88+ let meta = ptr:: metadata ( & value) ;
89+ WithOpaqueHeader :: try_new ( meta, value) . map ( |ptr| ThinBox { ptr, _marker : PhantomData } )
90+ }
91+ }
92+
7293#[ unstable( feature = "thin_box" , issue = "92791" ) ]
7394impl < Dyn : ?Sized > ThinBox < Dyn > {
7495 /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
@@ -179,6 +200,10 @@ impl WithOpaqueHeader {
179200 let ptr = WithHeader :: new ( header, value) ;
180201 Self ( ptr. 0 )
181202 }
203+
204+ fn try_new < H , T > ( header : H , value : T ) -> Result < Self , core:: alloc:: AllocError > {
205+ WithHeader :: try_new ( header, value) . map ( |ptr| Self ( ptr. 0 ) )
206+ }
182207}
183208
184209impl < H > WithHeader < H > {
@@ -226,6 +251,46 @@ impl<H> WithHeader<H> {
226251 }
227252 }
228253
254+ /// Non-panicking version of `new`.
255+ /// Any error is returned as `Err(core::alloc::AllocError)`.
256+ fn try_new < T > ( header : H , value : T ) -> Result < WithHeader < H > , core:: alloc:: AllocError > {
257+ let value_layout = Layout :: new :: < T > ( ) ;
258+ let Ok ( ( layout, value_offset) ) = Self :: alloc_layout ( value_layout) else {
259+ return Err ( core:: alloc:: AllocError ) ;
260+ } ;
261+
262+ unsafe {
263+ // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
264+ // we use `layout.dangling()` for this case, which should have a valid
265+ // alignment for both `T` and `H`.
266+ let ptr = if layout. size ( ) == 0 {
267+ // Some paranoia checking, mostly so that the ThinBox tests are
268+ // more able to catch issues.
269+ debug_assert ! (
270+ value_offset == 0 && mem:: size_of:: <T >( ) == 0 && mem:: size_of:: <H >( ) == 0
271+ ) ;
272+ layout. dangling ( )
273+ } else {
274+ let ptr = alloc:: alloc ( layout) ;
275+ if ptr. is_null ( ) {
276+ return Err ( core:: alloc:: AllocError ) ;
277+ }
278+
279+ // Safety:
280+ // - The size is at least `aligned_header_size`.
281+ let ptr = ptr. add ( value_offset) as * mut _ ;
282+
283+ NonNull :: new_unchecked ( ptr)
284+ } ;
285+
286+ let result = WithHeader ( ptr, PhantomData ) ;
287+ ptr:: write ( result. header ( ) , header) ;
288+ ptr:: write ( result. value ( ) . cast ( ) , value) ;
289+
290+ Ok ( result)
291+ }
292+ }
293+
229294 // Safety:
230295 // - Assumes that either `value` can be dereferenced, or is the
231296 // `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
0 commit comments