use std::any::TypeId;
use std::fmt::Debug;
use iced::advanced::graphics::futures::MaybeSend;
pub trait OxiAny: 'static + MaybeSend + Debug + Send + Sync {
fn type_id(&self) -> TypeId;
}
impl<T: 'static + ?Sized + Debug + MaybeSend + Send + Sync> OxiAny for T {
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}
}
impl dyn OxiAny {
#[inline]
pub fn is<T: OxiAny>(&self) -> bool {
let t = TypeId::of::<T>();
let concrete = self.type_id();
t == concrete
}
#[inline]
pub fn downcast_ref<T: OxiAny>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe { Some(self.downcast_ref_unchecked()) }
} else {
None
}
}
#[inline]
pub fn downcast_mut<T: OxiAny>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(self.downcast_mut_unchecked()) }
} else {
None
}
}
#[inline]
pub unsafe fn downcast_mut_unchecked<T: OxiAny>(&mut self) -> &mut T {
debug_assert!(self.is::<T>());
unsafe { &mut *(self as *mut dyn OxiAny as *mut T) }
}
#[inline]
pub unsafe fn downcast_ref_unchecked<T: OxiAny>(&self) -> &T {
debug_assert!(self.is::<T>());
unsafe { &*(self as *const dyn OxiAny as *const T) }
}
}
#[test]
fn test_enum_conversion() {
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
enum TestEnum {
One,
Two,
}
let enum_any = &mut TestEnum::One as &mut dyn OxiAny;
let comp = if let Some(val) = enum_any.downcast_ref::<TestEnum>() {
&TestEnum::One == val
} else {
false
};
assert!(comp)
}
#[test]
fn test_struct_conversion() {
#[derive(Debug, Default, PartialEq)]
struct TestStruct {
one: u32,
two: u32,
}
let struct_any = &mut TestStruct::default() as &mut dyn OxiAny;
let comp = if let Some(val) = struct_any.downcast_ref::<TestStruct>() {
&TestStruct::default() == val
} else {
false
};
assert!(comp)
}