Diffstat (limited to 'src/any/erased.rs')
-rw-r--r--src/any/erased.rs65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/any/erased.rs b/src/any/erased.rs
new file mode 100644
index 0000000..65571b1
--- /dev/null
+++ b/src/any/erased.rs
@@ -0,0 +1,65 @@
+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 })
+ }
+}