Skip to content

Commit b565635

Browse files
committed
Add Arc::(try_)clone_from_ref(_in)
1 parent 7a7142c commit b565635

File tree

1 file changed

+114
-5
lines changed

1 file changed

+114
-5
lines changed

library/alloc/src/sync.rs

Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@
1111
use core::any::Any;
1212
use core::cell::CloneFromCell;
1313
#[cfg(not(no_global_oom_handling))]
14-
use core::clone::CloneToUninit;
15-
#[cfg(not(no_global_oom_handling))]
1614
use core::clone::TrivialClone;
17-
use core::clone::UseCloned;
15+
use core::clone::{CloneToUninit, UseCloned};
1816
use core::cmp::Ordering;
1917
use core::hash::{Hash, Hasher};
2018
use core::intrinsics::abort;
@@ -1442,6 +1440,104 @@ impl<T, A: Allocator> Arc<mem::MaybeUninit<T>, A> {
14421440
}
14431441
}
14441442

1443+
impl<T: ?Sized + CloneToUninit> Arc<T> {
1444+
/// Constructs a new `Arc<T>` with a clone of `value`.
1445+
///
1446+
/// # Examples
1447+
///
1448+
/// ```
1449+
/// #![feature(clone_from_ref)]
1450+
/// use std::sync::Arc;
1451+
///
1452+
/// let hello: Arc<str> = Arc::clone_from_ref("hello");
1453+
/// ```
1454+
#[cfg(not(no_global_oom_handling))]
1455+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1456+
pub fn clone_from_ref(value: &T) -> Arc<T> {
1457+
Arc::clone_from_ref_in(value, Global)
1458+
}
1459+
1460+
/// Constructs a new `Arc<T>` with a clone of `value`, returning an error if allocation fails
1461+
///
1462+
/// # Examples
1463+
///
1464+
/// ```
1465+
/// #![feature(clone_from_ref)]
1466+
/// #![feature(allocator_api)]
1467+
/// use std::sync::Arc;
1468+
///
1469+
/// let hello: Arc<str> = Arc::try_clone_from_ref("hello")?;
1470+
/// # Ok::<(), std::alloc::AllocError>(())
1471+
/// ```
1472+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1473+
//#[unstable(feature = "allocator_api", issue = "32838")]
1474+
pub fn try_clone_from_ref(value: &T) -> Result<Arc<T>, AllocError> {
1475+
Arc::try_clone_from_ref_in(value, Global)
1476+
}
1477+
}
1478+
1479+
impl<T: ?Sized + CloneToUninit, A: Allocator> Arc<T, A> {
1480+
/// Constructs a new `Arc<T>` with a clone of `value` in the provided allocator.
1481+
///
1482+
/// # Examples
1483+
///
1484+
/// ```
1485+
/// #![feature(clone_from_ref)]
1486+
/// #![feature(allocator_api)]
1487+
/// use std::sync::Arc;
1488+
/// use std::alloc::System;
1489+
///
1490+
/// let hello: Arc<str, System> = Arc::clone_from_ref_in("hello", System);
1491+
/// ```
1492+
#[cfg(not(no_global_oom_handling))]
1493+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1494+
//#[unstable(feature = "allocator_api", issue = "32838")]
1495+
pub fn clone_from_ref_in(value: &T, alloc: A) -> Arc<T, A> {
1496+
// `in_progress` drops the allocation if we panic before finishing initializing it.
1497+
let mut in_progress: UniqueArcUninit<T, A> = UniqueArcUninit::new(value, alloc);
1498+
1499+
// Initialize with clone of value.
1500+
let initialized_clone = unsafe {
1501+
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
1502+
value.clone_to_uninit(in_progress.data_ptr().cast());
1503+
// Cast type of pointer, now that it is initialized.
1504+
in_progress.into_arc()
1505+
};
1506+
1507+
initialized_clone
1508+
}
1509+
1510+
/// Constructs a new `Arc<T>` with a clone of `value` in the provided allocator, returning an error if allocation fails
1511+
///
1512+
/// # Examples
1513+
///
1514+
/// ```
1515+
/// #![feature(clone_from_ref)]
1516+
/// #![feature(allocator_api)]
1517+
/// use std::sync::Arc;
1518+
/// use std::alloc::System;
1519+
///
1520+
/// let hello: Arc<str, System> = Arc::try_clone_from_ref_in("hello", System)?;
1521+
/// # Ok::<(), std::alloc::AllocError>(())
1522+
/// ```
1523+
#[unstable(feature = "clone_from_ref", issue = "149075")]
1524+
//#[unstable(feature = "allocator_api", issue = "32838")]
1525+
pub fn try_clone_from_ref_in(value: &T, alloc: A) -> Result<Arc<T, A>, AllocError> {
1526+
// `in_progress` drops the allocation if we panic before finishing initializing it.
1527+
let mut in_progress: UniqueArcUninit<T, A> = UniqueArcUninit::try_new(value, alloc)?;
1528+
1529+
// Initialize with clone of value.
1530+
let initialized_clone = unsafe {
1531+
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
1532+
value.clone_to_uninit(in_progress.data_ptr().cast());
1533+
// Cast type of pointer, now that it is initialized.
1534+
in_progress.into_arc()
1535+
};
1536+
1537+
Ok(initialized_clone)
1538+
}
1539+
}
1540+
14451541
impl<T, A: Allocator> Arc<[mem::MaybeUninit<T>], A> {
14461542
/// Converts to `Arc<[T]>`.
14471543
///
@@ -4137,16 +4233,15 @@ fn data_offset_align(align: usize) -> usize {
41374233
/// but will deallocate it (without dropping the value) when dropped.
41384234
///
41394235
/// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic.
4140-
#[cfg(not(no_global_oom_handling))]
41414236
struct UniqueArcUninit<T: ?Sized, A: Allocator> {
41424237
ptr: NonNull<ArcInner<T>>,
41434238
layout_for_value: Layout,
41444239
alloc: Option<A>,
41454240
}
41464241

4147-
#[cfg(not(no_global_oom_handling))]
41484242
impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
41494243
/// Allocates an ArcInner with layout suitable to contain `for_value` or a clone of it.
4244+
#[cfg(not(no_global_oom_handling))]
41504245
fn new(for_value: &T, alloc: A) -> UniqueArcUninit<T, A> {
41514246
let layout = Layout::for_value(for_value);
41524247
let ptr = unsafe {
@@ -4159,6 +4254,20 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
41594254
Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) }
41604255
}
41614256

4257+
/// Allocates an ArcInner with layout suitable to contain `for_value` or a clone of it,
4258+
/// returning an error if allocation fails.
4259+
fn try_new(for_value: &T, alloc: A) -> Result<UniqueArcUninit<T, A>, AllocError> {
4260+
let layout = Layout::for_value(for_value);
4261+
let ptr = unsafe {
4262+
Arc::try_allocate_for_layout(
4263+
layout,
4264+
|layout_for_arcinner| alloc.allocate(layout_for_arcinner),
4265+
|mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const ArcInner<T>),
4266+
)?
4267+
};
4268+
Ok(Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) })
4269+
}
4270+
41624271
/// Returns the pointer to be written into to initialize the [`Arc`].
41634272
fn data_ptr(&mut self) -> *mut T {
41644273
let offset = data_offset_align(self.layout_for_value.align());

0 commit comments

Comments
 (0)