use core::{ marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, }; /// Tiny version of dungeon-cell's DungeonCore. /// /// Can be used to erase types. This container **will not** /// run the stored value's Drop impl. Also this container does not /// track what type it is storing. Also, also this container /// does not align it's value so no making borrows of the inner value!. /// /// This type **is** safe to use in const environments. pub struct Erased { /// A value of some unknown type that is N bytes long. /// /// We don't need a UnsafeCell here because we never give out a borrow /// of the value. bytes: MaybeUninit<[u8; N]>, _marker: PhantomData<*const ()>, } impl Erased { /// Erase the type of a value. pub const fn new(value: T) -> Self { const { assert!(core::mem::size_of::() <= N); } let value = ManuallyDrop::new(value); #[repr(C)] union Transmute { value: ManuallyDrop, bytes: MaybeUninit<[u8; N]>, } Self { #[allow(unsafe_code)] bytes: unsafe { Transmute { value }.bytes }, _marker: PhantomData, } } /// Extract the original value. /// /// # Safety /// `T` must be the same type used when [`Self::new`] was called. #[allow(unsafe_code)] pub const unsafe fn into_inner(self) -> T { const { // This should already be covered by new, but here for completeness. assert!(core::mem::size_of::() <= N); } #[repr(C)] union Transmute { bytes: MaybeUninit<[u8; N]>, value: ManuallyDrop, } ManuallyDrop::into_inner(unsafe { Transmute { bytes: self.bytes }.value }) } }