Skip to content

Commit 3c880f2

Browse files
committed
Create try_new function for ThinBox
1 parent e279f90 commit 3c880f2

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

library/alloc/src/boxed/thin.rs

+65
Original file line numberDiff line numberDiff line change
@@ -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")]
7394
impl<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

184209
impl<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

Comments
 (0)