1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::cache::Cache;

use async_trait::async_trait;
use ttl_cache::TtlCache;

use std::hash::Hash;
use std::time::Duration;

pub struct DefaultCache<K, V>
where
    K: Eq + Hash + Send + Sync + 'static,
    V: Send + Sync + 'static,
{
    pub ttl: Duration,
    cache: TtlCache<K, V>,
}

impl<K, V> DefaultCache<K, V>
where
    K: Eq + Hash + Send + Sync + 'static,
    V: Send + Sync + 'static,
{
    pub fn new(cap: usize) -> DefaultCache<K, V> {
        DefaultCache {
            ttl: Duration::from_secs(120),
            cache: TtlCache::new(cap),
        }
    }
}

#[async_trait]
impl<K, V> Cache<K, V> for DefaultCache<K, V>
where
    K: Eq + Hash + Send + Sync + 'static,
    V: Send + Sync + 'static,
{
    fn set_capacity(&mut self, cap: usize) {
        self.cache.set_capacity(cap);
    }

    fn set_ttl(&mut self, ttl: Duration) {
        self.ttl = ttl;
    }

    async fn get<'a>(&'a self, k: &K) -> Option<&'a V> {
        self.cache.get(k)
    }

    async fn has(&self, k: &K) -> bool {
        self.cache.contains_key(k)
    }

    async fn set(&mut self, k: K, v: V) {
        if self.has(&k).await {
            self.cache.remove(&k);
        }
        self.cache.insert(k, v, self.ttl);
    }

    async fn clear(&mut self) {
        self.cache.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread::sleep;

    #[cfg_attr(feature = "runtime-async-std", async_std::test)]
    #[cfg_attr(feature = "runtime-tokio", tokio::test)]
    async fn test_set_and_get() {
        let mut cache = DefaultCache::new(1);

        cache.set(vec!["alice", "/data1", "read"], false).await;
        assert!(cache.get(&vec!["alice", "/data1", "read"]).await == Some(&false));
    }

    #[cfg_attr(feature = "runtime-async-std", async_std::test)]
    #[cfg_attr(feature = "runtime-tokio", tokio::test)]
    async fn test_set_ttl() {
        let mut cache = DefaultCache::new(1);
        cache.set_ttl(Duration::from_secs(2));

        cache.set(vec!["alice", "/data1", "read"], false).await;

        sleep(Duration::from_secs(1));
        assert!(cache.get(&vec!["alice", "/data1", "read"]).await == Some(&false));

        sleep(Duration::from_secs(2));
        assert!(!cache.has(&vec!["alice", "/data1", "read"]).await);
    }

    #[cfg_attr(feature = "runtime-async-std", async_std::test)]
    #[cfg_attr(feature = "runtime-tokio", tokio::test)]
    async fn test_capacity() {
        let mut cache = DefaultCache::new(1);

        cache.set(vec!["alice", "/data1", "read"], false).await;
        cache.set(vec!["bob", "/data2", "write"], false).await;
        assert!(!cache.has(&vec!["alice", "/data1", "read"]).await);
        assert!(cache.has(&vec!["bob", "/data2", "write"]).await);
    }

    #[cfg_attr(feature = "runtime-async-std", async_std::test)]
    #[cfg_attr(feature = "runtime-tokio", tokio::test)]
    async fn test_set_capacity() {
        let mut cache = DefaultCache::new(1);
        cache.set_capacity(2);

        cache.set(vec!["alice", "/data1", "read"], false).await;
        cache.set(vec!["bob", "/data2", "write"], false).await;
        cache
            .set(vec!["unknow", "/data3", "read_write"], false)
            .await;
        assert!(!cache.has(&vec!["alice", "/data1", "read"]).await);
        assert!(cache.has(&vec!["bob", "/data2", "write"]).await);
        assert!(cache.has(&vec!["unknow", "/data3", "read_write"]).await);
    }
}