mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Rollup merge of #62451 - SimonSapin:new_uninit, r=RalfJung
Add APIs for uninitialized Box, Rc, and Arc. (Plus get_mut_unchecked) Assigning `MaybeUninit::<Foo>::uninit()` to a local variable is usually free, even when `size_of::<Foo>()` is large. However, passing it for example to `Arc::new` [causes at least one copy](https://youtu.be/F1AquroPfcI?t=4116) (from the stack to the newly allocated heap memory) even though there is no meaningful data. It is theoretically possible that a Sufficiently Advanced Compiler could optimize this copy away, but this is [reportedly unlikely to happen soon in LLVM](https://youtu.be/F1AquroPfcI?t=5431). This PR proposes two sets of features: * Constructors for containers (`Box`, `Rc`, `Arc`) of `MaybeUninit<T>` or `[MaybeUninit<T>]` that do not initialized the data, and unsafe conversions to the known-initialized types (without `MaybeUninit`). The constructors are guaranteed not to make unnecessary copies. * On `Rc` and `Arc`, an unsafe `get_mut_unchecked` method that provides `&mut T` access without checking the reference count. `Arc::get_mut` involves multiple atomic operations whose cost can be non-trivial. `Rc::get_mut` is less costly, but we add `Rc::get_mut_unchecked` anyway for symmetry with `Arc`. These can be useful independently, but they will presumably be typical when the new constructors of `Rc` and `Arc` are used. An alternative with a safe API would be to introduce `UniqueRc` and `UniqueArc` types that have the same memory layout as `Rc` and `Arc` (and so zero-cost conversion to them) but are guaranteed to have only one reference. But introducing entire new types feels “heavier” than new constructors on existing types, and initialization of `MaybeUninit<T>` typically requires unsafe code anyway. Summary of new APIs (all unstable in this PR): ```rust impl<T> Box<T> { pub fn new_uninit() -> Box<MaybeUninit<T>> {…} } impl<T> Box<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Box<T> {…} } impl<T> Box<[T]> { pub fn new_uninit_slice(len: usize) -> Box<[MaybeUninit<T>]> {…} } impl<T> Box<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Box<[T]> {…} } impl<T> Rc<T> { pub fn new_uninit() -> Rc<MaybeUninit<T>> {…} } impl<T> Rc<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Rc<T> {…} } impl<T> Rc<[T]> { pub fn new_uninit_slice(len: usize) -> Rc<[MaybeUninit<T>]> {…} } impl<T> Rc<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Rc<[T]> {…} } impl<T> Arc<T> { pub fn new_uninit() -> Arc<MaybeUninit<T>> {…} } impl<T> Arc<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Arc<T> {…} } impl<T> Arc<[T]> { pub fn new_uninit_slice(len: usize) -> Arc<[MaybeUninit<T>]> {…} } impl<T> Arc<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Arc<[T]> {…} } impl<T: ?Sized> Rc<T> { pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {…} } impl<T: ?Sized> Arc<T> { pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {…} } ```
This commit is contained in:
commit
a3b6e8ef99
@ -91,8 +91,10 @@ use core::ops::{
|
||||
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
|
||||
};
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::slice;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use crate::alloc::{self, Global, Alloc};
|
||||
use crate::vec::Vec;
|
||||
use crate::raw_vec::RawVec;
|
||||
use crate::str::from_boxed_utf8_unchecked;
|
||||
@ -121,6 +123,34 @@ impl<T> Box<T> {
|
||||
box x
|
||||
}
|
||||
|
||||
/// Constructs a new box with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut five = Box::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// five.as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
|
||||
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
|
||||
let ptr = unsafe {
|
||||
Global.alloc(layout)
|
||||
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
|
||||
};
|
||||
Box(ptr.cast().into())
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `x` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
@ -130,6 +160,111 @@ impl<T> Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<[T]> {
|
||||
/// Constructs a new boxed slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// values[0].as_mut_ptr().write(1);
|
||||
/// values[1].as_mut_ptr().write(2);
|
||||
/// values[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
|
||||
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
|
||||
let ptr = unsafe { alloc::alloc(layout) };
|
||||
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
|
||||
Box(Unique::from(slice))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Box<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut five = Box::<u32>::new_uninit();
|
||||
///
|
||||
/// let five: Box<u32> = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// five.as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Box<T> {
|
||||
Box(Box::into_unique(self).cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Box<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Box<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the values
|
||||
/// really are in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
///
|
||||
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// values[0].as_mut_ptr().write(1);
|
||||
/// values[1].as_mut_ptr().write(2);
|
||||
/// values[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Box<[T]> {
|
||||
Box(Unique::new_unchecked(Box::into_raw(self) as _))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Box<T> {
|
||||
/// Constructs a box from a raw pointer.
|
||||
///
|
||||
|
@ -327,6 +327,37 @@ impl<T> Rc<T> {
|
||||
}))
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc` with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut five = Rc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
|
||||
unsafe {
|
||||
Rc::from_ptr(Rc::allocate_for_layout(
|
||||
Layout::new::<T>(),
|
||||
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `value` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
@ -377,6 +408,118 @@ impl<T> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<[T]> {
|
||||
/// Constructs a new reference-counted slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
|
||||
unsafe {
|
||||
Rc::from_ptr(Rc::allocate_for_slice(len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Rc<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut five = Rc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Rc<T> {
|
||||
Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rc<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Rc<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Rc<[T]> {
|
||||
Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Consumes the `Rc`, returning the wrapped pointer.
|
||||
///
|
||||
@ -560,13 +703,46 @@ impl<T: ?Sized> Rc<T> {
|
||||
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
|
||||
if Rc::is_unique(this) {
|
||||
unsafe {
|
||||
Some(&mut this.ptr.as_mut().value)
|
||||
Some(Rc::get_mut_unchecked(this))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner value,
|
||||
/// without any check.
|
||||
///
|
||||
/// See also [`get_mut`], which is safe and does appropriate checks.
|
||||
///
|
||||
/// [`get_mut`]: struct.Rc.html#method.get_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced
|
||||
/// for the duration of the returned borrow.
|
||||
/// This is trivially the case if no such pointers exist,
|
||||
/// for example immediately after `Rc::new`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut x = Rc::new(String::new());
|
||||
/// unsafe {
|
||||
/// Rc::get_mut_unchecked(&mut x).push_str("foo")
|
||||
/// }
|
||||
/// assert_eq!(*x, "foo");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
&mut this.ptr.as_mut().value
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[stable(feature = "ptr_eq", since = "1.17.0")]
|
||||
/// Returns `true` if the two `Rc`s point to the same value (not
|
||||
@ -704,11 +880,11 @@ impl Rc<dyn Any> {
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Allocates an `RcBox<T>` with sufficient space for
|
||||
/// an unsized value where the value has the layout provided.
|
||||
/// a possibly-unsized value where the value has the layout provided.
|
||||
///
|
||||
/// The function `mem_to_rcbox` is called with the data pointer
|
||||
/// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
|
||||
unsafe fn allocate_for_unsized(
|
||||
unsafe fn allocate_for_layout(
|
||||
value_layout: Layout,
|
||||
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>
|
||||
) -> *mut RcBox<T> {
|
||||
@ -737,7 +913,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
/// Allocates an `RcBox<T>` with sufficient space for an unsized value
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
|
||||
// Allocate for the `RcBox<T>` using the given value.
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
|
||||
)
|
||||
@ -768,7 +944,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
impl<T> Rc<[T]> {
|
||||
/// Allocates an `RcBox<[T]>` with the given length.
|
||||
unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::array::<T>(len).unwrap(),
|
||||
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>,
|
||||
)
|
||||
|
@ -311,6 +311,37 @@ impl<T> Arc<T> {
|
||||
Self::from_inner(Box::into_raw_non_null(x))
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc` with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut five = Arc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
|
||||
unsafe {
|
||||
Arc::from_ptr(Arc::allocate_for_layout(
|
||||
Layout::new::<T>(),
|
||||
|mem| mem as *mut ArcInner<mem::MaybeUninit<T>>,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Arc<T>>`. If `T` does not implement `Unpin`, then
|
||||
/// `data` will be pinned in memory and unable to be moved.
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
@ -361,6 +392,118 @@ impl<T> Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<[T]> {
|
||||
/// Constructs a new reference-counted slice with uninitialized contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
|
||||
unsafe {
|
||||
Arc::from_ptr(Arc::allocate_for_slice(len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<mem::MaybeUninit<T>> {
|
||||
/// Converts to `Arc<T>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut five = Arc::<u32>::new_uninit();
|
||||
///
|
||||
/// let five = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
|
||||
///
|
||||
/// five.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*five, 5)
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Arc<T> {
|
||||
Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Arc<[mem::MaybeUninit<T>]> {
|
||||
/// Converts to `Arc<[T]>`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// As with [`MaybeUninit::assume_init`],
|
||||
/// it is up to the caller to guarantee that the value
|
||||
/// really is in an initialized state.
|
||||
/// Calling this when the content is not yet fully initialized
|
||||
/// causes immediate undefined behavior.
|
||||
///
|
||||
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(new_uninit)]
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut values = Arc::<[u32]>::new_uninit_slice(3);
|
||||
///
|
||||
/// let values = unsafe {
|
||||
/// // Deferred initialization:
|
||||
/// Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
|
||||
/// Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
|
||||
/// Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
|
||||
///
|
||||
/// values.assume_init()
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(*values, [1, 2, 3])
|
||||
/// ```
|
||||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
#[inline]
|
||||
pub unsafe fn assume_init(self) -> Arc<[T]> {
|
||||
Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Consumes the `Arc`, returning the wrapped pointer.
|
||||
///
|
||||
@ -593,11 +736,11 @@ impl<T: ?Sized> Arc<T> {
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Allocates an `ArcInner<T>` with sufficient space for
|
||||
/// an unsized value where the value has the layout provided.
|
||||
/// a possibly-unsized value where the value has the layout provided.
|
||||
///
|
||||
/// The function `mem_to_arcinner` is called with the data pointer
|
||||
/// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
|
||||
unsafe fn allocate_for_unsized(
|
||||
unsafe fn allocate_for_layout(
|
||||
value_layout: Layout,
|
||||
mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>
|
||||
) -> *mut ArcInner<T> {
|
||||
@ -625,7 +768,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
/// Allocates an `ArcInner<T>` with sufficient space for an unsized value.
|
||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
|
||||
// Allocate for the `ArcInner<T>` using the given value.
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>,
|
||||
)
|
||||
@ -656,7 +799,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
impl<T> Arc<[T]> {
|
||||
/// Allocates an `ArcInner<[T]>` with the given length.
|
||||
unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
|
||||
Self::allocate_for_unsized(
|
||||
Self::allocate_for_layout(
|
||||
Layout::array::<T>(len).unwrap(),
|
||||
|mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>,
|
||||
)
|
||||
@ -945,13 +1088,46 @@ impl<T: ?Sized> Arc<T> {
|
||||
// the Arc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
unsafe {
|
||||
Some(&mut this.ptr.as_mut().data)
|
||||
Some(Arc::get_mut_unchecked(this))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the inner value,
|
||||
/// without any check.
|
||||
///
|
||||
/// See also [`get_mut`], which is safe and does appropriate checks.
|
||||
///
|
||||
/// [`get_mut`]: struct.Arc.html#method.get_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Any other `Arc` or [`Weak`] pointers to the same value must not be dereferenced
|
||||
/// for the duration of the returned borrow.
|
||||
/// This is trivially the case if no such pointers exist,
|
||||
/// for example immediately after `Arc::new`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(get_mut_unchecked)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut x = Arc::new(String::new());
|
||||
/// unsafe {
|
||||
/// Arc::get_mut_unchecked(&mut x).push_str("foo")
|
||||
/// }
|
||||
/// assert_eq!(*x, "foo");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
&mut this.ptr.as_mut().data
|
||||
}
|
||||
|
||||
/// Determine whether this is the unique reference (including weak refs) to
|
||||
/// the underlying data.
|
||||
///
|
||||
|
@ -122,6 +122,14 @@ impl<T: ?Sized> Unique<T> {
|
||||
pub unsafe fn as_mut(&mut self) -> &mut T {
|
||||
&mut *self.as_ptr()
|
||||
}
|
||||
|
||||
/// Casts to a pointer of another type.
|
||||
#[inline]
|
||||
pub const fn cast<U>(self) -> Unique<U> {
|
||||
unsafe {
|
||||
Unique::new_unchecked(self.as_ptr() as *mut U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "ptr_internals", issue = "0")]
|
||||
|
Loading…
Reference in New Issue
Block a user