use alloc::boxed::Box;
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use crate::State;
use crate::arena::{Alloc, ArenaBox};
pub struct Boxed<T: ?Sized> {
ptr: NonNull<T>,
alloc: Alloc,
_marker: PhantomData<T>,
}
unsafe impl<T: ?Sized + Send> Send for Boxed<T> {}
unsafe impl<T: ?Sized + Sync> Sync for Boxed<T> {}
impl<T: ?Sized> Boxed<T> {
#[inline(always)]
pub(crate) fn from_arena(value: ArenaBox<T>) -> Boxed<T> {
Boxed {
ptr: ArenaBox::into_raw(value),
alloc: Alloc::Arena,
_marker: PhantomData,
}
}
#[inline(always)]
pub(crate) fn into_raw(this: Boxed<T>) -> (NonNull<T>, Alloc) {
let rv = (this.ptr, this.alloc);
core::mem::forget(this);
rv
}
#[inline(always)]
pub(crate) unsafe fn from_raw(ptr: NonNull<T>, alloc: Alloc) -> Boxed<T> {
Boxed {
ptr,
alloc,
_marker: PhantomData,
}
}
#[inline(always)]
pub(crate) fn release(this: Boxed<T>, state: &mut State) {
let (ptr, alloc) = Boxed::into_raw(this);
unsafe {
match alloc {
Alloc::Arena => {
ArenaBox::release_in(ArenaBox::from_raw(ptr.as_ptr()), &mut state.arena)
}
Alloc::Heap => drop(Box::from_raw(ptr.as_ptr())),
}
}
}
}
impl<T> Boxed<T> {
#[inline(always)]
pub(crate) fn arena(value: T, state: &mut State) -> Boxed<T> {
Boxed::from_arena(ArenaBox::new(value, &mut state.arena))
}
}
impl<T: ?Sized> From<Box<T>> for Boxed<T> {
fn from(value: Box<T>) -> Boxed<T> {
Boxed {
ptr: unsafe { NonNull::new_unchecked(Box::into_raw(value)) },
alloc: Alloc::Heap,
_marker: PhantomData,
}
}
}
impl<T: ?Sized> Deref for Boxed<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> DerefMut for Boxed<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
}
impl<T: ?Sized> Drop for Boxed<T> {
fn drop(&mut self) {
unsafe {
match self.alloc {
Alloc::Arena => drop(ArenaBox::from_raw(self.ptr.as_ptr())),
Alloc::Heap => drop(Box::from_raw(self.ptr.as_ptr())),
}
}
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for Boxed<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[inline(always)]
pub(crate) fn unsize<T, U: ?Sized>(value: Boxed<T>, cast: fn(*mut T) -> *mut U) -> Boxed<U> {
let (ptr, alloc) = Boxed::into_raw(value);
unsafe { Boxed::from_raw(NonNull::new_unchecked(cast(ptr.as_ptr())), alloc) }
}