1use std::fmt::Debug;
2use crate::cache::{Cache, CacheableRepr};
3use std::future::Future;
4use std::sync::Arc;
5use std::sync::RwLock;
6use tokio::task::{spawn_blocking, JoinHandle};
7
8pub(crate) struct CacheableRead<T, R: Clone + Sync + Send> {
9 read_fn: fn(&T) -> R,
10 cache: Arc<RwLock<Option<R>>>,
11}
12impl<T: Clone + Sync + Send + 'static, R: Clone + Sync + Send + 'static> CacheableRead<T, R> {
13 pub(crate) fn new(read_fn: fn(&T) -> R) -> Self {
14 Self {
15 read_fn,
16 cache: Default::default(),
17 }
18 }
19 pub(crate) fn read(&self, arg: &T) -> R {
20 let res = self.cache.read().unwrap();
21 if let Some(cached) = res.as_ref() {
22 return cached.clone();
23 }
24 (self.read_fn)(arg)
25 }
26
27 pub(crate) fn update(&self, value: &T) -> JoinHandle<()> {
28 let mut writer = self.cache.write().unwrap();
29 *writer = None;
30 let cell = self.cache.clone();
31 let read_fn = self.read_fn;
32 let value = value.clone();
33 spawn_blocking(move || {
34 let value = value;
35 let mut writer = cell.write().unwrap();
36 *writer = Some(read_fn(&value));
37 })
38 }
39}
40impl<T: 'static + Sync + Send + Clone, R: Clone + 'static + Send + Sync> Cache<T> for CacheableRead<T, R> {
41 fn notify(&self, value: &T) {
42 self.update(value);
43 }
44}
45
46#[cfg(feature = "eager")]
47pub trait EagerCacheLookup<T: Clone + Sync + Send + 'static, I: Fn(&T) -> bool> {
48 fn eager<R: Clone + Clone + Sync + Send + 'static>(&mut self, read_fn: fn(&T) -> R) -> impl Future<Output=R>;
49 fn unregister<R: Clone + Clone + Sync + Send + 'static>(&mut self, read_fn: fn(&T) -> R) -> bool;
50}
51#[cfg(feature = "eager")]
52impl<T: Debug + Clone + Sync + Send + 'static, I: Fn(&T) -> bool> EagerCacheLookup<T, I> for CacheableRepr<T, I> {
53 #[allow(clippy::await_holding_refcell_ref)] async fn eager<R: Clone + Sync + Send + 'static>(&mut self, read_fn: fn(&T) -> R) -> R {
95 let fn_identity = read_fn as *const fn(&T) -> R as usize;
96 let is_empty = !self.eager_caches.contains_key(&fn_identity);
97 let entry = self.eager_caches.entry(fn_identity);
98
99 let cache = entry.or_insert_with(|| Box::new(CacheableRead::<T, R>::new(read_fn)));
100 let cache = cache.downcast_mut::<CacheableRead<T, R>>().unwrap();
101 let data = self.inner.inner.get_mut();
102 if is_empty {
103 cache.update(data).await.unwrap();
104 }
105 cache.read(data)
106 }
107 fn unregister<R: Clone + Clone + Sync + Send + 'static>(&mut self, read_fn: fn(&T) -> R) -> bool {
109 let fn_identity = read_fn as *const fn(&T) -> R as usize;
110 self.eager_caches.remove(&fn_identity).is_some()
111 }
112}