use std::mem;
#[cfg(feature = "unstable-debug")]
use std::intrinsics;
pub struct Any {
ptr: *mut (),
drop: fn(*mut ()),
fingerprint: Fingerprint,
#[cfg(feature = "unstable-debug")]
type_name: &'static str,
}
impl Any {
pub(crate) fn new<T>(t: T) -> Self {
let ptr = Box::into_raw(Box::new(t)) as *mut ();
let drop = |ptr| drop(unsafe { Box::from_raw(ptr as *mut T) });
let fingerprint = Fingerprint::of::<T>();
#[cfg(not(feature = "unstable-debug"))]
{
Any { ptr, drop, fingerprint }
}
#[cfg(feature = "unstable-debug")]
{
let type_name = unsafe { intrinsics::type_name::<T>() };
Any { ptr, drop, fingerprint, type_name }
}
}
pub(crate) fn view<T>(&mut self) -> &mut T {
if self.fingerprint != Fingerprint::of::<T>() {
self.invalid_cast_to::<T>();
}
let ptr = self.ptr as *mut T;
unsafe { &mut *ptr }
}
pub(crate) fn take<T>(self) -> T {
if self.fingerprint != Fingerprint::of::<T>() {
self.invalid_cast_to::<T>();
}
let ptr = self.ptr as *mut T;
let box_t = unsafe { Box::from_raw(ptr) };
mem::forget(self);
*box_t
}
#[cfg(not(feature = "unstable-debug"))]
fn invalid_cast_to<T>(&self) -> ! {
panic!("invalid cast; enable `unstable-debug` feature to debug");
}
#[cfg(feature = "unstable-debug")]
fn invalid_cast_to<T>(&self) -> ! {
let from = self.type_name;
let to = unsafe { intrinsics::type_name::<T>() };
panic!("invalid cast: {} to {}", from, to);
}
}
impl Drop for Any {
fn drop(&mut self) {
(self.drop)(self.ptr);
}
}
#[derive(Debug, Eq, PartialEq)]
struct Fingerprint {
size: usize,
align: usize,
id: usize,
}
impl Fingerprint {
fn of<T>() -> Fingerprint {
Fingerprint {
size: mem::size_of::<T>(),
align: mem::align_of::<T>(),
id: Fingerprint::of::<T> as usize,
}
}
}
#[test]
fn test_fingerprint() {
assert_eq!(Fingerprint::of::<usize>(), Fingerprint::of::<usize>());
assert_eq!(Fingerprint::of::<&str>(), Fingerprint::of::<&'static str>());
assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<isize>());
assert_ne!(Fingerprint::of::<usize>(), Fingerprint::of::<&usize>());
assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&&usize>());
assert_ne!(Fingerprint::of::<&usize>(), Fingerprint::of::<&mut usize>());
struct A;
struct B;
assert_ne!(Fingerprint::of::<A>(), Fingerprint::of::<B>());
}