use crate::Own;
#[cfg(feature = "alloc")]
use alloc::{alloc::{Global, handle_alloc_error}, boxed::Box, vec::Vec, string::String};
#[cfg(feature = "alloc")]
use core::alloc::{Allocator, Layout};
use core::mem::{ManuallyDrop, MaybeDangling, MaybeUninit, transmute_prefix as transmute};
use core::ops::DerefMut;
use core::ptr;
use core::ptr::{NonNull, metadata};
pub const trait DerefMove: DerefMut<Target: Sized> {
fn deref_move(self) -> Self::Target;
}
pub const unsafe trait DerefOwn: DerefMut {
unsafe fn deref_own(self: &mut ManuallyDrop<Self>) -> Own<'_, Self::Target>;
fn forget_contents(this: MaybeDangling<Self>);
unsafe fn forget_contents_in_place(this: &mut ManuallyDrop<Self>) where Self: Sized {
unsafe {
Self::forget_contents(transmute(ManuallyDrop::take(this)))
}
}
}
pub trait Take<T: ?Sized> {
fn take(val: Own<T>) -> Self;
}
#[cfg(feature = "alloc")]
pub trait TakeIn<T: ?Sized, A: Allocator> {
fn take_in(val: Own<T>, alloc: A) -> Self;
}
impl<T: Sized> Take<T> for T {
#[inline(always)]
fn take(val: Own<T>) -> Self {
val.deref_move()
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized> Take<T> for Box<T> {
#[inline(always)]
fn take(val: Own<T>) -> Self {
Self::take_in(val, Global)
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized, A: Allocator> TakeIn<T, A> for Box<T, A> {
#[inline(always)]
fn take_in(val: Own<T>, alloc: A) -> Self {
let val = MaybeDangling::new(val);
let borrow = &**val.as_ref();
let meta = metadata(borrow);
let layout = Layout::for_value(borrow);
let this_ptr = match alloc.allocate(layout) {
Ok(m) => NonNull::<T>::from_raw_parts(m.as_non_null_ptr(), meta),
Err(_) => handle_alloc_error(layout),
};
unsafe { ptr::copy_nonoverlapping((borrow as *const T).cast::<u8>(), this_ptr.cast().as_ptr(), layout.size()); }
DerefOwn::forget_contents(val);
unsafe { Box::from_raw_in(this_ptr.as_ptr(), alloc) }
}
}
#[cfg(feature = "alloc")]
impl<T: Sized> Take<[T]> for Vec<T> {
#[inline(always)]
fn take(val: Own<[T]>) -> Self {
let val = MaybeDangling::new(val);
let borrow = &**val.as_ref();
let len = borrow.len();
let mut this: Vec<MaybeUninit<T>> = Box::new_uninit_slice(len).into_vec();
let this_ptr = this[0].as_mut_ptr();
unsafe { ptr::copy_nonoverlapping(&raw const borrow[0], this_ptr, len); }
DerefOwn::forget_contents(val);
unsafe { transmute(this) }
}
}
#[cfg(feature = "alloc")]
impl<T: Sized, A: Allocator> TakeIn<[T], A> for Vec<T, A> {
#[inline(always)]
fn take_in(val: Own<[T]>, alloc: A) -> Self {
let val = MaybeDangling::new(val);
let borrow = &**val.as_ref();
let len = borrow.len();
let mut this: Vec<MaybeUninit<T>, A> = Box::new_uninit_slice_in(len, alloc).into_vec();
let this_ptr = this[0].as_mut_ptr();
unsafe { ptr::copy_nonoverlapping(&raw const borrow[0], this_ptr, len); }
DerefOwn::forget_contents(val);
unsafe { transmute(this) }
}
}
#[cfg(feature = "alloc")]
impl Take<str> for String {
#[inline(always)]
fn take(val: Own<str>) -> Self {
let val = MaybeDangling::new(val);
let borrow = &**val.as_ref();
let len = borrow.len();
let mut this: Vec<MaybeUninit<u8>> = Box::new_uninit_slice(len).into_vec();
let this_ptr = this[0].as_mut_ptr();
unsafe { ptr::copy_nonoverlapping(&raw const borrow.as_bytes()[0], this_ptr, len); }
DerefOwn::forget_contents(val);
unsafe { String::from_utf8_unchecked(transmute(this)) }
}
}