Skip to content

Commit cfb859e

Browse files
committed
Add Rc::(try_)clone_from_ref(_in)
1 parent 316d54a commit cfb859e

File tree

1 file changed

+115
-5
lines changed

1 file changed

+115
-5
lines changed

library/alloc/src/rc.rs

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@
243243

244244
use core::any::Any;
245245
use core::cell::{Cell, CloneFromCell};
246-
use core::clone::UseCloned;
247246
#[cfg(not(no_global_oom_handling))]
248-
use core::clone::{CloneToUninit, TrivialClone};
247+
use core::clone::TrivialClone;
248+
use core::clone::{CloneToUninit, UseCloned};
249249
use core::cmp::Ordering;
250250
use core::hash::{Hash, Hasher};
251251
use core::intrinsics::abort;
@@ -1290,6 +1290,104 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
12901290
}
12911291
}
12921292

1293+
impl<T: ?Sized + CloneToUninit> Rc<T> {
1294+
/// Constructs a new `Rc<T>` with a clone of `value`.
1295+
///
1296+
/// # Examples
1297+
///
1298+
/// ```
1299+
/// #![feature(clone_from_ref)]
1300+
/// use std::rc::Rc;
1301+
///
1302+
/// let hello: Rc<str> = Rc::clone_from_ref("hello");
1303+
/// ```
1304+
#[cfg(not(no_global_oom_handling))]
1305+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1306+
pub fn clone_from_ref(value: &T) -> Rc<T> {
1307+
Rc::clone_from_ref_in(value, Global)
1308+
}
1309+
1310+
/// Constructs a new `Rc<T>` with a clone of `value`, returning an error if allocation fails
1311+
///
1312+
/// # Examples
1313+
///
1314+
/// ```
1315+
/// #![feature(clone_from_ref)]
1316+
/// #![feature(allocator_api)]
1317+
/// use std::rc::Rc;
1318+
///
1319+
/// let hello: Rc<str> = Rc::try_clone_from_ref("hello")?;
1320+
/// # Ok::<(), std::alloc::AllocError>(())
1321+
/// ```
1322+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1323+
//#[unstable(feature = "allocator_api", issue = "32838")]
1324+
pub fn try_clone_from_ref(value: &T) -> Result<Rc<T>, AllocError> {
1325+
Rc::try_clone_from_ref_in(value, Global)
1326+
}
1327+
}
1328+
1329+
impl<T: ?Sized + CloneToUninit, A: Allocator> Rc<T, A> {
1330+
/// Constructs a new `Rc<T>` with a clone of `value` in the provided allocator.
1331+
///
1332+
/// # Examples
1333+
///
1334+
/// ```
1335+
/// #![feature(clone_from_ref)]
1336+
/// #![feature(allocator_api)]
1337+
/// use std::rc::Rc;
1338+
/// use std::alloc::System;
1339+
///
1340+
/// let hello: Rc<str, System> = Rc::clone_from_ref_in("hello", System);
1341+
/// ```
1342+
#[cfg(not(no_global_oom_handling))]
1343+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1344+
//#[unstable(feature = "allocator_api", issue = "32838")]
1345+
pub fn clone_from_ref_in(value: &T, alloc: A) -> Rc<T, A> {
1346+
// `in_progress` drops the allocation if we panic before finishing initializing it.
1347+
let mut in_progress: UniqueRcUninit<T, A> = UniqueRcUninit::new(value, alloc);
1348+
1349+
// Initialize with clone of value.
1350+
let initialized_clone = unsafe {
1351+
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
1352+
value.clone_to_uninit(in_progress.data_ptr().cast());
1353+
// Cast type of pointer, now that it is initialized.
1354+
in_progress.into_rc()
1355+
};
1356+
1357+
initialized_clone
1358+
}
1359+
1360+
/// Constructs a new `Rc<T>` with a clone of `value` in the provided allocator, returning an error if allocation fails
1361+
///
1362+
/// # Examples
1363+
///
1364+
/// ```
1365+
/// #![feature(clone_from_ref)]
1366+
/// #![feature(allocator_api)]
1367+
/// use std::rc::Rc;
1368+
/// use std::alloc::System;
1369+
///
1370+
/// let hello: Rc<str, System> = Rc::try_clone_from_ref_in("hello", System)?;
1371+
/// # Ok::<(), std::alloc::AllocError>(())
1372+
/// ```
1373+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1374+
//#[unstable(feature = "allocator_api", issue = "32838")]
1375+
pub fn try_clone_from_ref_in(value: &T, alloc: A) -> Result<Rc<T, A>, AllocError> {
1376+
// `in_progress` drops the allocation if we panic before finishing initializing it.
1377+
let mut in_progress: UniqueRcUninit<T, A> = UniqueRcUninit::try_new(value, alloc)?;
1378+
1379+
// Initialize with clone of value.
1380+
let initialized_clone = unsafe {
1381+
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
1382+
value.clone_to_uninit(in_progress.data_ptr().cast());
1383+
// Cast type of pointer, now that it is initialized.
1384+
in_progress.into_rc()
1385+
};
1386+
1387+
Ok(initialized_clone)
1388+
}
1389+
}
1390+
12931391
impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> {
12941392
/// Converts to `Rc<[T]>`.
12951393
///
@@ -4358,16 +4456,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc<T, A> {
43584456
/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic.
43594457
/// It is nearly a duplicate of `UniqueRc<MaybeUninit<T>, A>` except that it allows `T: !Sized`,
43604458
/// which `MaybeUninit` does not.
4361-
#[cfg(not(no_global_oom_handling))]
43624459
struct UniqueRcUninit<T: ?Sized, A: Allocator> {
43634460
ptr: NonNull<RcInner<T>>,
43644461
layout_for_value: Layout,
43654462
alloc: Option<A>,
43664463
}
43674464

4368-
#[cfg(not(no_global_oom_handling))]
43694465
impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
43704466
/// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it.
4467+
#[cfg(not(no_global_oom_handling))]
43714468
fn new(for_value: &T, alloc: A) -> UniqueRcUninit<T, A> {
43724469
let layout = Layout::for_value(for_value);
43734470
let ptr = unsafe {
@@ -4380,6 +4477,20 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
43804477
Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) }
43814478
}
43824479

4480+
/// Allocates a RcInner with layout suitable to contain `for_value` or a clone of it,
4481+
/// returning an error if allocation fails.
4482+
fn try_new(for_value: &T, alloc: A) -> Result<UniqueRcUninit<T, A>, AllocError> {
4483+
let layout = Layout::for_value(for_value);
4484+
let ptr = unsafe {
4485+
Rc::try_allocate_for_layout(
4486+
layout,
4487+
|layout_for_rc_inner| alloc.allocate(layout_for_rc_inner),
4488+
|mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner<T>),
4489+
)?
4490+
};
4491+
Ok(Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) })
4492+
}
4493+
43834494
/// Returns the pointer to be written into to initialize the [`Rc`].
43844495
fn data_ptr(&mut self) -> *mut T {
43854496
let offset = data_offset_align(self.layout_for_value.align());
@@ -4402,7 +4513,6 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
44024513
}
44034514
}
44044515

4405-
#[cfg(not(no_global_oom_handling))]
44064516
impl<T: ?Sized, A: Allocator> Drop for UniqueRcUninit<T, A> {
44074517
fn drop(&mut self) {
44084518
// SAFETY:

0 commit comments

Comments
 (0)