#![feature(unsize, ptr_metadata)] #![feature(layout_for_ptr)] use department::alloc::GlobalAlloc; use department::backing::{Align4, Align8, Backing}; use department::base::Storage; use department::handles::{Handle, MetaHandle}; use department::inline::SingleInline; use spin::RwLock; use std::alloc::Layout; use std::fmt::{Debug, Formatter}; use std::marker::{PhantomData, Unsize}; use std::ops::Deref; use std::ptr::{NonNull, Pointee}; use std::{mem, ptr}; pub(crate) fn layout_of(meta: T::Metadata) -> Layout { let pointer = ptr::from_raw_parts(ptr::null::<()>(), meta); // SAFETY: The provided metadata is passed by value, and thus must be a valid instance of the // metadata for `T` unsafe { Layout::for_value_raw::(pointer) } } #[repr(C)] pub struct ThinInner { meta: M, value: T, } pub struct ThinBox { handle: S::Handle<()>, storage: S, phantom: PhantomData, } impl ThinBox { fn metadata(&self) -> ::Metadata { let handle = S::cast::<_, ::Metadata>(self.handle); unsafe { *self.storage.get(handle).as_ref() } } } impl ThinBox { pub fn unsize_new>(value: U) -> Self { let meta = ptr::metadata::(&value as &T); let mut storage = S::default(); let handle = storage .allocate_single::::Metadata, U>>(()) .unwrap(); let inner_ptr: NonNull::Metadata, U>> = unsafe { storage.get(handle) }; unsafe { (*inner_ptr.as_ptr()).meta = meta; (*inner_ptr.as_ptr()).value = value; } ThinBox { handle: S::cast(handle), storage, phantom: PhantomData, } } } impl ThinBox { pub fn new(value: T) -> Self { let mut storage = S::default(); let handle = storage.allocate_single::>(()).unwrap(); let ptr = unsafe { storage.get(handle) }; unsafe { (*ptr.as_ptr()).value = value }; ThinBox { handle: S::cast(handle), storage, phantom: PhantomData, } } } impl Debug for ThinBox { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { (**self).fmt(f) } } impl Deref for ThinBox { type Target = T; fn deref(&self) -> &Self::Target { let handle = S::cast::<_, ::Metadata>(self.handle); let ptr = unsafe { self.storage.get(handle) }; let meta = unsafe { *ptr.as_ptr() }; let data_ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr().add(1)) }; unsafe { NonNull::from_raw_parts(data_ptr.cast(), meta).as_ref() } } } impl Drop for ThinBox { fn drop(&mut self) { union MetaCaster { meta: ::Metadata, meta2: ::Metadata, T> as Pointee>::Metadata, } let meta = unsafe { MetaCaster:: { meta: self.metadata(), } .meta2 }; let handle = S::from_raw_parts::::Metadata, T>>(self.handle, meta); unsafe { self.storage.drop_single(handle) } } } fn sized_item() { dbg!(ThinBox::<_, GlobalAlloc>::new(1)); dbg!(ThinBox::<_, SingleInline>>::new(1)); } fn thin_range() { dbg!(ThinBox::<[i32], GlobalAlloc>::unsize_new([1, 2, 3])); dbg!(ThinBox::<[i32], SingleInline>>::unsize_new([1, 2, 3])); } fn thin_dyn() { dbg!(ThinBox::::unsize_new( "Hello World!" )); dbg!(ThinBox::>>::unsize_new("Hello World!")); } fn ultra_thin() { struct SyncPtr(NonNull<()>); unsafe impl Send for SyncPtr {} unsafe impl Sync for SyncPtr {} static THIN_BACKING: RwLock = RwLock::new(SyncPtr(NonNull::dangling())); // This is incredibly likely to cause incorrectness or unsoundness - this implementation is just // here to show off the idea of a ZST box. #[derive(Default)] struct ThinStorage; unsafe impl Storage for ThinStorage { type Handle = MetaHandle; unsafe fn get(&self, handle: Self::Handle) -> NonNull { NonNull::from_raw_parts(THIN_BACKING.read().0, handle.metadata()) } fn from_raw_parts( handle: Self::Handle<()>, meta: T::Metadata, ) -> Self::Handle { MetaHandle::from_raw_parts(handle, meta) } fn cast(handle: Self::Handle) -> Self::Handle { MetaHandle::cast(handle) } fn cast_unsized>( handle: Self::Handle, ) -> Self::Handle { MetaHandle::cast_unsized(handle) } fn coerce, U: ?Sized + Pointee>( handle: Self::Handle, ) -> Self::Handle { MetaHandle::coerce(handle) } fn allocate_single( &mut self, meta: T::Metadata, ) -> department::error::Result> { let layout = layout_of::(meta); THIN_BACKING.write().0 = NonNull::new(unsafe { std::alloc::alloc(layout).cast() }).unwrap(); Ok(MetaHandle::from_metadata(meta)) } unsafe fn deallocate_single(&mut self, handle: Self::Handle) { let layout = layout_of::(handle.metadata()); let mut backing = THIN_BACKING.write(); std::alloc::dealloc(backing.0.as_ptr().cast(), layout); backing.0 = NonNull::dangling(); } } let b = ThinBox::<[i32], ThinStorage>::unsize_new([1, 2, 3, 4]); assert_eq!(&*b, &[1, 2, 3, 4]); assert_eq!(mem::size_of::>(), 0); } fn main() { sized_item(); thin_range(); thin_dyn(); ultra_thin(); }