@@ -69,6 +69,27 @@ impl<T> ThinBox<T> {
69
69
}
70
70
}
71
71
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
+
72
93
#[ unstable( feature = "thin_box" , issue = "92791" ) ]
73
94
impl < Dyn : ?Sized > ThinBox < Dyn > {
74
95
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
@@ -179,6 +200,10 @@ impl WithOpaqueHeader {
179
200
let ptr = WithHeader :: new ( header, value) ;
180
201
Self ( ptr. 0 )
181
202
}
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
+ }
182
207
}
183
208
184
209
impl < H > WithHeader < H > {
@@ -226,6 +251,46 @@ impl<H> WithHeader<H> {
226
251
}
227
252
}
228
253
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
+
229
294
// Safety:
230
295
// - Assumes that either `value` can be dereferenced, or is the
231
296
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
0 commit comments