Skip to content

Commit 973fa8e

Browse files
committed
Add fallible Rc APIs (Rc::try_new_*)
1 parent dd2c6c3 commit 973fa8e

File tree

1 file changed

+121
-22
lines changed

1 file changed

+121
-22
lines changed

library/alloc/src/rc.rs

+121-22
Original file line numberDiff line numberDiff line change
@@ -346,28 +346,6 @@ impl<T> Rc<T> {
346346
)
347347
}
348348

349-
/// Constructs a new `Rc<T>`.
350-
///
351-
/// # Examples
352-
///
353-
/// ```
354-
/// #![feature(allocator_api, new_uninit)]
355-
/// use std::rc::Rc;
356-
///
357-
/// let five = Rc::new(5);
358-
/// ```
359-
#[stable(feature = "rust1", since = "1.0.0")]
360-
pub fn try_new(value: T) -> Result<Rc<T>, AllocError> {
361-
// There is an implicit weak pointer owned by all the strong
362-
// pointers, which ensures that the weak destructor never frees
363-
// the allocation while the strong destructor is running, even
364-
// if the weak pointer is stored inside the strong one.
365-
Ok(Self::from_inner(
366-
Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?)
367-
.into(),
368-
))
369-
}
370-
371349
/// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
372350
/// to upgrade the weak reference before this function returns will result
373351
/// in a `None` value. However, the weak reference may be cloned freely and
@@ -475,6 +453,95 @@ impl<T> Rc<T> {
475453
}
476454
}
477455

456+
/// Constructs a new `Rc<T>`, returning an error if the allocation fails
457+
///
458+
/// # Examples
459+
///
460+
/// ```
461+
/// #![feature(allocator_api)]
462+
/// use std::rc::Rc;
463+
///
464+
/// let five = Rc::try_new(5);
465+
/// # Ok::<(), std::alloc::AllocError>(())
466+
/// ```
467+
#[unstable(feature = "allocator_api", issue = "32838")]
468+
pub fn try_new(value: T) -> Result<Rc<T>, AllocError> {
469+
// There is an implicit weak pointer owned by all the strong
470+
// pointers, which ensures that the weak destructor never frees
471+
// the allocation while the strong destructor is running, even
472+
// if the weak pointer is stored inside the strong one.
473+
Ok(Self::from_inner(
474+
Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?)
475+
.into(),
476+
))
477+
}
478+
479+
/// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails
480+
///
481+
/// # Examples
482+
///
483+
/// ```
484+
/// #![feature(allocator_api, new_uninit)]
485+
/// #![feature(get_mut_unchecked)]
486+
///
487+
/// use std::rc::Rc;
488+
///
489+
/// let mut five = Rc::<u32>::try_new_uninit()?;
490+
///
491+
/// let five = unsafe {
492+
/// // Deferred initialization:
493+
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
494+
///
495+
/// five.assume_init()
496+
/// };
497+
///
498+
/// assert_eq!(*five, 5);
499+
/// # Ok::<(), std::alloc::AllocError>(())
500+
/// ```
501+
#[unstable(feature = "allocator_api", issue = "32838")]
502+
// #[unstable(feature = "new_uninit", issue = "63291")]
503+
pub fn try_new_uninit() -> Result<Rc<mem::MaybeUninit<T>>, AllocError> {
504+
unsafe {
505+
Ok(Rc::from_ptr(Rc::try_allocate_for_layout(
506+
Layout::new::<T>(),
507+
|layout| Global.allocate(layout),
508+
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
509+
)?))
510+
}
511+
}
512+
513+
/// Constructs a new `Rc` with uninitialized contents, with the memory
514+
/// being filled with `0` bytes, returning an error if the allocation fails
515+
///
516+
/// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and
517+
/// incorrect usage of this method.
518+
///
519+
/// # Examples
520+
///
521+
/// ```
522+
/// #![feature(allocator_api, new_uninit)]
523+
///
524+
/// use std::rc::Rc;
525+
///
526+
/// let zero = Rc::<u32>::try_new_zeroed()?;
527+
/// let zero = unsafe { zero.assume_init() };
528+
///
529+
/// assert_eq!(*zero, 0);
530+
/// # Ok::<(), std::alloc::AllocError>(())
531+
/// ```
532+
///
533+
/// [zeroed]: mem::MaybeUninit::zeroed
534+
#[unstable(feature = "allocator_api", issue = "32838")]
535+
//#[unstable(feature = "new_uninit", issue = "63291")]
536+
pub fn try_new_zeroed() -> Result<Rc<mem::MaybeUninit<T>>, AllocError> {
537+
unsafe {
538+
Ok(Rc::from_ptr(Rc::try_allocate_for_layout(
539+
Layout::new::<T>(),
540+
|layout| Global.allocate_zeroed(layout),
541+
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
542+
)?))
543+
}
544+
}
478545
/// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then
479546
/// `value` will be pinned in memory and unable to be moved.
480547
#[stable(feature = "pin", since = "1.33.0")]
@@ -1056,6 +1123,38 @@ impl<T: ?Sized> Rc<T> {
10561123
inner
10571124
}
10581125

1126+
/// Allocates an `RcBox<T>` with sufficient space for
1127+
/// a possibly-unsized inner value where the value has the layout provided,
1128+
/// returning an error if allocation fails.
1129+
///
1130+
/// The function `mem_to_rcbox` is called with the data pointer
1131+
/// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
1132+
unsafe fn try_allocate_for_layout(
1133+
value_layout: Layout,
1134+
allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
1135+
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>,
1136+
) -> Result<*mut RcBox<T>, AllocError> {
1137+
// Calculate layout using the given value layout.
1138+
// Previously, layout was calculated on the expression
1139+
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
1140+
// reference (see #54908).
1141+
let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
1142+
1143+
// Allocate for the layout.
1144+
let ptr = allocate(layout)?;
1145+
1146+
// Initialize the RcBox
1147+
let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr());
1148+
unsafe {
1149+
debug_assert_eq!(Layout::for_value(&*inner), layout);
1150+
1151+
ptr::write(&mut (*inner).strong, Cell::new(1));
1152+
ptr::write(&mut (*inner).weak, Cell::new(1));
1153+
}
1154+
1155+
Ok(inner)
1156+
}
1157+
10591158
/// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
10601159
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
10611160
// Allocate for the `RcBox<T>` using the given value.

0 commit comments

Comments
 (0)