Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions library/alloc/src/boxed/thin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,27 @@ impl<T> ThinBox<T> {
}
}

#[unstable(feature = "thin_box", issue = "92791")]
impl<T> ThinBox<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T> ThinBox<T> {

These impl blocks are identical. They should be combined into one block, otherwise rustdoc will render it as two different impl blocks.

/// 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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example needs to cover ThinBox::try_new, not ThinBox::new.

/// ```
///
/// [`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")]
impl<Dyn: ?Sized> ThinBox<Dyn> {
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
Expand Down Expand Up @@ -179,6 +200,10 @@ impl WithOpaqueHeader {
let ptr = WithHeader::new(header, value);
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> {
Expand Down Expand Up @@ -226,6 +251,46 @@ impl<H> 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:
// - Assumes that either `value` can be dereferenced, or is the
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
Expand Down