@@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
6767 let ptr = WithOpaqueHeader :: new ( meta, value) ;
6868 ThinBox { ptr, _marker : PhantomData }
6969 }
70+
71+ /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
72+ /// the stack. Returns an error if allocation fails, instead of aborting.
73+ ///
74+ /// # Examples
75+ ///
76+ /// ```
77+ /// #![feature(allocator_api)]
78+ /// #![feature(thin_box)]
79+ /// use std::boxed::ThinBox;
80+ ///
81+ /// let five = ThinBox::try_new(5)?;
82+ /// # Ok::<(), std::alloc::AllocError>(())
83+ /// ```
84+ ///
85+ /// [`Metadata`]: core::ptr::Pointee::Metadata
86+ pub fn try_new ( value : T ) -> Result < Self , core:: alloc:: AllocError > {
87+ let meta = ptr:: metadata ( & value) ;
88+ WithOpaqueHeader :: try_new ( meta, value) . map ( |ptr| ThinBox { ptr, _marker : PhantomData } )
89+ }
7090}
7191
7292#[ unstable( feature = "thin_box" , issue = "92791" ) ]
@@ -179,6 +199,10 @@ impl WithOpaqueHeader {
179199 let ptr = WithHeader :: new ( header, value) ;
180200 Self ( ptr. 0 )
181201 }
202+
203+ fn try_new < H , T > ( header : H , value : T ) -> Result < Self , core:: alloc:: AllocError > {
204+ WithHeader :: try_new ( header, value) . map ( |ptr| Self ( ptr. 0 ) )
205+ }
182206}
183207
184208impl < H > WithHeader < H > {
@@ -224,6 +248,46 @@ impl<H> WithHeader<H> {
224248 }
225249 }
226250
251+ /// Non-panicking version of `new`.
252+ /// Any error is returned as `Err(core::alloc::AllocError)`.
253+ fn try_new < T > ( header : H , value : T ) -> Result < WithHeader < H > , core:: alloc:: AllocError > {
254+ let value_layout = Layout :: new :: < T > ( ) ;
255+ let Ok ( ( layout, value_offset) ) = Self :: alloc_layout ( value_layout) else {
256+ return Err ( core:: alloc:: AllocError ) ;
257+ } ;
258+
259+ unsafe {
260+ // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
261+ // we use `layout.dangling()` for this case, which should have a valid
262+ // alignment for both `T` and `H`.
263+ let ptr = if layout. size ( ) == 0 {
264+ // Some paranoia checking, mostly so that the ThinBox tests are
265+ // more able to catch issues.
266+ debug_assert ! (
267+ value_offset == 0 && mem:: size_of:: <T >( ) == 0 && mem:: size_of:: <H >( ) == 0
268+ ) ;
269+ layout. dangling ( )
270+ } else {
271+ let ptr = alloc:: alloc ( layout) ;
272+ if ptr. is_null ( ) {
273+ return Err ( core:: alloc:: AllocError ) ;
274+ }
275+
276+ // Safety:
277+ // - The size is at least `aligned_header_size`.
278+ let ptr = ptr. add ( value_offset) as * mut _ ;
279+
280+ NonNull :: new_unchecked ( ptr)
281+ } ;
282+
283+ let result = WithHeader ( ptr, PhantomData ) ;
284+ ptr:: write ( result. header ( ) , header) ;
285+ ptr:: write ( result. value ( ) . cast ( ) , value) ;
286+
287+ Ok ( result)
288+ }
289+ }
290+
227291 // Safety:
228292 // - Assumes that either `value` can be dereferenced, or is the
229293 // `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
0 commit comments