use std::{any::TypeId, marker::PhantomData};
pub use zonbi_macros::Zonbi;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ZonbiId(TypeId);
impl ZonbiId {
pub fn of<'life, Z: Zonbi<'life>>() -> ZonbiId {
Z::zonbi_id()
}
}
impl From<TypeId> for ZonbiId {
fn from(value: TypeId) -> Self {
Self(value) }
}
pub unsafe trait Zonbi<'life>: 'life {
type Casted: Sized + Zonbi<'life>;
fn zonbi_id() -> ZonbiId;
unsafe fn zonbify(self) -> Self::Casted;
unsafe fn zonbify_ref(&self) -> &Self::Casted;
unsafe fn zonbify_mut(&mut self) -> &mut Self::Casted;
}
mod private {
pub trait Sealed {}
}
pub trait AnyZonbi<'life>: private::Sealed + 'life {
fn zonbi_id(&self) -> ZonbiId;
unsafe fn get_raw(&self) -> *const ();
unsafe fn get_raw_mut(&mut self) -> *mut ();
}
impl<'life> dyn AnyZonbi<'life> {
pub fn represents<Z: Zonbi<'life>>(&self) -> bool {
ZonbiId::of::<Z>().eq(&self.zonbi_id())
}
pub fn downcast_ref<Z: Zonbi<'life>>(&self) -> Option<&Z::Casted> {
if self.represents::<Z>() {
Some(unsafe { self.downcast_ref_unchecked::<Z>() })
} else {
None
}
}
pub unsafe fn downcast_ref_unchecked<Z: Zonbi<'life>>(&self) -> &Z::Casted {
let raw = unsafe { &*self.get_raw().cast::<Z>() };
Z::zonbify_ref(raw)
}
pub fn downcast_mut<Z: Zonbi<'life>>(&mut self) -> Option<&mut Z::Casted> {
if self.represents::<Z>() {
Some(unsafe { self.downcast_mut_unchecked::<Z>() })
} else {
None
}
}
pub unsafe fn downcast_mut_unchecked<Z: Zonbi<'life>>(&mut self) -> &mut Z::Casted {
let raw = unsafe { &mut *self.get_raw_mut().cast::<Z>() };
Z::zonbify_mut(raw)
}
}
pub struct Cage<'life, Z: Zonbi<'life>> {
val: Z,
phantom: PhantomData<&'life ()>,
}
impl<'life, Z: Zonbi<'life>> Cage<'life, Z> {
pub fn new(val: Z) -> Self {
Self {
val,
phantom: PhantomData,
}
}
pub fn into_inner(self) -> Z::Casted {
unsafe { Z::zonbify(self.val) }
}
}
impl<'life, Z: Zonbi<'life>> private::Sealed for Cage<'life, Z> {}
impl<'life, Z: Zonbi<'life>> AnyZonbi<'life> for Cage<'life, Z> {
fn zonbi_id(&self) -> ZonbiId {
Z::zonbi_id()
}
unsafe fn get_raw(&self) -> *const () {
(&self.val as *const Z).cast()
}
unsafe fn get_raw_mut(&mut self) -> *mut () {
(&mut self.val as *mut Z).cast()
}
}