tokio_cache/
async_cache.rs

1use std::borrow::Borrow;
2use std::fmt::{self, Debug};
3use std::future::Future;
4use std::hash::Hash;
5use std::sync::Arc;
6
7use crate::core::{CacheCore, ExpireEntry};
8
9struct Never;
10
11impl<V> ExpireEntry<V> for Never {
12    fn is_fresh(&self, _: &V) -> bool {
13        true
14    }
15}
16
17/// A cache where reads are wait-free and where writes are asynchronous, such as it can be used
18/// within code that cannot block.
19#[derive(Clone)]
20pub struct AsyncCache<K, V>
21where
22    K: Hash + Eq + Clone,
23    V: Clone,
24{
25    core: Arc<CacheCore<K, V>>,
26}
27
28impl<K, V> AsyncCache<K, V>
29where
30    K: Hash + Eq + Clone,
31    V: Clone,
32{
33    pub fn new() -> Self {
34        AsyncCache {
35            core: Arc::new(CacheCore::new()),
36        }
37    }
38
39    /// Reads the cached entry for the given key.
40    ///
41    /// Note that this will not block.
42    pub fn read<BK>(&self, key: &BK) -> Option<V>
43    where
44        BK: Hash + Eq + ?Sized,
45        K: Borrow<BK>,
46    {
47        self.core.read(key, &Never)
48    }
49
50    /// Writes the result of the given `future` in the cache at entry `key`.
51    ///
52    /// If multiple writes, concurrent or not, on the same key are issued, only one of the futures
53    /// will be polled and the others will be dropped.
54    pub async fn write<F, E>(&self, key: K, future: F) -> Result<V, E>
55    where
56        F: Future<Output = Result<V, E>>,
57    {
58        if let Some(value) = self.read(&key) {
59            return Ok(value)
60        }
61
62        self.core.write(key, future, &Never).await
63    }
64}
65
66impl<K, V> Debug for AsyncCache<K, V>
67where
68    K: Hash + Eq + Clone + Debug,
69    V: Clone + Debug,
70{
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        f.debug_struct("AsyncCache")
73            .field("entries", &self.core)
74            .finish()
75    }
76}
77
78impl<K, V> Default for AsyncCache<K, V>
79where
80    K: Hash + Eq + Clone + Debug,
81    V: Clone + Debug,
82{
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::AsyncCache;
91
92    #[tokio::test]
93    async fn insert_then_get_single_entry() {
94        let cache = AsyncCache::new();
95
96        assert_eq!(None, cache.read(&1));
97        assert_eq!(
98            Ok(2),
99            cache.write(1, async { Result::<_, ()>::Ok(2) }).await
100        );
101        assert_eq!(Some(2), cache.read(&1));
102    }
103
104    #[tokio::test]
105    async fn writing_twice_does_not_override() {
106        let cache = AsyncCache::new();
107
108        assert_eq!(None, cache.read(&1));
109        assert_eq!(
110            Ok(2),
111            cache.write(1, async { Result::<_, ()>::Ok(2) }).await
112        );
113        assert_eq!(Some(2), cache.read(&1));
114        assert_eq!(
115            Ok(2),
116            cache.write(1, async { Result::<_, ()>::Ok(3) }).await
117        );
118        assert_eq!(Some(2), cache.read(&1));
119    }
120}