Add Arc::(try_)clone_from_ref(_in)
This commit is contained in:
parent
7a7142c93b
commit
b565635e04
1 changed files with 114 additions and 5 deletions
|
|
@ -11,10 +11,8 @@
|
|||
use core::any::Any;
|
||||
use core::cell::CloneFromCell;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::clone::CloneToUninit;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::clone::TrivialClone;
|
||||
use core::clone::UseCloned;
|
||||
use core::clone::{CloneToUninit, UseCloned};
|
||||
use core::cmp::Ordering;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::abort;
|
||||
|
|
@ -1442,6 +1440,104 @@ impl<T, A: Allocator> Arc<mem::MaybeUninit<T>, A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit> Arc<T> {
|
||||
/// Constructs a new `Arc<T>` with a clone of `value`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let hello: Arc<str> = Arc::clone_from_ref("hello");
|
||||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
pub fn clone_from_ref(value: &T) -> Arc<T> {
|
||||
Arc::clone_from_ref_in(value, Global)
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc<T>` with a clone of `value`, returning an error if allocation fails
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let hello: Arc<str> = Arc::try_clone_from_ref("hello")?;
|
||||
/// # Ok::<(), std::alloc::AllocError>(())
|
||||
/// ```
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
//#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn try_clone_from_ref(value: &T) -> Result<Arc<T>, AllocError> {
|
||||
Arc::try_clone_from_ref_in(value, Global)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit, A: Allocator> Arc<T, A> {
|
||||
/// Constructs a new `Arc<T>` with a clone of `value` in the provided allocator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
/// use std::sync::Arc;
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Arc<str, System> = Arc::clone_from_ref_in("hello", System);
|
||||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
//#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn clone_from_ref_in(value: &T, alloc: A) -> Arc<T, A> {
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueArcUninit<T, A> = UniqueArcUninit::new(value, alloc);
|
||||
|
||||
// Initialize with clone of value.
|
||||
let initialized_clone = unsafe {
|
||||
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
|
||||
value.clone_to_uninit(in_progress.data_ptr().cast());
|
||||
// Cast type of pointer, now that it is initialized.
|
||||
in_progress.into_arc()
|
||||
};
|
||||
|
||||
initialized_clone
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc<T>` with a clone of `value` in the provided allocator, returning an error if allocation fails
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
/// use std::sync::Arc;
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Arc<str, System> = Arc::try_clone_from_ref_in("hello", System)?;
|
||||
/// # Ok::<(), std::alloc::AllocError>(())
|
||||
/// ```
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
//#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn try_clone_from_ref_in(value: &T, alloc: A) -> Result<Arc<T, A>, AllocError> {
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueArcUninit<T, A> = UniqueArcUninit::try_new(value, alloc)?;
|
||||
|
||||
// Initialize with clone of value.
|
||||
let initialized_clone = unsafe {
|
||||
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
|
||||
value.clone_to_uninit(in_progress.data_ptr().cast());
|
||||
// Cast type of pointer, now that it is initialized.
|
||||
in_progress.into_arc()
|
||||
};
|
||||
|
||||
Ok(initialized_clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Arc<[mem::MaybeUninit<T>], A> {
|
||||
/// Converts to `Arc<[T]>`.
|
||||
///
|
||||
|
|
@ -4137,16 +4233,15 @@ fn data_offset_align(align: usize) -> usize {
|
|||
/// but will deallocate it (without dropping the value) when dropped.
|
||||
///
|
||||
/// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
struct UniqueArcUninit<T: ?Sized, A: Allocator> {
|
||||
ptr: NonNull<ArcInner<T>>,
|
||||
layout_for_value: Layout,
|
||||
alloc: Option<A>,
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
|
||||
/// Allocates an ArcInner with layout suitable to contain `for_value` or a clone of it.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
fn new(for_value: &T, alloc: A) -> UniqueArcUninit<T, A> {
|
||||
let layout = Layout::for_value(for_value);
|
||||
let ptr = unsafe {
|
||||
|
|
@ -4159,6 +4254,20 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
|
|||
Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) }
|
||||
}
|
||||
|
||||
/// Allocates an ArcInner with layout suitable to contain `for_value` or a clone of it,
|
||||
/// returning an error if allocation fails.
|
||||
fn try_new(for_value: &T, alloc: A) -> Result<UniqueArcUninit<T, A>, AllocError> {
|
||||
let layout = Layout::for_value(for_value);
|
||||
let ptr = unsafe {
|
||||
Arc::try_allocate_for_layout(
|
||||
layout,
|
||||
|layout_for_arcinner| alloc.allocate(layout_for_arcinner),
|
||||
|mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const ArcInner<T>),
|
||||
)?
|
||||
};
|
||||
Ok(Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) })
|
||||
}
|
||||
|
||||
/// Returns the pointer to be written into to initialize the [`Arc`].
|
||||
fn data_ptr(&mut self) -> *mut T {
|
||||
let offset = data_offset_align(self.layout_for_value.align());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue