hayro_interpret/
cache.rs

1use crate::util::hash128;
2use hayro_syntax::object::{Array, Dict, MaybeRef, Name, Null, ObjRef, Object, 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<u128, 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(crate) fn new() -> Self {
21        Self(Arc::new(Mutex::new(HashMap::new())))
22    }
23
24    pub(crate) fn get_or_insert_with<T: Clone + Send + Sync + 'static>(
25        &self,
26        id: u128,
27        f: impl FnOnce() -> Option<T>,
28    ) -> Option<T> {
29        let mut locked = self.0.lock().unwrap();
30
31        // We can't use `get_or_insert_with` here, because if the closure makes another access to the
32        // cache, we end up with a deadlock.
33        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
53/// A trait for objects that can generate a unique cache key.
54pub trait CacheKey {
55    /// Returns the cache key for this object.
56    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        hash128(self.data())
68    }
69}
70
71impl CacheKey for Stream<'_> {
72    fn cache_key(&self) -> u128 {
73        self.dict().cache_key()
74    }
75}
76
77impl CacheKey for Null {
78    fn cache_key(&self) -> u128 {
79        hash128(self)
80    }
81}
82
83impl CacheKey for bool {
84    fn cache_key(&self) -> u128 {
85        hash128(self)
86    }
87}
88
89impl CacheKey for hayro_syntax::object::Number {
90    fn cache_key(&self) -> u128 {
91        hash128(&self.as_f64().to_bits())
92    }
93}
94
95impl CacheKey for hayro_syntax::object::String<'_> {
96    fn cache_key(&self) -> u128 {
97        hash128(self.get().as_ref())
98    }
99}
100
101impl CacheKey for Name<'_> {
102    fn cache_key(&self) -> u128 {
103        hash128(self)
104    }
105}
106
107impl CacheKey for Array<'_> {
108    fn cache_key(&self) -> u128 {
109        hash128(self.data())
110    }
111}
112
113impl CacheKey for Object<'_> {
114    fn cache_key(&self) -> u128 {
115        match self {
116            Object::Null(n) => n.cache_key(),
117            Object::Boolean(b) => b.cache_key(),
118            Object::Number(n) => n.cache_key(),
119            Object::String(s) => s.cache_key(),
120            Object::Name(n) => n.cache_key(),
121            Object::Dict(d) => d.cache_key(),
122            Object::Array(a) => a.cache_key(),
123            Object::Stream(s) => s.cache_key(),
124        }
125    }
126}
127
128impl CacheKey for ObjRef {
129    fn cache_key(&self) -> u128 {
130        hash128(self)
131    }
132}
133
134impl<T: CacheKey> CacheKey for MaybeRef<T> {
135    fn cache_key(&self) -> u128 {
136        match self {
137            Self::Ref(r) => r.cache_key(),
138            Self::NotRef(o) => o.cache_key(),
139        }
140    }
141}
142
143impl CacheKey for Affine {
144    fn cache_key(&self) -> u128 {
145        let c = self.as_coeffs();
146        hash128(&[
147            c[0].to_bits(),
148            c[1].to_bits(),
149            c[2].to_bits(),
150            c[3].to_bits(),
151            c[4].to_bits(),
152            c[5].to_bits(),
153        ])
154    }
155}
156
157impl CacheKey for u128 {
158    fn cache_key(&self) -> u128 {
159        hash128(self)
160    }
161}