use crate::Meta;
use crate::TypedMetadata;
use crate::ptr_metadata::*;
use std::any::Any;
use std::any::TypeId;
pub trait MultiAny: Any {
fn get_metadata(&self, type_id: TypeId) -> Option<Meta>;
}
impl dyn MultiAny {
pub fn downcast_ref<RequestedType>(&self) -> Option<&RequestedType>
where
RequestedType: Pointee + ?Sized + 'static,
RequestedType::Metadata: TypedMetadata,
{
let meta = self.get_metadata(TypeId::of::<RequestedType>())?;
assert_eq!(meta.data_id, self.type_id(), "Wrong Data type");
let typed_meta = RequestedType::Metadata::from_meta(meta);
let data_pointer = self as *const dyn MultiAny as *const ();
let ptr: *const RequestedType = from_raw_parts(data_pointer, typed_meta);
unsafe { &*ptr }.into()
}
pub fn downcast_mut<RequestedType>(&mut self) -> Option<&mut RequestedType>
where
RequestedType: Pointee + ?Sized + 'static,
RequestedType::Metadata: TypedMetadata,
{
let ptr = self.downcast_mut_ptr::<RequestedType>()?;
unsafe { &mut *ptr }.into()
}
pub fn downcast<RequestedType>(mut self: Box<Self>) -> Result<Box<RequestedType>, Box<Self>>
where
RequestedType: Pointee + ?Sized + 'static,
RequestedType::Metadata: TypedMetadata,
{
let Some(ptr) = self.downcast_mut_ptr::<RequestedType>() else {
return Err(self);
};
Box::leak(self);
Ok(unsafe { Box::from_raw(ptr) })
}
fn downcast_mut_ptr<RequestedType>(&mut self) -> Option<*mut RequestedType>
where
RequestedType: Pointee + ?Sized + 'static,
RequestedType::Metadata: TypedMetadata,
{
let meta = self.get_metadata(TypeId::of::<RequestedType>())?;
assert_eq!(meta.data_id, (*self).type_id(), "Wrong Data type");
let typed_meta = RequestedType::Metadata::from_meta(meta);
let data_pointer = self as *mut dyn MultiAny as *mut ();
let ptr: *mut RequestedType = from_raw_parts_mut(data_pointer, typed_meta);
Some(ptr)
}
}
impl std::fmt::Debug for dyn MultiAny {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MultiAny").finish()
}
}