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<const N: usize> {
/// 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<const N: usize> Erased<N> {
/// Erase the type of a value.
pub const fn new<T>(value: T) -> Self {
const {
assert!(core::mem::size_of::<T>() <= N);
}
let value = ManuallyDrop::new(value);
#[repr(C)]
union Transmute<T, const N: usize> {
value: ManuallyDrop<T>,
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<T>(self) -> T {
const {
// This should already be covered by new, but here for completeness.
assert!(core::mem::size_of::<T>() <= N);
}
#[repr(C)]
union Transmute<T, const N: usize> {
bytes: MaybeUninit<[u8; N]>,
value: ManuallyDrop<T>,
}
ManuallyDrop::into_inner(unsafe { Transmute { bytes: self.bytes }.value })
}
}