priority_lfu/traits.rs
1use std::hash::Hash;
2
3use priority_lfu_derive::DeepSizeOf;
4
5use crate::deepsize::DeepSizeOf;
6
7pub(crate) const NUM_POLICY_BUCKETS: usize = 3;
8
9/// Cache eviction policy determining retention priority.
10///
11/// Lower discriminant values = higher priority = evicted last.
12#[repr(u8)]
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, DeepSizeOf)]
14pub enum CachePolicy {
15 /// Critical metadata that should persist (catalog, schemas, indexes).
16 /// Last to be evicted, highest retention.
17 Critical = 0,
18
19 /// Standard cacheable data (recent queries, lookup results).
20 /// Normal eviction behavior.
21 #[default]
22 Standard = 1,
23
24 /// Temporary or easily recomputed data (intermediate results, aggregations).
25 /// First to be evicted.
26 Volatile = 2,
27}
28
29/// Marker trait for cache keys. Associates a key type with its value type.
30///
31/// # Example
32///
33/// ```
34/// use priority_lfu::{DeepSizeOf, CacheKey, CachePolicy};
35///
36/// #[derive(Hash, Eq, PartialEq, Clone)]
37/// struct UserId(u64);
38///
39/// #[derive(Clone, Debug, PartialEq, DeepSizeOf)]
40/// struct UserData {
41/// name: String,
42/// }
43///
44/// impl CacheKey for UserId {
45/// type Value = UserData;
46///
47/// fn policy(&self) -> CachePolicy {
48/// CachePolicy::Standard
49/// }
50/// }
51/// ```
52pub trait CacheKey: Hash + Eq + Clone + Send + Sync + 'static {
53 /// The value type associated with this key.
54 type Value: DeepSizeOf + Send + Sync;
55
56 /// Eviction policy determining retention priority.
57 ///
58 /// This method is called on the key, allowing different keys to have
59 /// different policies for the same value type.
60 fn policy(&self) -> CachePolicy {
61 CachePolicy::Standard
62 }
63}
64
65/// Trait for borrowed keys that can look up entries of type `K`.
66///
67/// This trait enables zero-allocation cache lookups using borrowed key types.
68/// For example, you can use `(&str, &str)` to look up entries stored with
69/// `(String, String)` keys, avoiding the allocation of owned strings.
70///
71/// # Hash Consistency Requirement
72///
73/// **CRITICAL**: The `Hash` implementation MUST produce the same hash as `K`
74/// for equivalent keys. If the hashes differ, lookups will fail.
75///
76/// # Example
77///
78/// ```
79/// use std::hash::{Hash, Hasher};
80/// use priority_lfu::{CacheKey, CacheKeyLookup, CachePolicy, DeepSizeOf};
81///
82/// // Owned key type
83/// #[derive(Hash, Eq, PartialEq, Clone)]
84/// struct DbCacheKey(String, String);
85///
86/// impl CacheKey for DbCacheKey {
87/// type Value = String;
88/// }
89///
90/// // Borrowed lookup type
91/// struct DbCacheKeyRef<'a>(&'a str, &'a str);
92///
93/// impl Hash for DbCacheKeyRef<'_> {
94/// fn hash<H: Hasher>(&self, state: &mut H) {
95/// // MUST match DbCacheKey's hash implementation
96/// self.0.hash(state);
97/// self.1.hash(state);
98/// }
99/// }
100///
101/// impl CacheKeyLookup<DbCacheKey> for DbCacheKeyRef<'_> {
102/// fn eq_key(&self, key: &DbCacheKey) -> bool {
103/// self.0 == key.0 && self.1 == key.1
104/// }
105///
106/// fn to_owned_key(self) -> DbCacheKey {
107/// DbCacheKey(self.0.to_owned(), self.1.to_owned())
108/// }
109/// }
110/// ```
111pub trait CacheKeyLookup<K: CacheKey>: Hash {
112 /// Check equality against an owned key.
113 ///
114 /// Returns `true` if this borrowed key is equivalent to the given owned key.
115 fn eq_key(&self, key: &K) -> bool;
116
117 /// Convert this borrowed key to an owned key.
118 fn to_owned_key(self) -> K;
119}
120
121/// Blanket implementation: every `CacheKey` can look up itself.
122///
123/// This allows existing code using `cache.get(&key)` to continue working unchanged.
124impl<K: CacheKey> CacheKeyLookup<K> for K {
125 fn eq_key(&self, key: &K) -> bool {
126 self == key
127 }
128
129 fn to_owned_key(self) -> K {
130 self
131 }
132}