Skip to content

Commit

Permalink
Add new_uninit and assume_init on Box, Rc, and Arc
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Aug 16, 2019
1 parent 1613fda commit 7b02b9f
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/liballoc/boxed.rs
Expand Up @@ -93,6 +93,7 @@ use core::ops::{
use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll};

use crate::alloc;
use crate::vec::Vec;
use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked;
Expand Down Expand Up @@ -121,6 +122,32 @@ impl<T> Box<T> {
box x
}

/// Construct 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);
///
/// Box::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
let ptr = unsafe { alloc::alloc(layout) };
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
Box(unique.cast())
}

/// 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")]
Expand All @@ -130,6 +157,40 @@ impl<T> Box<T> {
}
}

impl<T> Box<mem::MaybeUninit<T>> {
/// Convert 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.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five: Box<u32> = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// Box::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Box<T> {
Box(Box::into_unique(this).cast())
}
}

impl<T: ?Sized> Box<T> {
/// Constructs a box from a raw pointer.
///
Expand Down
81 changes: 81 additions & 0 deletions src/liballoc/rc.rs
Expand Up @@ -327,6 +327,43 @@ impl<T> Rc<T> {
}))
}

/// Construct 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);
///
/// Rc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
let layout = Layout::new::<RcBox<mem::MaybeUninit<T>>>();
unsafe {
let mut ptr = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout))
.cast::<RcBox<mem::MaybeUninit<T>>>();
ptr::write(&mut ptr.as_mut().strong, Cell::new(1));
ptr::write(&mut ptr.as_mut().weak, Cell::new(1));
Rc {
ptr,
phantom: PhantomData,
}
}
}

/// 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")]
Expand Down Expand Up @@ -377,6 +414,48 @@ impl<T> Rc<T> {
}
}

impl<T> Rc<mem::MaybeUninit<T>> {
/// Convert 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.
///
/// # 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);
///
/// Rc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Rc<T> {
let ptr = this.ptr.cast();
mem::forget(this);
Rc {
ptr,
phantom: PhantomData,
}
}
}

impl<T: ?Sized> Rc<T> {
/// Consumes the `Rc`, returning the wrapped pointer.
///
Expand Down Expand Up @@ -582,6 +661,8 @@ impl<T: ?Sized> Rc<T> {
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut x = Rc::new(String::new());
Expand Down
81 changes: 81 additions & 0 deletions src/liballoc/sync.rs
Expand Up @@ -311,6 +311,43 @@ impl<T> Arc<T> {
Self::from_inner(Box::into_raw_non_null(x))
}

/// Construct a Arc box 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);
///
/// Arc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
let layout = Layout::new::<ArcInner<mem::MaybeUninit<T>>>();
unsafe {
let mut ptr = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout))
.cast::<ArcInner<mem::MaybeUninit<T>>>();
ptr::write(&mut ptr.as_mut().strong, atomic::AtomicUsize::new(1));
ptr::write(&mut ptr.as_mut().weak, atomic::AtomicUsize::new(1));
Arc {
ptr,
phantom: PhantomData,
}
}
}

/// 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")]
Expand Down Expand Up @@ -361,6 +398,48 @@ impl<T> Arc<T> {
}
}

impl<T> Arc<mem::MaybeUninit<T>> {
/// Convert 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.
///
/// # 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);
///
/// Arc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Arc<T> {
let ptr = this.ptr.cast();
mem::forget(this);
Arc {
ptr,
phantom: PhantomData,
}
}
}

impl<T: ?Sized> Arc<T> {
/// Consumes the `Arc`, returning the wrapped pointer.
///
Expand Down Expand Up @@ -967,6 +1046,8 @@ impl<T: ?Sized> Arc<T> {
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut x = Arc::new(String::new());
Expand Down
8 changes: 8 additions & 0 deletions src/libcore/ptr/unique.rs
Expand Up @@ -122,6 +122,14 @@ impl<T: ?Sized> Unique<T> {
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}

/// Cast 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")]
Expand Down

0 comments on commit 7b02b9f

Please sign in to comment.