Add Box::(try_)clone_from_ref(_in)

This commit is contained in:
Zachary S 2024-11-15 00:47:22 -06:00
parent 07bdbaedc6
commit 9e497b6071
5 changed files with 130 additions and 8 deletions

View file

@ -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.
///

View file

@ -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)]

View file

@ -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> {};

View file

@ -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 {};

View file

@ -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 {};