From dd2c6c318bfe3191e936f4500d60b5089db1ef60 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 31 Dec 2020 06:40:17 +0000 Subject: [PATCH] Add fallible box APIs (`Box::try_new_*`) --- library/alloc/src/boxed.rs | 74 +++++++++++++++++++++++++++++++++++++- library/alloc/src/rc.rs | 22 ++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index bc56c7a3c4f..eb00d1a8b47 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -241,6 +241,77 @@ impl Box { pub fn pin(x: T) -> Pin> { (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::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::::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>, 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::::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>, AllocError> { + Box::try_new_zeroed_in(Global) + } } impl Box { @@ -380,7 +451,8 @@ impl Box { } /// 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. diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a96be57143d..739ffd31f60 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -346,6 +346,28 @@ impl Rc { ) } + /// Constructs a new `Rc`. + /// + /// # 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, 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` 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