use std::any::{Any, TypeId};
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use dyn_hash::DynHash;
pub trait DynEq: Any {
fn dyn_eq(&self, other: &dyn Any) -> bool;
}
impl<T: Eq + 'static> DynEq for T {
fn dyn_eq(&self, other: &dyn Any) -> bool {
other.downcast_ref::<T>().is_some_and(|o| self == o)
}
}
pub trait CacheKey: DynHash + DynEq + Debug + Send + Sync {
fn as_any(&self) -> &dyn Any;
fn type_name(&self) -> &'static str;
}
impl<T: Hash + Eq + Debug + Send + Sync + 'static> CacheKey for T {
fn as_any(&self) -> &dyn Any {
self
}
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
}
dyn_hash::hash_trait_object!(CacheKey);
#[derive(Clone)]
pub struct QueryCacheKey {
query_type: TypeId,
key: Arc<dyn CacheKey>,
}
impl QueryCacheKey {
pub fn new<Q: CacheKey + 'static>(query: Q) -> Self {
Self {
query_type: TypeId::of::<Q>(),
key: Arc::new(query),
}
}
pub fn debug_repr(&self) -> String {
format!("{:?}", self.key)
}
pub fn downcast<K: 'static>(&self) -> Option<&K> {
self.key.as_any().downcast_ref()
}
pub fn query_type(&self) -> TypeId {
self.query_type
}
pub fn key(&self) -> &Arc<dyn CacheKey> {
&self.key
}
pub fn type_name(&self) -> &'static str {
self.key.type_name()
}
}
impl Debug for QueryCacheKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.key)
}
}
impl Hash for QueryCacheKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.query_type.hash(state);
self.key.hash(state);
}
}
impl PartialEq for QueryCacheKey {
fn eq(&self, other: &Self) -> bool {
self.query_type == other.query_type && self.key.dyn_eq(other.key.as_any())
}
}
impl Eq for QueryCacheKey {}
#[derive(Clone)]
pub struct AssetCacheKey {
asset_key_type: TypeId,
key: Arc<dyn CacheKey>,
}
impl AssetCacheKey {
pub fn new<K: CacheKey + 'static>(key: K) -> Self {
Self {
asset_key_type: TypeId::of::<K>(),
key: Arc::new(key),
}
}
pub fn debug_repr(&self) -> String {
format!("{:?}", self.key)
}
pub fn downcast<K: 'static>(&self) -> Option<&K> {
self.key.as_any().downcast_ref()
}
pub fn asset_key_type(&self) -> TypeId {
self.asset_key_type
}
pub fn key(&self) -> &Arc<dyn CacheKey> {
&self.key
}
pub fn type_name(&self) -> &'static str {
self.key.type_name()
}
}
impl Debug for AssetCacheKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Asset({:?})", self.key)
}
}
impl Hash for AssetCacheKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.asset_key_type.hash(state);
self.key.hash(state);
}
}
impl PartialEq for AssetCacheKey {
fn eq(&self, other: &Self) -> bool {
self.asset_key_type == other.asset_key_type && self.key.dyn_eq(other.key.as_any())
}
}
impl Eq for AssetCacheKey {}
#[derive(Clone, Copy)]
pub struct QuerySetSentinelKey {
query_type: TypeId,
type_name: &'static str,
}
impl QuerySetSentinelKey {
pub fn new<Q: 'static>() -> Self {
Self {
query_type: TypeId::of::<Q>(),
type_name: std::any::type_name::<Q>(),
}
}
pub fn query_type(&self) -> TypeId {
self.query_type
}
pub fn type_name(&self) -> &'static str {
self.type_name
}
}
impl Debug for QuerySetSentinelKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "QuerySet({:?})", self.query_type)
}
}
impl Hash for QuerySetSentinelKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.query_type.hash(state);
}
}
impl PartialEq for QuerySetSentinelKey {
fn eq(&self, other: &Self) -> bool {
self.query_type == other.query_type
}
}
impl Eq for QuerySetSentinelKey {}
#[derive(Clone, Copy)]
pub struct AssetKeySetSentinelKey {
asset_key_type: TypeId,
type_name: &'static str,
}
impl AssetKeySetSentinelKey {
pub fn new<K: 'static>() -> Self {
Self {
asset_key_type: TypeId::of::<K>(),
type_name: std::any::type_name::<K>(),
}
}
pub fn asset_key_type(&self) -> TypeId {
self.asset_key_type
}
pub fn type_name(&self) -> &'static str {
self.type_name
}
}
impl Debug for AssetKeySetSentinelKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AssetKeySet({:?})", self.asset_key_type)
}
}
impl Hash for AssetKeySetSentinelKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.asset_key_type.hash(state);
}
}
impl PartialEq for AssetKeySetSentinelKey {
fn eq(&self, other: &Self) -> bool {
self.asset_key_type == other.asset_key_type
}
}
impl Eq for AssetKeySetSentinelKey {}
#[derive(Clone)]
pub enum FullCacheKey {
Query(QueryCacheKey),
Asset(AssetCacheKey),
QuerySetSentinel(QuerySetSentinelKey),
AssetKeySetSentinel(AssetKeySetSentinelKey),
}
impl FullCacheKey {
pub fn debug_repr(&self) -> String {
match self {
FullCacheKey::Query(k) => k.debug_repr(),
FullCacheKey::Asset(k) => k.debug_repr(),
FullCacheKey::QuerySetSentinel(k) => format!("{:?}", k),
FullCacheKey::AssetKeySetSentinel(k) => format!("{:?}", k),
}
}
pub fn downcast<K: 'static>(&self) -> Option<&K> {
match self {
FullCacheKey::Query(k) => k.downcast(),
FullCacheKey::Asset(k) => k.downcast(),
FullCacheKey::QuerySetSentinel(_) | FullCacheKey::AssetKeySetSentinel(_) => None,
}
}
pub fn key(&self) -> Option<&Arc<dyn CacheKey>> {
match self {
FullCacheKey::Query(k) => Some(k.key()),
FullCacheKey::Asset(k) => Some(k.key()),
FullCacheKey::QuerySetSentinel(_) | FullCacheKey::AssetKeySetSentinel(_) => None,
}
}
pub fn type_name(&self) -> &'static str {
match self {
FullCacheKey::Query(k) => k.type_name(),
FullCacheKey::Asset(k) => k.type_name(),
FullCacheKey::QuerySetSentinel(k) => k.type_name(),
FullCacheKey::AssetKeySetSentinel(k) => k.type_name(),
}
}
}
impl Debug for FullCacheKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FullCacheKey::Query(k) => write!(f, "{:?}", k),
FullCacheKey::Asset(k) => write!(f, "{:?}", k),
FullCacheKey::QuerySetSentinel(k) => write!(f, "{:?}", k),
FullCacheKey::AssetKeySetSentinel(k) => write!(f, "{:?}", k),
}
}
}
impl Hash for FullCacheKey {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
FullCacheKey::Query(k) => k.hash(state),
FullCacheKey::Asset(k) => k.hash(state),
FullCacheKey::QuerySetSentinel(k) => k.hash(state),
FullCacheKey::AssetKeySetSentinel(k) => k.hash(state),
}
}
}
impl PartialEq for FullCacheKey {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(FullCacheKey::Query(a), FullCacheKey::Query(b)) => a == b,
(FullCacheKey::Asset(a), FullCacheKey::Asset(b)) => a == b,
(FullCacheKey::QuerySetSentinel(a), FullCacheKey::QuerySetSentinel(b)) => a == b,
(FullCacheKey::AssetKeySetSentinel(a), FullCacheKey::AssetKeySetSentinel(b)) => a == b,
_ => false,
}
}
}
impl Eq for FullCacheKey {}
impl From<QueryCacheKey> for FullCacheKey {
fn from(key: QueryCacheKey) -> Self {
FullCacheKey::Query(key)
}
}
impl From<AssetCacheKey> for FullCacheKey {
fn from(key: AssetCacheKey) -> Self {
FullCacheKey::Asset(key)
}
}
impl From<QuerySetSentinelKey> for FullCacheKey {
fn from(key: QuerySetSentinelKey) -> Self {
FullCacheKey::QuerySetSentinel(key)
}
}
impl From<AssetKeySetSentinelKey> for FullCacheKey {
fn from(key: AssetKeySetSentinelKey) -> Self {
FullCacheKey::AssetKeySetSentinel(key)
}
}
pub trait Cachable: std::hash::Hash + Eq + Clone + std::fmt::Debug + Send + Sync + 'static {}
impl<T: std::hash::Hash + Eq + Clone + std::fmt::Debug + Send + Sync + 'static> Cachable for T {}