use core::ops::{Deref, DerefMut};
use crate::{Alloc, Allocator, AllocatorExt, Error, Panic, Strategy};
pub struct Box<'alloc, T, S: Strategy> {
alloc: Option<Alloc<'alloc, T>>,
_strategy: S,
}
#[cfg(feature = "global")]
impl<T, S: Strategy> Box<'static, T, S> {
pub fn new(value: T) -> S::Result<Self, Error> {
let allocator = S::create(crate::global::get().ok_or(Error::NoGlobalAllocator));
S::and_then(allocator, |allocator| Self::new_in(value, allocator))
}
}
impl<'alloc, T, S: Strategy> Box<'alloc, T, S> {
pub fn new_in(value: T, allocator: &'alloc dyn Allocator) -> S::Result<Self, Error> {
let alloc = S::create(allocator.alloc_with(value));
let alloc = S::map(alloc, |alloc| Self {
alloc: Some(alloc),
_strategy: S::UNIT,
});
S::map_err(alloc, |(_, e)| e)
}
pub fn clone_in<'new_alloc>(
&self,
allocator: &'new_alloc dyn Allocator,
) -> S::Result<Box<'new_alloc, T, S>, Error>
where
T: Clone,
{
let value = self.deref().clone();
Box::<T, S>::new_in(value, allocator)
}
pub fn clone_in_same(&self) -> S::Result<Self, Error>
where
T: Clone,
{
self.clone_in(self.alloc.as_ref().unwrap().allocator())
}
pub fn change_strategy<NS: Strategy>(mut self) -> Box<'alloc, T, NS> {
let alloc = self.alloc.take();
Box {
alloc,
_strategy: NS::UNIT,
}
}
pub fn take(mut self) -> T {
let alloc = self.alloc.take().unwrap();
let value = unsafe { alloc.as_ptr().read() };
alloc.dealloc();
value
}
pub fn leak(this: Self) -> &'alloc mut T {
let mut this = core::mem::ManuallyDrop::new(this);
unsafe { &mut *this.alloc.take().unwrap().as_ptr() }
}
}
impl<T: Clone, S: Strategy> Clone for Box<'_, T, S> {
fn clone(&self) -> Self {
let value = self.deref().clone();
Box::<_, Panic>::new_in(value, self.alloc.as_ref().unwrap().allocator()).change_strategy()
}
}
impl<T, S: Strategy> Deref for Box<'_, T, S> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.alloc.as_ref().unwrap().as_ref() }
}
}
impl<T, S: Strategy> DerefMut for Box<'_, T, S> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.alloc.as_mut().unwrap().as_mut() }
}
}
impl<T, S: Strategy> Drop for Box<'_, T, S> {
fn drop(&mut self) {
let alloc = self.alloc.take().unwrap();
drop(unsafe { alloc.as_ptr().read() });
alloc.dealloc();
}
}