diff options
| author | bors <bors@rust-lang.org> | 2024-02-12 00:34:22 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-02-12 00:34:22 +0000 |
| commit | 084ce5bdb5f7dc1c725f6770a8de281165ba3b0a (patch) | |
| tree | 19b02783a13bce0a281f7d29274a102afde2c629 /library/alloc | |
| parent | 520b0b20aa8c218f84cefc6260f52406b84fa55f (diff) | |
| parent | 9bd630af97e609cd9579703777a2d8d67f8fc2da (diff) | |
Auto merge of #120951 - matthiaskrgr:rollup-0nnm7dv, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #110483 (Create try_new function for ThinBox) - #120740 (Make cmath.rs a single file) - #120872 (hir: Refactor getters for HIR parents) - #120880 (add note on comparing vtables / function pointers) - #120885 (interpret/visitor: ensure we only see normalized types) - #120888 (assert_unsafe_precondition cleanup) - #120897 (Encode `coroutine_for_closure` for foreign crates) - #120937 ([docs] Update armv6k-nintendo-3ds platform docs for outdated info) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'library/alloc')
| -rw-r--r-- | library/alloc/src/boxed/thin.rs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index f83c8f83cc9..3b29c144a89 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -67,6 +67,26 @@ impl<T> ThinBox<T> { let ptr = WithOpaqueHeader::new(meta, value); ThinBox { ptr, _marker: PhantomData } } + + /// 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(allocator_api)] + /// #![feature(thin_box)] + /// use std::boxed::ThinBox; + /// + /// let five = ThinBox::try_new(5)?; + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [`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")] @@ -179,6 +199,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> { @@ -224,6 +248,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. |
