1use crate::util::hash128;
2use hayro_syntax::object::{Dict, ObjectIdentifier, Stream};
3use kurbo::Affine;
4use std::any::Any;
5use std::collections::HashMap;
6use std::collections::hash_map::Entry;
7use std::sync::{Arc, Mutex};
8
9type CacheMap = HashMap<ObjectIdentifier, Option<Box<dyn Any + Send + Sync>>>;
10#[derive(Clone)]
11pub(crate) struct Cache(Arc<Mutex<CacheMap>>);
12
13impl Default for Cache {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl Cache {
20 pub fn new() -> Self {
21 Self(Arc::new(Mutex::new(HashMap::new())))
22 }
23
24 pub fn get_or_insert_with<T: Clone + Send + Sync + 'static>(
25 &self,
26 id: ObjectIdentifier,
27 f: impl FnOnce() -> Option<T>,
28 ) -> Option<T> {
29 let mut locked = self.0.lock().unwrap();
30
31 match locked.entry(id) {
34 Entry::Occupied(o) => o
35 .get()
36 .as_ref()
37 .and_then(|val| val.downcast_ref::<T>().cloned()),
38 Entry::Vacant(_) => {
39 drop(locked);
40 let val = f();
41 self.0.lock().unwrap().insert(
42 id,
43 val.clone()
44 .map(|val| Box::new(val) as Box<dyn Any + Send + Sync>),
45 );
46
47 val
48 }
49 }
50 }
51}
52
53pub trait CacheKey {
55 fn cache_key(&self) -> u128;
57}
58
59impl<T: CacheKey, U: CacheKey> CacheKey for (T, U) {
60 fn cache_key(&self) -> u128 {
61 hash128(&(self.0.cache_key(), self.1.cache_key()))
62 }
63}
64
65impl CacheKey for Dict<'_> {
66 fn cache_key(&self) -> u128 {
67 self.obj_id()
68 .map(|o| hash128(&o))
69 .unwrap_or(hash128(self.data()))
70 }
71}
72
73impl CacheKey for Stream<'_> {
74 fn cache_key(&self) -> u128 {
75 self.dict().cache_key()
76 }
77}
78
79impl CacheKey for Affine {
80 fn cache_key(&self) -> u128 {
81 let c = self.as_coeffs();
82 hash128(&[
83 c[0].to_bits(),
84 c[1].to_bits(),
85 c[2].to_bits(),
86 c[3].to_bits(),
87 c[4].to_bits(),
88 c[5].to_bits(),
89 ])
90 }
91}