Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 122 additions & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
///
Expand Down
43 changes: 4 additions & 39 deletions library/alloc/src/boxed/convert.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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]> {
Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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)
}
}

Expand Down
3 changes: 1 addition & 2 deletions library/alloc/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Loading
Loading