#![cfg_attr(not(test), no_std)]
#![feature(ptr_metadata)]
#![feature(unsize)]
#![feature(const_pin)]
use core::{
alloc::Layout,
marker::{PhantomData, Unsize},
ops::{Deref, DerefMut},
ptr::{self, DynMetadata, NonNull, Pointee},
};
#[cfg(test)]
mod tests;
#[inline]
fn meta_offset_layout<T, Value>(value: &Value) -> (DynMetadata<T>, Layout, usize)
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
Value: Unsize<T> + ?Sized,
{
let meta = ptr::metadata(value as &T);
let meta_layout = Layout::for_value(&meta);
let value_layout = Layout::for_value(value);
let (layout, offset) = meta_layout.extend(value_layout).unwrap();
(meta, layout, offset)
}
pub struct Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
align_offset: usize,
mem: &'m mut [u8],
phantom: PhantomData<T>,
}
impl<'m, T> Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
pub fn new<Value>(mem: &'m mut [u8], value: Value) -> Self
where
Value: Unsize<T>,
{
let (meta, layout, offset) = meta_offset_layout(&value);
assert!(layout.size() > 0, "Unsupported value layot");
let mut new_box = Self {
align_offset: 0,
mem,
phantom: PhantomData,
};
let raw_ptr = new_box.mem.as_mut().as_mut_ptr();
new_box.align_offset = raw_ptr.align_offset(layout.align());
let total_len = new_box.align_offset + layout.size();
let buf_len = new_box.mem.as_ref().len();
if total_len > buf_len {
core::mem::forget(new_box);
panic!(
"Not enough memory to store the specified value (got: {}, needed: {})",
buf_len, total_len,
);
}
unsafe {
let ptr = NonNull::new(raw_ptr.add(new_box.align_offset)).unwrap();
ptr.cast::<DynMetadata<T>>().as_ptr().write(meta);
ptr.cast::<u8>()
.as_ptr()
.add(offset)
.cast::<Value>()
.write(value);
new_box
}
}
#[inline]
pub fn layout_of_dyn<Value>(value: &Value) -> Layout
where
Value: Unsize<T> + ?Sized,
{
meta_offset_layout::<T, Value>(value).1
}
#[inline]
fn meta(&self) -> DynMetadata<T> {
unsafe { *self.mem.as_ref().as_ptr().add(self.align_offset).cast() }
}
#[inline]
fn layout_meta(&self) -> (Layout, usize, DynMetadata<T>) {
let meta = self.meta();
let (layout, offset) = Layout::for_value(&meta).extend(meta.layout()).unwrap();
(layout, offset, meta)
}
#[inline]
fn value_ptr(&self) -> *const T {
let (_, value_offset, meta) = self.layout_meta();
unsafe {
let ptr = self
.mem
.as_ref()
.as_ptr()
.add(self.align_offset)
.add(value_offset)
.cast::<()>();
ptr::from_raw_parts(ptr, meta)
}
}
#[inline]
fn value_mut_ptr(&mut self) -> *mut T {
let (_, value_offset, meta) = self.layout_meta();
unsafe {
let ptr = self
.mem
.as_mut()
.as_mut_ptr()
.add(self.align_offset)
.add(value_offset)
.cast::<()>();
ptr::from_raw_parts_mut(ptr, meta)
}
}
}
impl<'m, T> AsRef<T> for Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
#[inline]
fn as_ref(&self) -> &T {
unsafe { &*self.value_ptr() }
}
}
impl<'m, T> AsMut<T> for Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
#[inline]
fn as_mut(&mut self) -> &mut T {
unsafe { &mut *self.value_mut_ptr() }
}
}
impl<'m, T> Deref for Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.as_ref()
}
}
impl<'m, T> DerefMut for Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.as_mut()
}
}
impl<'m, T> Drop for Box<'m, T>
where
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
{
#[inline]
fn drop(&mut self) {
unsafe {
ptr::drop_in_place::<T>(&mut **self);
}
}
}