use allocator_api::{Alloc, Box, Layout, handle_alloc_error};
use core::ptr::{self, NonNull};
use {BoxExt, Zero};
pub trait BoxInExt<A: Alloc> {
type Inner;
fn new_in_with<F: FnOnce() -> Self::Inner>(f: F, a: A) -> Self;
fn new_zeroed_in(a: A) -> Self
where
Self: Sized,
Self::Inner: Zero;
fn try_new_in(x: Self::Inner, a: A) -> Option<Self>
where
Self: Sized;
fn try_new_in_with<F: FnOnce() -> Self::Inner>(f: F, a: A) -> Option<Self>
where
Self: Sized;
fn try_new_zeroed_in(a: A) -> Option<Self>
where
Self: Sized;
}
unsafe fn new_box_in<T, A: Alloc>(mut a: A, zeroed: bool) -> Result<Box<T, A>, Layout> {
let layout = Layout::new::<T>();
let raw = if layout.size() == 0 {
Ok(NonNull::<T>::dangling())
} else if zeroed {
a.alloc_zeroed(layout).map(NonNull::cast)
} else {
a.alloc(layout).map(NonNull::cast)
};
match raw {
Ok(raw) => Ok(Box::from_raw_in(raw.as_ptr(), a)),
Err(_) => Err(layout),
}
}
impl<T, A: Alloc> BoxInExt<A> for Box<T, A> {
type Inner = T;
#[inline]
fn new_in_with<F: FnOnce() -> T>(f: F, a: A) -> Self {
unsafe {
let mut b = new_box_in::<T, A>(a, false).unwrap_or_else(|l| handle_alloc_error(l));
ptr::write(b.as_mut(), f());
b
}
}
#[inline]
fn new_zeroed_in(a: A) -> Self
where
T: Zero,
{
unsafe { new_box_in::<T, A>(a, true).unwrap_or_else(|l| handle_alloc_error(l)) }
}
#[inline]
fn try_new_in(x: T, mut a: A) -> Option<Self> {
unsafe {
let raw = a.alloc(Layout::new::<T>()).ok()?.cast().as_ptr();
ptr::write(raw, x);
Some(Box::from_raw_in(raw, a))
}
}
#[inline]
fn try_new_in_with<F: FnOnce() -> Self::Inner>(f: F, mut a: A) -> Option<Self> {
unsafe {
let raw = a.alloc(Layout::new::<T>()).ok()?.cast().as_ptr();
ptr::write(raw, f());
Some(Box::from_raw_in(raw, a))
}
}
#[inline]
fn try_new_zeroed_in(mut a: A) -> Option<Self> {
unsafe {
let raw = a.alloc_zeroed(Layout::new::<T>()).ok()?.cast();
Some(Box::from_raw_in(raw.as_ptr(), a))
}
}
}
impl<T, A: Alloc + Default> BoxExt for Box<T, A> {
type Inner = <Self as BoxInExt<A>>::Inner;
#[inline]
fn new_with<F: FnOnce() -> Self::Inner>(f: F) -> Self {
BoxInExt::new_in_with(f, Default::default())
}
#[inline]
fn new_zeroed() -> Self
where
T: Zero,
{
BoxInExt::new_zeroed_in(Default::default())
}
#[inline]
fn try_new(x: T) -> Option<Self> {
BoxInExt::try_new_in(x, Default::default())
}
#[inline]
fn try_new_with<F: FnOnce() -> Self::Inner>(f: F) -> Option<Self> {
BoxInExt::try_new_in_with(f, Default::default())
}
#[inline]
fn try_new_zeroed() -> Option<Self>
where
Self::Inner: Zero,
{
BoxInExt::try_new_zeroed_in(Default::default())
}
}