use std::{
any::{Any, TypeId},
fmt::Debug,
hash::{Hash, Hasher},
sync::Arc,
};
use crate::Capsule;
pub trait CapsuleKey: Hash + Eq + Debug + Send + Sync + 'static {}
impl<T: Hash + Eq + Debug + Send + Sync + 'static> CapsuleKey for T {}
trait DynCapsuleKey: Debug + Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn dyn_hash(&self, state: &mut dyn Hasher);
fn dyn_eq(&self, other: &dyn DynCapsuleKey) -> bool;
}
impl<T> DynCapsuleKey for T
where
T: Hash + Eq + Debug + Send + Sync + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
}
fn dyn_eq(&self, other: &dyn DynCapsuleKey) -> bool {
other
.as_any()
.downcast_ref::<T>()
.map_or(false, |other| self == other)
}
}
impl Hash for dyn DynCapsuleKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dyn_hash(state);
}
}
impl PartialEq for dyn DynCapsuleKey {
fn eq(&self, other: &dyn DynCapsuleKey) -> bool {
self.dyn_eq(other)
}
}
impl Eq for dyn DynCapsuleKey {}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CapsuleId {
capsule_type: TypeId,
capsule_key: Arc<Box<dyn DynCapsuleKey>>,
}
pub trait CreateCapsuleId {
fn id(&self) -> CapsuleId;
}
impl<C: Capsule> CreateCapsuleId for C {
fn id(&self) -> CapsuleId {
CapsuleId {
capsule_type: TypeId::of::<C>(),
capsule_key: Arc::new(Box::new(self.key())),
}
}
}