use std::any::Any;
use std::any::TypeId;
pub struct VBox {
data: Box<dyn Any + Send>,
vtable: usize,
type_id: TypeId,
}
impl VBox {
pub fn new(
data: Box<dyn Any + Send>,
vtable: usize,
type_id: TypeId,
) -> Self {
VBox {
data,
vtable,
type_id,
}
}
pub fn unpack(self) -> (Box<dyn Any + Send>, usize, TypeId) {
(self.data, self.vtable, self.type_id)
}
}
#[macro_export]
macro_rules! into_vbox {
($t: ty, $v: expr) => {{
let type_id = {
let trait_obj_ref: &$t = &$v;
::std::any::Any::type_id(trait_obj_ref)
};
let vtable = {
let fat_ptr: *const $t = &$v;
let (_data, vtable): (*const (), *const ()) =
unsafe { ::std::mem::transmute(fat_ptr) };
vtable as usize
};
VBox::new(Box::new($v), vtable, type_id)
}};
}
#[macro_export]
macro_rules! from_vbox {
($t: ty, $v: expr) => {{
let (data, vtable, type_id) = $v.unpack();
let any_fat_ptr: *const dyn ::core::any::Any = Box::into_raw(data);
let (data_ptr, _vtable): (*const (), *const ()) =
unsafe { ::std::mem::transmute(any_fat_ptr) };
let vtable_ptr = vtable as *const ();
let fat_ptr: *mut $t =
unsafe { ::std::mem::transmute((data_ptr, vtable_ptr)) };
let ret = unsafe { Box::from_raw(fat_ptr) };
{
let trait_obj_ref = &*ret;
debug_assert_eq!(
::std::any::Any::type_id(trait_obj_ref),
type_id,
"expected type_id: {:?}, actual type_id: {:?}",
::std::any::Any::type_id(trait_obj_ref),
type_id
);
}
ret
}};
}