#![deny(missing_docs)]
#[cfg(not(feature = "std"))]
use core::{
marker::PhantomData,
mem::{align_of, size_of, MaybeUninit},
ptr,
};
#[cfg(feature = "std")]
use std::{
marker::PhantomData,
mem::{align_of, size_of, MaybeUninit},
ptr,
};
#[repr(C, align(8))]
pub struct TypeErased<const C: usize> {
buf: [MaybeUninit<u8>; C],
__no_send_sync: PhantomData<*const ()>,
}
impl<const C: usize> TypeErased<C> {
pub fn new<T: 'static>(value: T) -> Self {
assert!(
size_of::<T>() <= C,
"typeless: size of T ({}) > capacity ({})",
size_of::<T>(),
C
); assert!(
align_of::<T>() <= 8,
"typeless: alignment of T ({}) > max align (8)",
align_of::<T>()
);
unsafe { Self::new_unchecked(value) }
}
pub const fn empty() -> Self {
const U8_UNINIT: MaybeUninit<u8> = MaybeUninit::uninit();
Self {
buf: [U8_UNINIT; C],
__no_send_sync: PhantomData,
}
}
pub unsafe fn new_unchecked<T>(value: T) -> Self {
debug_assert!(
size_of::<T>() <= C,
"typeless: safety requirement violated: size of T ({}) > capacity ({})",
size_of::<T>(),
C
); debug_assert!(
align_of::<T>() <= 8,
"typeless: safety requirement violated: alignment of T ({}) > max align (8)",
align_of::<T>()
);
let mut this = Self::empty();
let ptr = this.as_mut_ptr::<T>();
debug_assert_eq!(
ptr as usize % 8,
0,
"typeless: internal error: ptr not 8-byte aligned"
); ptr::write(ptr, value);
this
}
pub const fn as_ptr<T>(&self) -> *const T {
self.buf.as_ptr().cast()
}
pub fn as_mut_ptr<T>(&mut self) -> *mut T {
self.buf.as_mut_ptr().cast()
}
pub unsafe fn assume_type_ref<T>(&self) -> &T {
&*self.as_ptr()
}
pub unsafe fn assume_type_mut<T>(&mut self) -> &mut T {
&mut *self.as_mut_ptr()
}
pub unsafe fn assume_type_take<T>(self) -> T {
ptr::read(self.as_ptr())
}
pub const fn raw(&self) -> &[MaybeUninit<u8>; C] {
&self.buf
}
pub fn raw_mut(&mut self) -> &mut [MaybeUninit<u8>; C] {
&mut self.buf
}
}