query_flow/
key.rs

1//! Key types for query caching.
2
3use std::any::TypeId;
4use std::fmt::Debug;
5use std::hash::{Hash, Hasher};
6use std::sync::Arc;
7
8use crate::asset::FullAssetKey;
9
10/// Trait for query cache keys.
11///
12/// Cache keys must be hashable, comparable, cloneable, and thread-safe.
13pub trait Key: Hash + Eq + Clone + Send + Sync + Debug + 'static {}
14
15// Blanket implementation for all types that satisfy the bounds
16impl<T> Key for T where T: Hash + Eq + Clone + Send + Sync + Debug + 'static {}
17
18/// Marker type to distinguish asset keys in the dependency graph.
19struct AssetKeyMarker;
20
21/// Marker type for query set sentinels (used by list_queries).
22struct QuerySetMarker;
23
24/// Marker type for asset key set sentinels (used by list_asset_keys).
25struct AssetKeySetMarker;
26
27/// Internal full cache key that includes query type information.
28///
29/// This prevents collisions between different query types that might
30/// have the same `CacheKey` type (e.g., both use `u32`).
31#[derive(Clone)]
32pub(crate) struct FullCacheKey {
33    /// Type ID of the query (or AssetKeyMarker for assets)
34    query_type: TypeId,
35    /// Hash of the user's cache key
36    key_hash: u64,
37    /// Debug representation for error messages
38    debug_repr: Arc<str>,
39}
40
41impl FullCacheKey {
42    /// Create a new full cache key for a query.
43    pub fn new<Q: 'static, K: Key>(key: &K) -> Self {
44        let mut hasher = ahash::AHasher::default();
45        key.hash(&mut hasher);
46        let key_hash = hasher.finish();
47
48        Self {
49            query_type: TypeId::of::<Q>(),
50            key_hash,
51            debug_repr: Arc::from(format!("{}({:?})", std::any::type_name::<Q>(), key)),
52        }
53    }
54
55    /// Create a cache key from an asset key.
56    ///
57    /// This allows assets to participate in the same dependency graph as queries.
58    /// Assets use a special marker type to namespace them separately from queries.
59    pub fn from_asset_key(asset_key: &FullAssetKey) -> Self {
60        // Combine asset key's type and hash to create a unique key
61        let mut hasher = ahash::AHasher::default();
62        asset_key.key_type().hash(&mut hasher);
63        asset_key.key_hash().hash(&mut hasher);
64        let key_hash = hasher.finish();
65
66        Self {
67            query_type: TypeId::of::<AssetKeyMarker>(),
68            key_hash,
69            debug_repr: Arc::from(asset_key.debug_repr()),
70        }
71    }
72
73    /// Get debug representation for error messages.
74    pub fn debug_repr(&self) -> &str {
75        &self.debug_repr
76    }
77
78    /// Create a sentinel key representing "all queries of type Q".
79    ///
80    /// This is used by `list_queries` to track dependencies on the set of queries,
81    /// rather than individual query values.
82    pub fn query_set_sentinel<Q: 'static>() -> Self {
83        let mut hasher = ahash::AHasher::default();
84        TypeId::of::<Q>().hash(&mut hasher);
85        let type_hash = hasher.finish();
86
87        Self {
88            query_type: TypeId::of::<QuerySetMarker>(),
89            key_hash: type_hash,
90            debug_repr: Arc::from(format!("QuerySet<{}>", std::any::type_name::<Q>())),
91        }
92    }
93
94    /// Create a sentinel key representing "all asset keys of type K".
95    ///
96    /// This is used by `list_asset_keys` to track dependencies on the set of asset keys,
97    /// rather than individual asset values.
98    pub fn asset_key_set_sentinel<K: 'static>() -> Self {
99        let mut hasher = ahash::AHasher::default();
100        TypeId::of::<K>().hash(&mut hasher);
101        let type_hash = hasher.finish();
102
103        Self {
104            query_type: TypeId::of::<AssetKeySetMarker>(),
105            key_hash: type_hash,
106            debug_repr: Arc::from(format!("AssetKeySet<{}>", std::any::type_name::<K>())),
107        }
108    }
109}
110
111impl Debug for FullCacheKey {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        write!(f, "{}", self.debug_repr)
114    }
115}
116
117impl Hash for FullCacheKey {
118    fn hash<H: Hasher>(&self, state: &mut H) {
119        self.query_type.hash(state);
120        self.key_hash.hash(state);
121    }
122}
123
124impl PartialEq for FullCacheKey {
125    fn eq(&self, other: &Self) -> bool {
126        self.query_type == other.query_type && self.key_hash == other.key_hash
127    }
128}
129
130impl Eq for FullCacheKey {}