Skip to content

Commit

Permalink
Add fallible box APIs (Box::try_new_*)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Dec 31, 2020
1 parent d116f48 commit dd2c6c3
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
74 changes: 73 additions & 1 deletion library/alloc/src/boxed.rs
Expand Up @@ -241,6 +241,77 @@ impl<T> Box<T> {
pub fn pin(x: T) -> Pin<Box<T>> {
(box x).into()
}

/// Allocates memory on the heap then places `x` into it,
/// returning an error if the allocation fails
///
/// This doesn't actually allocate if `T` is zero-sized.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
///
/// let five = Box::try_new(5)?;
/// # Ok::<(), std::alloc::AllocError>(())
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn try_new(x: T) -> Result<Self, AllocError> {
Self::try_new_in(x, Global)
}

/// Constructs a new box with uninitialized contents on the heap,
/// returning an error if the allocation fails
///
/// # Examples
///
/// ```
/// #![feature(allocator_api, new_uninit)]
///
///
/// let mut five = Box::<u32>::try_new_uninit()?;
///
/// let five = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5);
/// # Ok::<(), std::alloc::AllocError>(())
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
pub fn try_new_uninit() -> Result<Box<mem::MaybeUninit<T>>, AllocError> {
Box::try_new_uninit_in(Global)
}

/// Constructs a new `Box` with uninitialized contents, with the memory
/// being filled with `0` bytes on the heap
///
/// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage
/// of this method.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api, new_uninit)]
///
/// let zero = Box::<u32>::try_new_zeroed()?;
/// let zero = unsafe { zero.assume_init() };
///
/// assert_eq!(*zero, 0);
/// # Ok::<(), std::alloc::AllocError>(())
/// ```
///
/// [zeroed]: mem::MaybeUninit::zeroed
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
pub fn try_new_zeroed() -> Result<Box<mem::MaybeUninit<T>>, AllocError> {
Box::try_new_zeroed_in(Global)
}
}

impl<T, A: Allocator> Box<T, A> {
Expand Down Expand Up @@ -380,7 +451,8 @@ impl<T, A: Allocator> Box<T, A> {
}

/// Constructs a new `Box` with uninitialized contents, with the memory
/// being filled with `0` bytes in the provided allocator.
/// being filled with `0` bytes in the provided allocator,
/// returning an error if the allocation fails,
///
/// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage
/// of this method.
Expand Down
22 changes: 22 additions & 0 deletions library/alloc/src/rc.rs
Expand Up @@ -346,6 +346,28 @@ impl<T> Rc<T> {
)
}

/// Constructs a new `Rc<T>`.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api, new_uninit)]
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_new(value: T) -> Result<Rc<T>, AllocError> {
// There is an implicit weak pointer owned by all the strong
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
Ok(Self::from_inner(
Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?)
.into(),
))
}

/// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
/// to upgrade the weak reference before this function returns will result
/// in a `None` value. However, the weak reference may be cloned freely and
Expand Down

0 comments on commit dd2c6c3

Please sign in to comment.