use std::alloc::{Allocator, Global, Layout};
use std::ptr::NonNull;
pub struct UnsafeAny {
data: Option<NonNull<[u8]>>,
deleter: unsafe fn(NonNull<[u8]>),
}
unsafe fn delete<T>(value: NonNull<[u8]>) {
assert_eq!(size_of::<T>(), unsafe { value.as_ref().len() });
let ptr = unsafe { std::mem::transmute::<*const (), *const T>(value.as_ptr() as *const ()) };
drop(unsafe { std::ptr::read(ptr) });
}
impl UnsafeAny {
pub fn uninit() -> UnsafeAny {
UnsafeAny {
data: None,
deleter: delete::<()>,
}
}
pub unsafe fn from<T>(value: T) -> UnsafeAny {
unsafe {
let memory = Global.allocate_zeroed(Layout::for_value(&value)).unwrap();
assert_eq!(size_of::<T>(), memory.len());
std::ptr::write(
std::mem::transmute::<*mut (), *mut T>(memory.as_ptr() as *mut ()),
value,
);
UnsafeAny {
data: Some(memory),
deleter: delete::<T>,
}
}
}
pub unsafe fn get<T>(&self) -> &T {
assert!(self.data.is_some());
assert_eq!(size_of::<T>(), unsafe { self.data.unwrap().as_ref().len() });
unsafe { &*std::mem::transmute::<*const (), *const T>(self.data.unwrap().as_ptr() as *const ()) }
}
}
impl Drop for UnsafeAny {
fn drop(&mut self) {
if let Some(ptr) = self.data {
unsafe { (self.deleter)(ptr) }
}
}
}