|
|
|
@ -33,20 +33,21 @@ pub struct FatPointer {
|
|
|
|
|
/// ```
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct MultitraitObject {
|
|
|
|
|
pub data: *mut (),
|
|
|
|
|
pub original_typeid: TypeId,
|
|
|
|
|
pub any_vtable: *const (),
|
|
|
|
|
pub traits: HashMap<TypeId, *const ()>,
|
|
|
|
|
data: *mut (),
|
|
|
|
|
original_typeid: TypeId,
|
|
|
|
|
traits: HashMap<TypeId, *const ()>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MultitraitObject {
|
|
|
|
|
/// Creates a new multitrait object from the given value
|
|
|
|
|
/// All traits except Any must be registered on this object
|
|
|
|
|
/// in order to access them.
|
|
|
|
|
pub fn new<T: 'static + Any>(value: T) -> Self {
|
|
|
|
|
let any_vtable = __fat_pointer!(T as dyn Any).vptr;
|
|
|
|
|
let data = Box::into_raw(Box::new(value)) as *mut ();
|
|
|
|
|
|
|
|
|
|
let mut this = Self {
|
|
|
|
|
data,
|
|
|
|
|
any_vtable,
|
|
|
|
|
original_typeid: TypeId::of::<T>(),
|
|
|
|
|
traits: Default::default(),
|
|
|
|
|
};
|
|
|
|
@ -104,6 +105,7 @@ impl MultitraitObject {
|
|
|
|
|
pub fn downcast<T: Any>(self) -> Option<T> {
|
|
|
|
|
if TypeId::of::<T>() == self.original_typeid {
|
|
|
|
|
unsafe {
|
|
|
|
|
// SAFETY: We've checked for the type so it's safe to cast the data and consume it in the process
|
|
|
|
|
let typed_ptr = std::mem::transmute::<_, *mut T>(self.data);
|
|
|
|
|
let boxed = Box::from_raw(typed_ptr);
|
|
|
|
|
|
|
|
|
@ -121,6 +123,7 @@ impl MultitraitObject {
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
|
unsafe fn _downcast_trait<T1: 'static + ?Sized>(&self) -> Option<&T1> {
|
|
|
|
|
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
|
|
|
|
|
let vptr = *self.traits.get(&TypeId::of::<T1>())?;
|
|
|
|
|
let fat_pointer = FatPointer { data: self.data, vptr };
|
|
|
|
|
let value = std::mem::transmute::<_, &&T1>(&fat_pointer);
|
|
|
|
@ -130,6 +133,7 @@ impl MultitraitObject {
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
|
unsafe fn _downcast_trait_mut<T1: 'static + ?Sized>(&mut self) -> Option<&mut T1> {
|
|
|
|
|
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
|
|
|
|
|
let vptr = *self.traits.get(&TypeId::of::<T1>())?;
|
|
|
|
|
let mut fat_pointer = FatPointer { data: self.data, vptr };
|
|
|
|
|
let value = std::mem::transmute::<_, &mut &mut T1>(&mut fat_pointer);
|
|
|
|
@ -139,6 +143,7 @@ impl MultitraitObject {
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
|
unsafe fn _downcast_boxed_trait<T1: 'static + ?Sized>(&mut self) -> Option<Box<T1>> {
|
|
|
|
|
// SAFETY: Creating a fat pointer from the given v-table and data has no side effects
|
|
|
|
|
let vptr = *self.traits.get(&TypeId::of::<T1>())?;
|
|
|
|
|
let fat_pointer = FatPointer { data: self.data, vptr };
|
|
|
|
|
let value = std::mem::transmute::<_, *const *mut T1>(&fat_pointer);
|
|
|
|
@ -151,6 +156,7 @@ impl MultitraitObject {
|
|
|
|
|
impl Drop for MultitraitObject {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
unsafe {
|
|
|
|
|
// Safety: The Multitrait object has exclusive access to the data pointer
|
|
|
|
|
let raw = Box::from_raw(self.data);
|
|
|
|
|
std::mem::drop(raw);
|
|
|
|
|
}
|
|
|
|
|