Create try_new function for ThinBox
This commit is contained in:
parent
e279f902f3
commit
3c880f2405
@ -69,6 +69,27 @@ pub fn new(value: T) -> Self {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "thin_box", issue = "92791")]
|
||||||
|
impl<T> ThinBox<T> {
|
||||||
|
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
|
||||||
|
/// the stack. Returns an error if allocation fails, instead of aborting.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(thin_box)]
|
||||||
|
/// use std::boxed::ThinBox;
|
||||||
|
///
|
||||||
|
/// let five = ThinBox::new(5);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`Metadata`]: core::ptr::Pointee::Metadata
|
||||||
|
pub fn try_new(value: T) -> Result<Self, core::alloc::AllocError> {
|
||||||
|
let meta = ptr::metadata(&value);
|
||||||
|
WithOpaqueHeader::try_new(meta, value).map(|ptr| ThinBox { ptr, _marker: PhantomData })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[unstable(feature = "thin_box", issue = "92791")]
|
#[unstable(feature = "thin_box", issue = "92791")]
|
||||||
impl<Dyn: ?Sized> ThinBox<Dyn> {
|
impl<Dyn: ?Sized> ThinBox<Dyn> {
|
||||||
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
|
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
|
||||||
@ -179,6 +200,10 @@ fn new<H, T>(header: H, value: T) -> Self {
|
|||||||
let ptr = WithHeader::new(header, value);
|
let ptr = WithHeader::new(header, value);
|
||||||
Self(ptr.0)
|
Self(ptr.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> {
|
||||||
|
WithHeader::try_new(header, value).map(|ptr| Self(ptr.0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H> WithHeader<H> {
|
impl<H> WithHeader<H> {
|
||||||
@ -226,6 +251,46 @@ fn new<T>(header: H, value: T) -> WithHeader<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Non-panicking version of `new`.
|
||||||
|
/// Any error is returned as `Err(core::alloc::AllocError)`.
|
||||||
|
fn try_new<T>(header: H, value: T) -> Result<WithHeader<H>, core::alloc::AllocError> {
|
||||||
|
let value_layout = Layout::new::<T>();
|
||||||
|
let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
|
||||||
|
return Err(core::alloc::AllocError);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
|
||||||
|
// we use `layout.dangling()` for this case, which should have a valid
|
||||||
|
// alignment for both `T` and `H`.
|
||||||
|
let ptr = if layout.size() == 0 {
|
||||||
|
// Some paranoia checking, mostly so that the ThinBox tests are
|
||||||
|
// more able to catch issues.
|
||||||
|
debug_assert!(
|
||||||
|
value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
|
||||||
|
);
|
||||||
|
layout.dangling()
|
||||||
|
} else {
|
||||||
|
let ptr = alloc::alloc(layout);
|
||||||
|
if ptr.is_null() {
|
||||||
|
return Err(core::alloc::AllocError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety:
|
||||||
|
// - The size is at least `aligned_header_size`.
|
||||||
|
let ptr = ptr.add(value_offset) as *mut _;
|
||||||
|
|
||||||
|
NonNull::new_unchecked(ptr)
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = WithHeader(ptr, PhantomData);
|
||||||
|
ptr::write(result.header(), header);
|
||||||
|
ptr::write(result.value().cast(), value);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Safety:
|
// Safety:
|
||||||
// - Assumes that either `value` can be dereferenced, or is the
|
// - Assumes that either `value` can be dereferenced, or is the
|
||||||
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
|
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
|
||||||
|
Loading…
Reference in New Issue
Block a user