@@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
67
67
let ptr = WithOpaqueHeader :: new ( meta, value) ;
68
68
ThinBox { ptr, _marker : PhantomData }
69
69
}
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
+ }
70
90
}
71
91
72
92
#[ unstable( feature = "thin_box" , issue = "92791" ) ]
@@ -179,6 +199,10 @@ impl WithOpaqueHeader {
179
199
let ptr = WithHeader :: new ( header, value) ;
180
200
Self ( ptr. 0 )
181
201
}
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
+ }
182
206
}
183
207
184
208
impl < H > WithHeader < H > {
@@ -224,6 +248,46 @@ impl<H> WithHeader<H> {
224
248
}
225
249
}
226
250
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
+
227
291
// Safety:
228
292
// - Assumes that either `value` can be dereferenced, or is the
229
293
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
0 commit comments