use std::{
any::{Any, TypeId},
fmt::Debug,
hash::{Hash, Hasher},
sync::Arc,
};
use crate::Capsule;
#[derive(Default)]
pub struct CapsuleKey(CapsuleKeyType);
impl<T: Hash + Eq + Debug + Send + Sync + 'static> From<T> for CapsuleKey {
fn from(key: T) -> Self {
Self(CapsuleKeyType::Dynamic(Box::new(key)))
}
}
#[derive(Debug, Default, PartialEq, Eq, Hash)]
enum CapsuleKeyType<DynDynamicCapsuleKey: ?Sized = dyn DynamicCapsuleKey> {
#[default]
Static,
Dynamic(Box<DynDynamicCapsuleKey>),
}
trait DynamicCapsuleKey: Debug + Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
fn dyn_hash(&self, state: &mut dyn Hasher);
fn dyn_eq(&self, other: &dyn Any) -> bool;
}
impl<T> DynamicCapsuleKey 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 Any) -> bool {
other
.downcast_ref::<T>()
.map_or(false, |other| self == other)
}
}
impl Hash for dyn DynamicCapsuleKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dyn_hash(state);
}
}
impl PartialEq for dyn DynamicCapsuleKey {
fn eq(&self, other: &dyn DynamicCapsuleKey) -> bool {
self.dyn_eq(other.as_any())
}
}
impl Eq for dyn DynamicCapsuleKey {}
#[allow(clippy::redundant_pub_crate)] #[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct InternalCapsuleKey {
capsule_type: TypeId,
capsule_key: CapsuleKeyType,
}
#[allow(clippy::redundant_pub_crate)] pub(crate) type Id = Arc<InternalCapsuleKey>;
#[allow(clippy::redundant_pub_crate)] pub(crate) trait CreateId {
fn id(&self) -> Id;
}
impl<C: Capsule> CreateId for C {
fn id(&self) -> Id {
Arc::new(InternalCapsuleKey {
capsule_type: TypeId::of::<C>(),
capsule_key: self.key().0,
})
}
}