hayro_interpret/
cache.rs

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        // 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        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}