use core::{
marker::Unsize,
mem::MaybeUninit,
ops::{CoerceUnsized, Deref, DerefMut},
ptr::{addr_of_mut, DynMetadata, Pointee, Thin},
};
pub struct SizedBox<T: ?Sized, const SIZE: usize> {
storage: [u8; SIZE],
_ptr: *mut T,
}
impl<T, const SIZE: usize> SizedBox<T, SIZE> {
pub const fn new(inner: T) -> Self where {
const {
if core::mem::size_of::<T>() > SIZE {
panic!("Type is too big to fit in SizedBox")
}
};
let mut s: MaybeUninit<Self> = core::mem::MaybeUninit::uninit();
let ptr = s.as_mut_ptr();
unsafe {
(addr_of_mut!((*ptr).storage) as *mut T).write(inner);
addr_of_mut!((*ptr)._ptr).write(core::ptr::null_mut());
s.assume_init()
}
}
}
impl<T: ?Sized, const MAX_SIZE: usize, A: ?Sized> Deref for SizedBox<T, MAX_SIZE>
where
T: Pointee<Metadata = DynMetadata<A>>,
{
type Target = T;
fn deref(&self) -> &Self::Target {
let addr = self.storage.as_ptr() as *const ();
let meta = core::ptr::metadata(self._ptr);
let new_ptr = core::ptr::from_raw_parts(addr, meta);
unsafe { &*new_ptr }
}
}
impl<T: ?Sized, const MAX_SIZE: usize, A: ?Sized> DerefMut for SizedBox<T, MAX_SIZE>
where
T: Pointee<Metadata = DynMetadata<A>>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
let addr = self.storage.as_mut_ptr() as *mut ();
let meta = core::ptr::metadata(self._ptr);
let new_ptr = core::ptr::from_raw_parts_mut(addr, meta);
unsafe { &mut *new_ptr }
}
}
unsafe impl<T: ?Sized + Send, const SIZE: usize> Send for SizedBox<T, SIZE> {}
unsafe impl<T: ?Sized + Sync, const SIZE: usize> Sync for SizedBox<T, SIZE> {}
impl<T: ?Sized + Unsize<U>, U: ?Sized, const SIZE: usize> CoerceUnsized<SizedBox<U, SIZE>>
for SizedBox<T, SIZE>
{
}
impl<T: ?Sized, const SIZE: usize> SizedBox<T, SIZE> {
pub fn resize<const NEW_SIZE: usize>(self) -> SizedBox<T, NEW_SIZE> {
const {
if NEW_SIZE < SIZE {
panic!("Can't reduce the size of a box")
}
};
let mut s: MaybeUninit<SizedBox<T, NEW_SIZE>> = core::mem::MaybeUninit::uninit();
let ptr = s.as_mut_ptr();
unsafe {
let new = addr_of_mut!((*ptr).storage) as *mut u8;
let old = &self.storage as *const _ as *const u8;
core::ptr::copy(old, new, SIZE);
addr_of_mut!((*ptr)._ptr).write(self._ptr);
s.assume_init()
}
}
}