1use blake2::{Blake2b, Digest};
18use http::Extensions;
19use serde::{Deserialize, Serialize};
20use std::fmt::{Display, Formatter, Result as FmtResult};
21
22const KEY_SIZE: usize = 16;
24
25pub type HashBinary = [u8; KEY_SIZE];
27
28fn hex2str(hex: &[u8]) -> String {
29 use std::fmt::Write;
30 let mut s = String::with_capacity(KEY_SIZE * 2);
31 for c in hex {
32 write!(s, "{:02x}", c).unwrap(); }
34 s
35}
36
37pub fn str2hex(s: &str) -> Option<HashBinary> {
41 if s.len() != KEY_SIZE * 2 {
42 return None;
43 }
44 let mut output = [0; KEY_SIZE];
45 hex::decode_to_slice(s.as_bytes(), &mut output).ok()?;
47 Some(output)
48}
49
50pub trait CacheHashKey {
52 fn primary_bin(&self) -> HashBinary;
54
55 fn variance_bin(&self) -> Option<HashBinary>;
59
60 fn combined_bin(&self) -> HashBinary {
62 let key = self.primary_bin();
63 if let Some(v) = self.variance_bin() {
64 let mut hasher = Blake2b128::new();
65 hasher.update(key);
66 hasher.update(v);
67 hasher.finalize().into()
68 } else {
69 key
71 }
72 }
73
74 fn user_tag(&self) -> &str;
78
79 fn primary(&self) -> String {
81 hex2str(&self.primary_bin())
82 }
83
84 fn variance(&self) -> Option<String> {
86 self.variance_bin().as_ref().map(|b| hex2str(&b[..]))
87 }
88
89 fn combined(&self) -> String {
91 hex2str(&self.combined_bin())
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct CacheKey {
98 namespace: Vec<u8>,
102 primary: Vec<u8>,
103 primary_bin_override: Option<HashBinary>,
104 variance: Option<HashBinary>,
105 pub user_tag: String,
109
110 pub extensions: Extensions,
112}
113
114impl CacheKey {
115 pub fn set_variance_key(&mut self, key: HashBinary) {
117 self.variance = Some(key)
118 }
119
120 pub fn get_variance_key(&self) -> Option<&HashBinary> {
122 self.variance.as_ref()
123 }
124
125 pub fn remove_variance_key(&mut self) {
127 self.variance = None
128 }
129
130 pub fn set_primary_bin_override(&mut self, key: HashBinary) {
132 self.primary_bin_override = Some(key)
133 }
134
135 pub fn primary_key_str(&self) -> Option<&str> {
137 std::str::from_utf8(&self.primary).ok()
138 }
139
140 pub fn namespace_str(&self) -> Option<&str> {
142 std::str::from_utf8(&self.namespace).ok()
143 }
144}
145
146#[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
149pub struct CompactCacheKey {
150 pub primary: HashBinary,
151 pub variance: Option<Box<HashBinary>>,
153 pub user_tag: Box<str>, }
155
156impl Display for CompactCacheKey {
157 fn fmt(&self, f: &mut Formatter) -> FmtResult {
158 write!(f, "{}", hex2str(&self.primary))?;
159 if let Some(var) = &self.variance {
160 write!(f, ", variance: {}", hex2str(var.as_ref()))?;
161 }
162 write!(f, ", user_tag: {}", self.user_tag)
163 }
164}
165
166impl CacheHashKey for CompactCacheKey {
167 fn primary_bin(&self) -> HashBinary {
168 self.primary
169 }
170
171 fn variance_bin(&self) -> Option<HashBinary> {
172 self.variance.as_ref().map(|s| *s.as_ref())
173 }
174
175 fn user_tag(&self) -> &str {
176 &self.user_tag
177 }
178}
179
180pub(crate) type Blake2b128 = Blake2b<blake2::digest::consts::U16>;
190
191pub fn hash_u8(key: &str) -> u8 {
193 let mut hasher = Blake2b128::new();
194 hasher.update(key);
195 let raw = hasher.finalize();
196 raw[0]
197}
198
199pub fn hash_key<K: AsRef<[u8]>>(key: K) -> HashBinary {
201 let mut hasher = Blake2b128::new();
202 hasher.update(key.as_ref());
203 let raw = hasher.finalize();
204 raw.into()
205}
206
207impl CacheKey {
208 fn primary_hasher(&self) -> Blake2b128 {
209 let mut hasher = Blake2b128::new();
210 hasher.update(&self.namespace);
211 hasher.update(&self.primary);
212 hasher
213 }
214
215 pub fn new<B1, B2, S>(namespace: B1, primary: B2, user_tag: S) -> Self
219 where
220 B1: Into<Vec<u8>>,
221 B2: Into<Vec<u8>>,
222 S: Into<String>,
223 {
224 CacheKey {
225 namespace: namespace.into(),
226 primary: primary.into(),
227 primary_bin_override: None,
228 variance: None,
229 user_tag: user_tag.into(),
230 extensions: Extensions::new(),
231 }
232 }
233
234 pub fn namespace(&self) -> &[u8] {
236 &self.namespace[..]
237 }
238
239 pub fn primary_key(&self) -> &[u8] {
241 &self.primary[..]
242 }
243
244 pub fn to_compact(&self) -> CompactCacheKey {
246 let primary = self.primary_bin();
247 CompactCacheKey {
248 primary,
249 variance: self.variance_bin().map(Box::new),
250 user_tag: self.user_tag.clone().into_boxed_str(),
251 }
252 }
253}
254
255impl CacheHashKey for CacheKey {
256 fn primary_bin(&self) -> HashBinary {
257 if let Some(primary_bin_override) = self.primary_bin_override {
258 primary_bin_override
259 } else {
260 self.primary_hasher().finalize().into()
261 }
262 }
263
264 fn variance_bin(&self) -> Option<HashBinary> {
265 self.variance
266 }
267
268 fn user_tag(&self) -> &str {
269 &self.user_tag
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_cache_key_hash() {
279 let key = CacheKey {
280 namespace: Vec::new(),
281 primary: b"aa".to_vec(),
282 primary_bin_override: None,
283 variance: None,
284 user_tag: "1".into(),
285 extensions: Extensions::new(),
286 };
287 let hash = key.primary();
288 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
289 assert!(key.variance().is_none());
290 assert_eq!(key.combined(), hash);
291 let compact = key.to_compact();
292 assert_eq!(compact.primary(), hash);
293 assert!(compact.variance().is_none());
294 assert_eq!(compact.combined(), hash);
295 }
296
297 #[test]
298 fn test_cache_key_hash_override() {
299 let mut key = CacheKey {
300 namespace: Vec::new(),
301 primary: b"aa".to_vec(),
302 primary_bin_override: str2hex("27c35e6e9373877f29e562464e46497e"),
303 variance: None,
304 user_tag: "1".into(),
305 extensions: Extensions::new(),
306 };
307 let hash = key.primary();
308 assert_eq!(hash, "27c35e6e9373877f29e562464e46497e");
309 assert!(key.variance().is_none());
310 assert_eq!(key.combined(), hash);
311 let compact = key.to_compact();
312 assert_eq!(compact.primary(), hash);
313 assert!(compact.variance().is_none());
314 assert_eq!(compact.combined(), hash);
315
316 key.set_primary_bin_override(str2hex("004174d3e75a811a5b44c46b3856f3ee").unwrap());
318 let hash = key.primary();
319 assert_eq!(hash, "004174d3e75a811a5b44c46b3856f3ee");
320 assert!(key.variance().is_none());
321 assert_eq!(key.combined(), hash);
322 let compact = key.to_compact();
323 assert_eq!(compact.primary(), hash);
324 assert!(compact.variance().is_none());
325 assert_eq!(compact.combined(), hash);
326 }
327
328 #[test]
329 fn test_cache_key_vary_hash() {
330 let key = CacheKey {
331 namespace: Vec::new(),
332 primary: b"aa".to_vec(),
333 primary_bin_override: None,
334 variance: Some([0u8; 16]),
335 user_tag: "1".into(),
336 extensions: Extensions::new(),
337 };
338 let hash = key.primary();
339 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
340 assert_eq!(key.variance().unwrap(), "00000000000000000000000000000000");
341 assert_eq!(key.combined(), "004174d3e75a811a5b44c46b3856f3ee");
342 let compact = key.to_compact();
343 assert_eq!(compact.primary(), "ac10f2aef117729f8dad056b3059eb7e");
344 assert_eq!(
345 compact.variance().unwrap(),
346 "00000000000000000000000000000000"
347 );
348 assert_eq!(compact.combined(), "004174d3e75a811a5b44c46b3856f3ee");
349 }
350
351 #[test]
352 fn test_cache_key_vary_hash_override() {
353 let key = CacheKey {
354 namespace: Vec::new(),
355 primary: b"saaaad".to_vec(),
356 primary_bin_override: str2hex("ac10f2aef117729f8dad056b3059eb7e"),
357 variance: Some([0u8; 16]),
358 user_tag: "1".into(),
359 extensions: Extensions::new(),
360 };
361 let hash = key.primary();
362 assert_eq!(hash, "ac10f2aef117729f8dad056b3059eb7e");
363 assert_eq!(key.variance().unwrap(), "00000000000000000000000000000000");
364 assert_eq!(key.combined(), "004174d3e75a811a5b44c46b3856f3ee");
365 let compact = key.to_compact();
366 assert_eq!(compact.primary(), "ac10f2aef117729f8dad056b3059eb7e");
367 assert_eq!(
368 compact.variance().unwrap(),
369 "00000000000000000000000000000000"
370 );
371 assert_eq!(compact.combined(), "004174d3e75a811a5b44c46b3856f3ee");
372 }
373
374 #[test]
375 fn test_hex_str() {
376 let mut key = [0; KEY_SIZE];
377 for (i, v) in key.iter_mut().enumerate() {
378 *v = i as u8;
380 }
381 let hex_str = hex2str(&key);
382 let key2 = str2hex(&hex_str).unwrap();
383 for i in 0..KEY_SIZE {
384 assert_eq!(key[i], key2[i]);
385 }
386 }
387 #[test]
388 fn test_primary_key_str_valid_utf8() {
389 let valid_utf8_key = CacheKey {
390 namespace: Vec::new(),
391 primary: b"/valid/path?query=1".to_vec(),
392 primary_bin_override: None,
393 variance: None,
394 user_tag: "1".into(),
395 extensions: Extensions::new(),
396 };
397
398 assert_eq!(
399 valid_utf8_key.primary_key_str(),
400 Some("/valid/path?query=1")
401 )
402 }
403
404 #[test]
405 fn test_primary_key_str_invalid_utf8() {
406 let invalid_utf8_key = CacheKey {
407 namespace: Vec::new(),
408 primary: vec![0x66, 0x6f, 0x6f, 0xff],
409 primary_bin_override: None,
410 variance: None,
411 user_tag: "1".into(),
412 extensions: Extensions::new(),
413 };
414
415 assert!(invalid_utf8_key.primary_key_str().is_none())
416 }
417}