Auto merge of #149079 - zachs18:clone_from_ref, r=Mark-Simulacrum
Add `Box::clone_from_ref` and similar under `feature(clone_from_ref)` Tracking issue: https://github.com/rust-lang/rust/issues/149075 Accepted ACP: https://github.com/rust-lang/libs-team/issues/483 This PR implements `clone_from_ref` (and `try_*` and `_*in` variants), to get a `Box<T>`, `Arc<T>`, or `Rc<T>` by cloning from a `&T` where `T: CloneToUninit`. The "Implement..." commits replace some ad-hoc conversions with `clone_from_ref` variants, which can be split out to a separate PR if desired. This PR will conflict with https://github.com/rust-lang/rust/pull/148769 due to usage of `Layout::dangling` (which that PR is renaming to `dangling_ptr`), so they should not be rolled up together, and the one which merges later will need to be amended.
This commit is contained in:
commit
1be6b13be7
13 changed files with 368 additions and 104 deletions
|
|
@ -184,7 +184,6 @@
|
|||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::clone::CloneToUninit;
|
||||
use core::cmp::Ordering;
|
||||
use core::error::{self, Error};
|
||||
|
|
@ -733,6 +732,128 @@ impl<T, A: Allocator> Box<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit> Box<T> {
|
||||
/// Allocates memory on the heap then clones `src` into it.
|
||||
///
|
||||
/// This doesn't actually allocate if `src` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
///
|
||||
/// let hello: Box<str> = Box::clone_from_ref("hello");
|
||||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn clone_from_ref(src: &T) -> Box<T> {
|
||||
Box::clone_from_ref_in(src, Global)
|
||||
}
|
||||
|
||||
/// Allocates memory on the heap then clones `src` into it, returning an error if allocation fails.
|
||||
///
|
||||
/// This doesn't actually allocate if `src` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// let hello: Box<str> = Box::try_clone_from_ref("hello")?;
|
||||
/// # Ok::<(), std::alloc::AllocError>(())
|
||||
/// ```
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
//#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn try_clone_from_ref(src: &T) -> Result<Box<T>, AllocError> {
|
||||
Box::try_clone_from_ref_in(src, Global)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit, A: Allocator> Box<T, A> {
|
||||
/// Allocates memory in the given allocator then clones `src` into it.
|
||||
///
|
||||
/// This doesn't actually allocate if `src` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Box<str, System> = Box::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")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn clone_from_ref_in(src: &T, alloc: A) -> Box<T, A> {
|
||||
let layout = Layout::for_value::<T>(src);
|
||||
match Box::try_clone_from_ref_in(src, alloc) {
|
||||
Ok(bx) => bx,
|
||||
Err(_) => handle_alloc_error(layout),
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates memory in the given allocator then clones `src` into it, returning an error if allocation fails.
|
||||
///
|
||||
/// This doesn't actually allocate if `src` is zero-sized.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Box<str, System> = Box::try_clone_from_ref_in("hello", System)?;
|
||||
/// # Ok::<(), std::alloc::AllocError>(())
|
||||
/// ```
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
//#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn try_clone_from_ref_in(src: &T, alloc: A) -> Result<Box<T, A>, AllocError> {
|
||||
struct DeallocDropGuard<'a, A: Allocator>(Layout, &'a A, NonNull<u8>);
|
||||
impl<'a, A: Allocator> Drop for DeallocDropGuard<'a, A> {
|
||||
fn drop(&mut self) {
|
||||
let &mut DeallocDropGuard(layout, alloc, ptr) = self;
|
||||
// Safety: `ptr` was allocated by `*alloc` with layout `layout`
|
||||
unsafe {
|
||||
alloc.deallocate(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
let layout = Layout::for_value::<T>(src);
|
||||
let (ptr, guard) = if layout.size() == 0 {
|
||||
(layout.dangling(), None)
|
||||
} else {
|
||||
// Safety: layout is non-zero-sized
|
||||
let ptr = alloc.allocate(layout)?.cast();
|
||||
(ptr, Some(DeallocDropGuard(layout, &alloc, ptr)))
|
||||
};
|
||||
let ptr = ptr.as_ptr();
|
||||
// Safety: `*ptr` is newly allocated, correctly aligned to `align_of_val(src)`,
|
||||
// and is valid for writes for `size_of_val(src)`.
|
||||
// If this panics, then `guard` will deallocate for us (if allocation occuured)
|
||||
unsafe {
|
||||
<T as CloneToUninit>::clone_to_uninit(src, ptr);
|
||||
}
|
||||
// Defuse the deallocate guard
|
||||
core::mem::forget(guard);
|
||||
// Safety: We just initialized `*ptr` as a clone of `src`
|
||||
Ok(unsafe { Box::from_raw_in(ptr.with_metadata_of(src), alloc) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<[T]> {
|
||||
/// Constructs a new boxed slice with uninitialized contents.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
use core::any::Any;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::clone::TrivialClone;
|
||||
use core::error::Error;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::fmt;
|
||||
use core::mem;
|
||||
use core::pin::Pin;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::{fmt, ptr};
|
||||
|
||||
use crate::alloc::Allocator;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::borrow::Cow;
|
||||
use crate::boxed::Box;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::raw_vec::RawVec;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::str::from_boxed_utf8_unchecked;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::string::String;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use crate::vec::Vec;
|
||||
|
|
@ -62,35 +56,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Specialization trait used for `From<&[T]>`.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
trait BoxFromSlice<T> {
|
||||
fn from_slice(slice: &[T]) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
|
||||
#[inline]
|
||||
default fn from_slice(slice: &[T]) -> Self {
|
||||
slice.to_vec().into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<T: TrivialClone> BoxFromSlice<T> for Box<[T]> {
|
||||
#[inline]
|
||||
fn from_slice(slice: &[T]) -> Self {
|
||||
let len = slice.len();
|
||||
let buf = RawVec::with_capacity(len);
|
||||
// SAFETY: since `T` implements `TrivialClone`, this is sound and
|
||||
// equivalent to the above.
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
|
||||
buf.into_box(slice.len()).assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "box_from_slice", since = "1.17.0")]
|
||||
impl<T: Clone> From<&[T]> for Box<[T]> {
|
||||
|
|
@ -109,7 +74,7 @@ impl<T: Clone> From<&[T]> for Box<[T]> {
|
|||
/// ```
|
||||
#[inline]
|
||||
fn from(slice: &[T]) -> Box<[T]> {
|
||||
<Self as BoxFromSlice<T>>::from_slice(slice)
|
||||
Box::clone_from_ref(slice)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +135,7 @@ impl From<&str> for Box<str> {
|
|||
/// ```
|
||||
#[inline]
|
||||
fn from(s: &str) -> Box<str> {
|
||||
unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
|
||||
Box::clone_from_ref(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -766,8 +766,7 @@ impl From<&CStr> for Box<CStr> {
|
|||
/// Converts a `&CStr` into a `Box<CStr>`,
|
||||
/// by copying the contents into a newly allocated [`Box`].
|
||||
fn from(s: &CStr) -> Box<CStr> {
|
||||
let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
|
||||
unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
|
||||
Box::clone_from_ref(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -243,9 +243,9 @@
|
|||
|
||||
use core::any::Any;
|
||||
use core::cell::{Cell, CloneFromCell};
|
||||
use core::clone::UseCloned;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::clone::{CloneToUninit, TrivialClone};
|
||||
use core::clone::TrivialClone;
|
||||
use core::clone::{CloneToUninit, UseCloned};
|
||||
use core::cmp::Ordering;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::abort;
|
||||
|
|
@ -1290,6 +1290,104 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit> Rc<T> {
|
||||
/// Constructs a new `Rc<T>` with a clone of `value`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let hello: Rc<str> = Rc::clone_from_ref("hello");
|
||||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "clone_from_ref", issue = "149075")]
|
||||
pub fn clone_from_ref(value: &T) -> Rc<T> {
|
||||
Rc::clone_from_ref_in(value, Global)
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc<T>` with a clone of `value`, returning an error if allocation fails
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let hello: Rc<str> = Rc::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<Rc<T>, AllocError> {
|
||||
Rc::try_clone_from_ref_in(value, Global)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + CloneToUninit, A: Allocator> Rc<T, A> {
|
||||
/// Constructs a new `Rc<T>` with a clone of `value` in the provided allocator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clone_from_ref)]
|
||||
/// #![feature(allocator_api)]
|
||||
/// use std::rc::Rc;
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Rc<str, System> = Rc::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) -> Rc<T, A> {
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueRcUninit<T, A> = UniqueRcUninit::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_rc()
|
||||
};
|
||||
|
||||
initialized_clone
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc<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::rc::Rc;
|
||||
/// use std::alloc::System;
|
||||
///
|
||||
/// let hello: Rc<str, System> = Rc::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<Rc<T, A>, AllocError> {
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueRcUninit<T, A> = UniqueRcUninit::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_rc()
|
||||
};
|
||||
|
||||
Ok(initialized_clone)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> {
|
||||
/// Converts to `Rc<[T]>`.
|
||||
///
|
||||
|
|
@ -1969,22 +2067,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Rc<T, A> {
|
|||
|
||||
if Rc::strong_count(this) != 1 {
|
||||
// Gotta clone the data, there are other Rcs.
|
||||
|
||||
let this_data_ref: &T = &**this;
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueRcUninit<T, A> =
|
||||
UniqueRcUninit::new(this_data_ref, this.alloc.clone());
|
||||
|
||||
// Initialize with clone of this.
|
||||
let initialized_clone = unsafe {
|
||||
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
|
||||
this_data_ref.clone_to_uninit(in_progress.data_ptr().cast());
|
||||
// Cast type of pointer, now that it is initialized.
|
||||
in_progress.into_rc()
|
||||
};
|
||||
|
||||
// Replace `this` with newly constructed Rc.
|
||||
*this = initialized_clone;
|
||||
*this = Rc::clone_from_ref_in(&**this, this.alloc.clone());
|
||||
} else if Rc::weak_count(this) != 0 {
|
||||
// Can just steal the data, all that's left is Weaks
|
||||
|
||||
|
|
@ -4358,16 +4441,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc<T, A> {
|
|||
/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic.
|
||||
/// It is nearly a duplicate of `UniqueRc<MaybeUninit<T>, A>` except that it allows `T: !Sized`,
|
||||
/// which `MaybeUninit` does not.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
struct UniqueRcUninit<T: ?Sized, A: Allocator> {
|
||||
ptr: NonNull<RcInner<T>>,
|
||||
layout_for_value: Layout,
|
||||
alloc: Option<A>,
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
|
||||
/// Allocates a RcInner 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) -> UniqueRcUninit<T, A> {
|
||||
let layout = Layout::for_value(for_value);
|
||||
let ptr = unsafe {
|
||||
|
|
@ -4380,6 +4462,20 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
|
|||
Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) }
|
||||
}
|
||||
|
||||
/// Allocates a RcInner 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<UniqueRcUninit<T, A>, AllocError> {
|
||||
let layout = Layout::for_value(for_value);
|
||||
let ptr = unsafe {
|
||||
Rc::try_allocate_for_layout(
|
||||
layout,
|
||||
|layout_for_rc_inner| alloc.allocate(layout_for_rc_inner),
|
||||
|mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcInner<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 [`Rc`].
|
||||
fn data_ptr(&mut self) -> *mut T {
|
||||
let offset = data_offset_align(self.layout_for_value.align());
|
||||
|
|
@ -4402,7 +4498,6 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<T: ?Sized, A: Allocator> Drop for UniqueRcUninit<T, A> {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY:
|
||||
|
|
|
|||
|
|
@ -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]>`.
|
||||
///
|
||||
|
|
@ -2406,19 +2502,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> {
|
|||
// deallocated.
|
||||
if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() {
|
||||
// Another strong pointer exists, so we must clone.
|
||||
|
||||
let this_data_ref: &T = &**this;
|
||||
// `in_progress` drops the allocation if we panic before finishing initializing it.
|
||||
let mut in_progress: UniqueArcUninit<T, A> =
|
||||
UniqueArcUninit::new(this_data_ref, this.alloc.clone());
|
||||
|
||||
let initialized_clone = unsafe {
|
||||
// Clone. If the clone panics, `in_progress` will be dropped and clean up.
|
||||
this_data_ref.clone_to_uninit(in_progress.data_ptr().cast());
|
||||
// Cast type of pointer, now that it is initialized.
|
||||
in_progress.into_arc()
|
||||
};
|
||||
*this = initialized_clone;
|
||||
*this = Arc::clone_from_ref_in(&**this, this.alloc.clone());
|
||||
} else if this.inner().weak.load(Relaxed) != 1 {
|
||||
// Relaxed suffices in the above because this is fundamentally an
|
||||
// optimization: we are always racing with weak pointers being
|
||||
|
|
@ -4137,16 +4221,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 +4242,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());
|
||||
|
|
|
|||
|
|
@ -1285,8 +1285,7 @@ impl From<&OsStr> for Box<OsStr> {
|
|||
/// Copies the string into a newly allocated <code>[Box]<[OsStr]></code>.
|
||||
#[inline]
|
||||
fn from(s: &OsStr) -> Box<OsStr> {
|
||||
let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
|
||||
unsafe { Box::from_raw(rw) }
|
||||
Box::clone_from_ref(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@
|
|||
// tidy-alphabetical-start
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(clone_from_ref)]
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(slice_concat_trait)]
|
||||
|
|
|
|||
|
|
@ -1877,9 +1877,7 @@ impl From<&Path> for Box<Path> {
|
|||
///
|
||||
/// This will allocate and clone `path` to it.
|
||||
fn from(path: &Path) -> Box<Path> {
|
||||
let boxed: Box<OsStr> = path.inner.into();
|
||||
let rw = Box::into_raw(boxed) as *mut Path;
|
||||
unsafe { Box::from_raw(rw) }
|
||||
Box::clone_from_ref(path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -321,12 +321,6 @@ impl Slice {
|
|||
self.inner.clone_into(&mut buf.inner)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_box(&self) -> Box<Slice> {
|
||||
let boxed: Box<[u8]> = self.inner.into();
|
||||
unsafe { mem::transmute(boxed) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty_box() -> Box<Slice> {
|
||||
let boxed: Box<[u8]> = Default::default();
|
||||
|
|
|
|||
|
|
@ -271,11 +271,6 @@ impl Slice {
|
|||
self.inner.clone_into(&mut buf.inner)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_box(&self) -> Box<Slice> {
|
||||
unsafe { mem::transmute(self.inner.into_box()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty_box() -> Box<Slice> {
|
||||
unsafe { mem::transmute(Wtf8::empty_box()) }
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ LL - x: (),
|
|||
LL - })),
|
||||
LL + wtf: Some(Box::new_in(_, _)),
|
||||
|
|
||||
= and 13 other candidates
|
||||
= and 15 other candidates
|
||||
help: consider using the `Default` trait
|
||||
|
|
||||
LL - wtf: Some(Box(U {
|
||||
|
|
@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed();
|
|||
LL - let _ = Box {};
|
||||
LL + let _ = Box::new_in(_, _);
|
||||
|
|
||||
= and 14 other candidates
|
||||
= and 16 other candidates
|
||||
help: consider using the `Default` trait
|
||||
|
|
||||
LL - let _ = Box {};
|
||||
|
|
@ -146,7 +146,7 @@ LL + let _ = Box::<i32>::map(_, _);
|
|||
LL - let _ = Box::<i32> {};
|
||||
LL + let _ = Box::<i32>::into_inner(_);
|
||||
|
|
||||
= and 5 other candidates
|
||||
= and 7 other candidates
|
||||
help: consider using the `Default` trait
|
||||
|
|
||||
LL - let _ = Box::<i32> {};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ LL - x: (),
|
|||
LL - })),
|
||||
LL + wtf: Some(Box::new_in(_, _)),
|
||||
|
|
||||
= and 13 other candidates
|
||||
= and 15 other candidates
|
||||
help: consider using the `Default` trait
|
||||
|
|
||||
LL - wtf: Some(Box(U {
|
||||
|
|
@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed();
|
|||
LL - let _ = Box {};
|
||||
LL + let _ = Box::new_in(_, _);
|
||||
|
|
||||
= and 14 other candidates
|
||||
= and 16 other candidates
|
||||
help: consider using the `Default` trait
|
||||
|
|
||||
LL - let _ = Box {};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ LL - x: (),
|
|||
LL - })),
|
||||
LL + wtf: Some(Box::new_in(_, _)),
|
||||
│
|
||||
╰ and 13 other candidates
|
||||
╰ and 15 other candidates
|
||||
help: consider using the `Default` trait
|
||||
╭╴
|
||||
LL - wtf: Some(Box(U {
|
||||
|
|
@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed();
|
|||
LL - let _ = Box {};
|
||||
LL + let _ = Box::new_in(_, _);
|
||||
│
|
||||
╰ and 14 other candidates
|
||||
╰ and 16 other candidates
|
||||
help: consider using the `Default` trait
|
||||
╭╴
|
||||
LL - let _ = Box {};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue