use crate::{
alloc::{AbortAlloc, AllocRef, BuildAlloc, BuildDealloc, DeallocRef, Global, NonZeroLayout},
UncheckedResultExt,
};
use core::{
alloc::Layout,
fmt,
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
pin::Pin,
ptr::NonNull,
slice,
};
pub struct Box<T: ?Sized, B: BuildDealloc = AbortAlloc<Global>>(NonNull<T>, B, PhantomData<T>);
#[allow(clippy::use_self)]
impl<T> Box<T> {
pub fn new(x: T) -> Self {
Self::new_in(x, AbortAlloc(Global))
}
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
Self::new_uninit_in(AbortAlloc(Global))
}
#[inline(always)]
pub fn pin(x: T) -> Pin<Self> {
Self::new(x).into()
}
}
#[allow(clippy::use_self)]
impl<T, B: BuildDealloc> Box<T, B>
where
B: BuildAlloc,
{
pub fn new_in(x: T, a: B::AllocRef) -> Self
where
B::AllocRef: AllocRef<Error = crate::Never>,
{
unsafe { Self::try_new_in(x, a).unwrap_unchecked() }
}
pub fn try_new_in(x: T, mut a: B::AllocRef) -> Result<Self, <B::AllocRef as AllocRef>::Error> {
let ptr = if let Ok(layout) = NonZeroLayout::new::<T>() {
let ptr = a.alloc(layout)?.cast::<T>();
unsafe {
ptr.as_ptr().write(x);
}
ptr
} else {
NonNull::dangling()
};
Ok(Self(ptr, a.get_build_alloc(), PhantomData))
}
pub fn new_uninit_in(a: B::AllocRef) -> Box<mem::MaybeUninit<T>, B>
where
B::AllocRef: AllocRef<Error = crate::Never>,
{
unsafe { Self::try_new_uninit_in(a).unwrap_unchecked() }
}
pub fn try_new_uninit_in(
mut a: B::AllocRef,
) -> Result<Box<mem::MaybeUninit<T>, B>, <B::AllocRef as AllocRef>::Error> {
let ptr = if let Ok(layout) = NonZeroLayout::new::<T>() {
let ptr: NonNull<T> = a.alloc(layout)?.cast();
ptr
} else {
NonNull::dangling()
};
Ok(Self(ptr.cast(), a.get_build_alloc(), PhantomData))
}
#[inline(always)]
pub fn pin_in(x: T, a: B::AllocRef) -> Pin<Self>
where
B::AllocRef: AllocRef<Error = crate::Never>,
{
unsafe { Self::try_pin_in(x, a).unwrap_unchecked() }
}
#[inline(always)]
pub fn try_pin_in(x: T, a: B::AllocRef) -> Result<Pin<Self>, <B::AllocRef as AllocRef>::Error> {
Self::try_new_in(x, a).map(Pin::from)
}
}
#[allow(clippy::use_self)]
impl<T> Box<[T]> {
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
Self::new_uninit_slice_in(len, AbortAlloc(Global))
}
}
#[allow(clippy::use_self)]
impl<T, B: BuildDealloc> Box<[T], B>
where
B: BuildAlloc,
B::AllocRef: AllocRef<Error = crate::Never>,
{
pub fn new_uninit_slice_in(len: usize, a: B::AllocRef) -> Box<[mem::MaybeUninit<T>], B> {
unsafe { Self::try_new_uninit_slice_in(len, a).unwrap_unchecked() }
}
}
#[allow(clippy::use_self)]
impl<T, B: BuildDealloc> Box<[T], B>
where
B: BuildAlloc,
{
#[allow(clippy::type_complexity)]
pub fn try_new_uninit_slice_in(
len: usize,
mut a: B::AllocRef,
) -> Result<Box<[mem::MaybeUninit<T>], B>, <B::AllocRef as AllocRef>::Error> {
let ptr = if mem::size_of::<T>() == 0 {
NonNull::dangling()
} else {
let layout =
NonZeroLayout::array::<mem::MaybeUninit<T>>(len).expect("capacity overflow");
a.alloc(layout)?
};
unsafe {
let slice = slice::from_raw_parts_mut(ptr.cast().as_ptr(), len);
Ok(Self(NonNull::from(slice), a.get_build_alloc(), PhantomData))
}
}
}
#[allow(clippy::use_self)]
impl<T, B: BuildDealloc> Box<mem::MaybeUninit<T>, B> {
#[inline]
pub unsafe fn assume_init(mut self) -> Box<T, B> {
let a = self.get_alloc();
let ptr = Self::into_raw(self);
Box::from_raw_in(ptr as _, a)
}
}
#[allow(clippy::use_self)]
impl<T, B: BuildDealloc> Box<[mem::MaybeUninit<T>], B> {
#[inline]
pub unsafe fn assume_init(mut self) -> Box<[T], B> {
let a = self.get_alloc();
let ptr = Self::into_raw(self);
Box::from_raw_in(ptr as _, a)
}
}
impl<T: ?Sized> Box<T> {
pub unsafe fn from_raw(raw: *mut T) -> Self {
Self::from_raw_in(raw, AbortAlloc(Global))
}
}
impl<T: ?Sized, B: BuildDealloc> Box<T, B> {
#[inline]
pub unsafe fn from_raw_in(raw: *mut T, mut d: B::DeallocRef) -> Self {
Self(
NonNull::new_unchecked(raw),
d.get_build_dealloc(),
PhantomData,
)
}
pub fn get_alloc(&mut self) -> B::DeallocRef {
unsafe {
self.1
.build_dealloc_ref(self.0.cast(), Layout::for_value(self.as_ref()))
}
}
#[inline]
pub fn into_raw(b: Self) -> *mut T {
Self::into_raw_non_null(b).as_ptr()
}
#[inline]
pub fn into_raw_non_null(b: Self) -> NonNull<T> {
let mut ptr = b.0;
mem::forget(b);
unsafe { NonNull::new_unchecked(ptr.as_mut()) }
}
#[inline]
pub fn leak<'a>(b: Self) -> &'a mut T
where
T: 'a, {
unsafe { &mut *Self::into_raw(b) }
}
pub fn into_pin(boxed: Self) -> Pin<Self> {
unsafe { Pin::new_unchecked(boxed) }
}
}
impl<T: ?Sized, B: BuildDealloc> Deref for Box<T, B> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.0.as_ref() }
}
}
impl<T: ?Sized, B: BuildDealloc> DerefMut for Box<T, B> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() }
}
}
impl<T: ?Sized, B: BuildDealloc> From<Box<T, B>> for Pin<Box<T, B>> {
fn from(boxed: Box<T, B>) -> Self {
Box::into_pin(boxed)
}
}
impl<T: fmt::Display + ?Sized, B: BuildDealloc> fmt::Display for Box<T, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<T: fmt::Debug + ?Sized, B: BuildDealloc> fmt::Debug for Box<T, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized, B: BuildDealloc> AsRef<T> for Box<T, B> {
fn as_ref(&self) -> &T {
&**self
}
}
impl<T: ?Sized, B: BuildDealloc> AsMut<T> for Box<T, B> {
fn as_mut(&mut self) -> &mut T {
&mut **self
}
}
#[cfg(feature = "dropck_eyepatch")]
unsafe impl<#[may_dangle] T: ?Sized, B: BuildDealloc> Drop for Box<T, B> {
fn drop(&mut self) {
unsafe {
self.get_alloc().dealloc(
self.0.cast(),
NonZeroLayout::for_value_unchecked(self.0.as_ref()),
)
}
}
}
#[cfg(not(feature = "dropck_eyepatch"))]
impl<T: ?Sized, B: BuildDealloc> Drop for Box<T, B> {
fn drop(&mut self) {
unsafe {
self.get_alloc().dealloc(
self.0.cast(),
NonZeroLayout::for_value_unchecked(self.0.as_ref()),
)
}
}
}