#[cfg_attr(
feature = "bumpalo",
doc = "The [`copy_to_bump()`] function is useful for copying data into [`bumpalo`]-based allocations."
)]
pub unsafe trait UnsizedCopy {
#[inline]
fn unsized_copy_into<T: UnsizedCopyFrom<Source = Self>>(&self) -> T {
T::unsized_copy_from(self)
}
#[inline]
fn copy(&self) -> Self
where
Self: Sized,
{
unsafe { core::ptr::read(self) }
}
type Alignment: Sized;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self;
}
pub use domain_macros::UnsizedCopy;
macro_rules! impl_primitive_unsized_copy {
($($type:ty),+) => {
$(unsafe impl UnsizedCopy for $type {
type Alignment = Self;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
addr.cast::<Self>()
}
})+
};
}
impl_primitive_unsized_copy!((), bool, char);
impl_primitive_unsized_copy!(u8, u16, u32, u64, u128, usize);
impl_primitive_unsized_copy!(i8, i16, i32, i64, i128, isize);
impl_primitive_unsized_copy!(f32, f64);
unsafe impl<T: ?Sized> UnsizedCopy for &T {
type Alignment = Self;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
addr.cast::<Self>()
}
}
unsafe impl UnsizedCopy for str {
type Alignment = u8;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
self.as_bytes().ptr_with_addr(addr) as *const Self
}
}
unsafe impl<T: UnsizedCopy> UnsizedCopy for [T] {
type Alignment = T;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
core::ptr::slice_from_raw_parts(addr.cast::<T>(), self.len())
}
}
unsafe impl<T: UnsizedCopy, const N: usize> UnsizedCopy for [T; N] {
type Alignment = T;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
addr.cast::<Self>()
}
}
macro_rules! impl_unsized_copy_tuple {
($($type:ident),*; $last:ident) => {
unsafe impl<$($type: Copy,)* $last: ?Sized + UnsizedCopy>
UnsizedCopy for ($($type,)* $last,) {
type Alignment = ($($type,)* <$last>::Alignment,);
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
let (.., last) = self;
last.ptr_with_addr(addr) as *const Self
}
}
};
}
impl_unsized_copy_tuple!(; A);
impl_unsized_copy_tuple!(A; B);
impl_unsized_copy_tuple!(A, B; C);
impl_unsized_copy_tuple!(A, B, C; D);
impl_unsized_copy_tuple!(A, B, C, D; E);
impl_unsized_copy_tuple!(A, B, C, D, E; F);
impl_unsized_copy_tuple!(A, B, C, D, E, F; G);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G; H);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H; I);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I; J);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I, J; K);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I, J, K; L);
pub trait UnsizedCopyFrom: Sized {
type Source: ?Sized + UnsizedCopy;
fn unsized_copy_from(value: &Self::Source) -> Self;
}
#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::boxed::Box<T> {
type Source = T;
fn unsized_copy_from(value: &Self::Source) -> Self {
use std::alloc;
let layout = alloc::Layout::for_value(value);
let ptr = unsafe { alloc::alloc(layout) };
if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
let src = value as *const _ as *const u8;
unsafe { core::ptr::copy_nonoverlapping(src, ptr, layout.size()) };
let ptr = value.ptr_with_addr(ptr.cast()).cast_mut();
unsafe { std::boxed::Box::from_raw(ptr) }
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::rc::Rc<T> {
type Source = T;
fn unsized_copy_from(value: &Self::Source) -> Self {
use core::mem::MaybeUninit;
#[derive(Copy, Clone)]
#[repr(C)]
struct AlignedU8<T>([T; 0], u8);
let size = core::mem::size_of_val(value);
let rc: std::rc::Rc<[MaybeUninit<AlignedU8<T::Alignment>>]> =
(0..size).map(|_| MaybeUninit::uninit()).collect();
let src = value as *const _ as *const u8;
let dst = std::rc::Rc::into_raw(rc).cast_mut();
unsafe { core::ptr::copy_nonoverlapping(src, dst.cast(), size) };
let ptr = value.ptr_with_addr(dst.cast());
unsafe { std::rc::Rc::from_raw(ptr) }
}
}
#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::sync::Arc<T> {
type Source = T;
fn unsized_copy_from(value: &Self::Source) -> Self {
use core::mem::MaybeUninit;
#[derive(Copy, Clone)]
#[repr(C)]
struct AlignedU8<T>([T; 0], u8);
let size = core::mem::size_of_val(value);
let arc: std::sync::Arc<[MaybeUninit<AlignedU8<T::Alignment>>]> =
(0..size).map(|_| MaybeUninit::uninit()).collect();
let src = value as *const _ as *const u8;
let dst = std::sync::Arc::into_raw(arc).cast_mut();
unsafe { core::ptr::copy_nonoverlapping(src, dst.cast(), size) };
let ptr = value.ptr_with_addr(dst.cast());
unsafe { std::sync::Arc::from_raw(ptr) }
}
}
#[cfg(feature = "std")]
impl<T: UnsizedCopy> UnsizedCopyFrom for std::vec::Vec<T> {
type Source = [T];
fn unsized_copy_from(value: &Self::Source) -> Self {
let mut this = Self::with_capacity(value.len());
let src = value.as_ptr();
let dst = this.spare_capacity_mut() as *mut _ as *mut T;
unsafe { core::ptr::copy_nonoverlapping(src, dst, value.len()) };
unsafe { this.set_len(value.len()) };
this
}
}
#[cfg(feature = "std")]
impl UnsizedCopyFrom for std::string::String {
type Source = str;
fn unsized_copy_from(value: &Self::Source) -> Self {
value.into()
}
}
#[cfg(feature = "bumpalo")]
#[allow(clippy::mut_from_ref)] pub fn copy_to_bump<'a, T: ?Sized + UnsizedCopy>(
value: &T,
bump: &'a bumpalo::Bump,
) -> &'a mut T {
let layout = std::alloc::Layout::for_value(value);
let ptr = bump.alloc_layout(layout).as_ptr();
let src = value as *const _ as *const u8;
unsafe { core::ptr::copy_nonoverlapping(src, ptr, layout.size()) };
let ptr = value.ptr_with_addr(ptr.cast()).cast_mut();
unsafe { &mut *ptr }
}