use std::any::{Any, TypeId, type_name};
use std::ops::{Deref, DerefMut};
use crate::multimap::AnyMultiMap;
pub struct AnyCloneBox {
inner: Box<dyn AnyClone>,
type_id: TypeId,
type_name: &'static str,
}
impl AnyCloneBox {
pub fn new<T: Clone + Send + Sync + 'static>(value: T) -> Self {
AnyCloneBox {
inner: Box::new(value),
type_id: TypeId::of::<T>(),
type_name: type_name::<T>(),
}
}
pub fn type_id(&self) -> TypeId {
self.type_id
}
pub fn type_name(&self) -> &'static str {
self.type_name
}
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.type_id == TypeId::of::<T>() {
Some(unsafe {
self.downcast_ref_unchecked::<T>()
})
} else {
None
}
}
pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
unsafe { &*(self.inner.deref() as *const dyn Any as *const T) }
}
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.type_id == TypeId::of::<T>() {
Some(unsafe {
self.downcast_mut_unchecked::<T>()
})
} else {
None
}
}
pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
unsafe { &mut *(self.inner.deref_mut() as *mut dyn Any as *mut T) }
}
pub fn downcast<T: Any>(self) -> Result<Box<T>, Self> {
if self.type_id == TypeId::of::<T>() {
Ok(unsafe {
self.downcast_unchecked::<T>()
})
} else {
Err(self)
}
}
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T> {
unsafe {
let raw = Box::into_raw(self.inner);
Box::from_raw(raw as *mut T)
}
}
}
impl AnyCloneBox {
pub(super) fn insert_into_multimap(self, multimap: &mut AnyMultiMap) {
self.inner.insert_into_multimap(multimap);
}
}
impl Clone for AnyCloneBox {
fn clone(&self) -> Self {
AnyCloneBox {
inner: self.inner.clone_box(),
type_id: self.type_id,
type_name: self.type_name,
}
}
}
trait AnyClone: Any + Send + Sync {
fn clone_box(&self) -> Box<dyn AnyClone>;
fn insert_into_multimap(self: Box<Self>, multimap: &mut AnyMultiMap);
}
impl<T: Clone + Send + Sync + 'static> AnyClone for T {
fn clone_box(&self) -> Box<dyn AnyClone> {
Box::new(self.clone())
}
fn insert_into_multimap(self: Box<Self>, multimap: &mut AnyMultiMap) {
multimap.insert(*self);
}
}