1use std::any::{Any, TypeId};
4use std::fmt::Debug;
5use std::hash::{Hash, Hasher};
6use std::sync::Arc;
7
8use dyn_hash::DynHash;
9
10pub trait DynEq: Any {
15 fn dyn_eq(&self, other: &dyn Any) -> bool;
19}
20
21impl<T: Eq + 'static> DynEq for T {
22 fn dyn_eq(&self, other: &dyn Any) -> bool {
23 other.downcast_ref::<T>().is_some_and(|o| self == o)
24 }
25}
26
27pub trait CacheKey: DynHash + DynEq + Debug + Send + Sync {
38 fn as_any(&self) -> &dyn Any;
40
41 fn type_name(&self) -> &'static str;
43}
44
45impl<T: Hash + Eq + Debug + Send + Sync + 'static> CacheKey for T {
46 fn as_any(&self) -> &dyn Any {
47 self
48 }
49
50 fn type_name(&self) -> &'static str {
51 std::any::type_name::<T>()
52 }
53}
54
55dyn_hash::hash_trait_object!(CacheKey);
57
58#[derive(Clone)]
62pub struct QueryCacheKey {
63 query_type: TypeId,
64 key: Arc<dyn CacheKey>,
65}
66
67impl QueryCacheKey {
68 pub fn new<Q: CacheKey + 'static>(query: Q) -> Self {
70 Self {
71 query_type: TypeId::of::<Q>(),
72 key: Arc::new(query),
73 }
74 }
75
76 pub fn debug_repr(&self) -> String {
78 format!("{:?}", self.key)
79 }
80
81 pub fn downcast<K: 'static>(&self) -> Option<&K> {
83 self.key.as_any().downcast_ref()
84 }
85
86 pub fn query_type(&self) -> TypeId {
88 self.query_type
89 }
90
91 pub fn key(&self) -> &Arc<dyn CacheKey> {
93 &self.key
94 }
95
96 pub fn type_name(&self) -> &'static str {
98 self.key.type_name()
99 }
100}
101
102impl Debug for QueryCacheKey {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(f, "{:?}", self.key)
105 }
106}
107
108impl Hash for QueryCacheKey {
109 fn hash<H: Hasher>(&self, state: &mut H) {
110 self.query_type.hash(state);
111 self.key.hash(state);
112 }
113}
114
115impl PartialEq for QueryCacheKey {
116 fn eq(&self, other: &Self) -> bool {
117 self.query_type == other.query_type && self.key.dyn_eq(other.key.as_any())
118 }
119}
120
121impl Eq for QueryCacheKey {}
122
123#[derive(Clone)]
127pub struct AssetCacheKey {
128 asset_key_type: TypeId,
129 key: Arc<dyn CacheKey>,
130}
131
132impl AssetCacheKey {
133 pub fn new<K: CacheKey + 'static>(key: K) -> Self {
135 Self {
136 asset_key_type: TypeId::of::<K>(),
137 key: Arc::new(key),
138 }
139 }
140
141 pub fn debug_repr(&self) -> String {
143 format!("{:?}", self.key)
144 }
145
146 pub fn downcast<K: 'static>(&self) -> Option<&K> {
148 self.key.as_any().downcast_ref()
149 }
150
151 pub fn asset_key_type(&self) -> TypeId {
153 self.asset_key_type
154 }
155
156 pub fn key(&self) -> &Arc<dyn CacheKey> {
158 &self.key
159 }
160
161 pub fn type_name(&self) -> &'static str {
163 self.key.type_name()
164 }
165}
166
167impl Debug for AssetCacheKey {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(f, "Asset({:?})", self.key)
170 }
171}
172
173impl Hash for AssetCacheKey {
174 fn hash<H: Hasher>(&self, state: &mut H) {
175 self.asset_key_type.hash(state);
176 self.key.hash(state);
177 }
178}
179
180impl PartialEq for AssetCacheKey {
181 fn eq(&self, other: &Self) -> bool {
182 self.asset_key_type == other.asset_key_type && self.key.dyn_eq(other.key.as_any())
183 }
184}
185
186impl Eq for AssetCacheKey {}
187
188#[derive(Clone, Copy)]
193pub struct QuerySetSentinelKey {
194 query_type: TypeId,
195 type_name: &'static str,
196}
197
198impl QuerySetSentinelKey {
199 pub fn new<Q: 'static>() -> Self {
201 Self {
202 query_type: TypeId::of::<Q>(),
203 type_name: std::any::type_name::<Q>(),
204 }
205 }
206
207 pub fn query_type(&self) -> TypeId {
209 self.query_type
210 }
211
212 pub fn type_name(&self) -> &'static str {
214 self.type_name
215 }
216}
217
218impl Debug for QuerySetSentinelKey {
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 write!(f, "QuerySet({:?})", self.query_type)
221 }
222}
223
224impl Hash for QuerySetSentinelKey {
225 fn hash<H: Hasher>(&self, state: &mut H) {
226 self.query_type.hash(state);
227 }
228}
229
230impl PartialEq for QuerySetSentinelKey {
231 fn eq(&self, other: &Self) -> bool {
232 self.query_type == other.query_type
233 }
234}
235
236impl Eq for QuerySetSentinelKey {}
237
238#[derive(Clone, Copy)]
243pub struct AssetKeySetSentinelKey {
244 asset_key_type: TypeId,
245 type_name: &'static str,
246}
247
248impl AssetKeySetSentinelKey {
249 pub fn new<K: 'static>() -> Self {
251 Self {
252 asset_key_type: TypeId::of::<K>(),
253 type_name: std::any::type_name::<K>(),
254 }
255 }
256
257 pub fn asset_key_type(&self) -> TypeId {
259 self.asset_key_type
260 }
261
262 pub fn type_name(&self) -> &'static str {
264 self.type_name
265 }
266}
267
268impl Debug for AssetKeySetSentinelKey {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 write!(f, "AssetKeySet({:?})", self.asset_key_type)
271 }
272}
273
274impl Hash for AssetKeySetSentinelKey {
275 fn hash<H: Hasher>(&self, state: &mut H) {
276 self.asset_key_type.hash(state);
277 }
278}
279
280impl PartialEq for AssetKeySetSentinelKey {
281 fn eq(&self, other: &Self) -> bool {
282 self.asset_key_type == other.asset_key_type
283 }
284}
285
286impl Eq for AssetKeySetSentinelKey {}
287
288#[derive(Clone)]
293pub enum FullCacheKey {
294 Query(QueryCacheKey),
296 Asset(AssetCacheKey),
298 QuerySetSentinel(QuerySetSentinelKey),
300 AssetKeySetSentinel(AssetKeySetSentinelKey),
302}
303
304impl FullCacheKey {
305 pub fn debug_repr(&self) -> String {
307 match self {
308 FullCacheKey::Query(k) => k.debug_repr(),
309 FullCacheKey::Asset(k) => k.debug_repr(),
310 FullCacheKey::QuerySetSentinel(k) => format!("{:?}", k),
311 FullCacheKey::AssetKeySetSentinel(k) => format!("{:?}", k),
312 }
313 }
314
315 pub fn downcast<K: 'static>(&self) -> Option<&K> {
319 match self {
320 FullCacheKey::Query(k) => k.downcast(),
321 FullCacheKey::Asset(k) => k.downcast(),
322 FullCacheKey::QuerySetSentinel(_) | FullCacheKey::AssetKeySetSentinel(_) => None,
323 }
324 }
325
326 pub fn key(&self) -> Option<&Arc<dyn CacheKey>> {
328 match self {
329 FullCacheKey::Query(k) => Some(k.key()),
330 FullCacheKey::Asset(k) => Some(k.key()),
331 FullCacheKey::QuerySetSentinel(_) | FullCacheKey::AssetKeySetSentinel(_) => None,
332 }
333 }
334
335 pub fn type_name(&self) -> &'static str {
337 match self {
338 FullCacheKey::Query(k) => k.type_name(),
339 FullCacheKey::Asset(k) => k.type_name(),
340 FullCacheKey::QuerySetSentinel(k) => k.type_name(),
341 FullCacheKey::AssetKeySetSentinel(k) => k.type_name(),
342 }
343 }
344}
345
346impl Debug for FullCacheKey {
347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348 match self {
349 FullCacheKey::Query(k) => write!(f, "{:?}", k),
350 FullCacheKey::Asset(k) => write!(f, "{:?}", k),
351 FullCacheKey::QuerySetSentinel(k) => write!(f, "{:?}", k),
352 FullCacheKey::AssetKeySetSentinel(k) => write!(f, "{:?}", k),
353 }
354 }
355}
356
357impl Hash for FullCacheKey {
358 fn hash<H: Hasher>(&self, state: &mut H) {
359 std::mem::discriminant(self).hash(state);
360 match self {
361 FullCacheKey::Query(k) => k.hash(state),
362 FullCacheKey::Asset(k) => k.hash(state),
363 FullCacheKey::QuerySetSentinel(k) => k.hash(state),
364 FullCacheKey::AssetKeySetSentinel(k) => k.hash(state),
365 }
366 }
367}
368
369impl PartialEq for FullCacheKey {
370 fn eq(&self, other: &Self) -> bool {
371 match (self, other) {
372 (FullCacheKey::Query(a), FullCacheKey::Query(b)) => a == b,
373 (FullCacheKey::Asset(a), FullCacheKey::Asset(b)) => a == b,
374 (FullCacheKey::QuerySetSentinel(a), FullCacheKey::QuerySetSentinel(b)) => a == b,
375 (FullCacheKey::AssetKeySetSentinel(a), FullCacheKey::AssetKeySetSentinel(b)) => a == b,
376 _ => false,
377 }
378 }
379}
380
381impl Eq for FullCacheKey {}
382
383impl From<QueryCacheKey> for FullCacheKey {
384 fn from(key: QueryCacheKey) -> Self {
385 FullCacheKey::Query(key)
386 }
387}
388
389impl From<AssetCacheKey> for FullCacheKey {
390 fn from(key: AssetCacheKey) -> Self {
391 FullCacheKey::Asset(key)
392 }
393}
394
395impl From<QuerySetSentinelKey> for FullCacheKey {
396 fn from(key: QuerySetSentinelKey) -> Self {
397 FullCacheKey::QuerySetSentinel(key)
398 }
399}
400
401impl From<AssetKeySetSentinelKey> for FullCacheKey {
402 fn from(key: AssetKeySetSentinelKey) -> Self {
403 FullCacheKey::AssetKeySetSentinel(key)
404 }
405}