simple_cache/
lib.rs

1use std::any::Any;
2use std::borrow::Borrow;
3use std::collections::HashMap;
4use std::hash::Hash;
5use std::sync::{Arc, RwLock};
6
7use arc_swap::ArcSwap;
8
9type AnyObject = Box<dyn Any + Send + Sync>;
10type CacheObject = ArcSwap<AnyObject>;
11type CacheResult<T> = Result<T, CacheError>;
12
13pub trait CacheItem: Send + Sync {}
14
15#[derive(Debug)]
16pub enum CacheError {
17    ReadError,
18    WriteError,
19    NotFound,
20    ValueMismatch,
21}
22
23#[derive(Clone)]
24pub struct Cache<K> {
25    items: Arc<RwLock<HashMap<K, Option<CacheObject>>>>,
26}
27
28impl<K> Cache<K>
29where
30    K: Eq + Hash,
31{
32    pub fn new() -> Self {
33        Self {
34            items: Arc::new(RwLock::new(HashMap::new())),
35        }
36    }
37
38    pub fn get<T: 'static + CacheItem, Q: ?Sized>(
39        &self,
40        key: &Q,
41    ) -> CacheResult<Option<Option<Arc<T>>>>
42    where
43        K: Borrow<Q>,
44        Q: Hash + Eq,
45    {
46        match self.items.read() {
47            Ok(map) => match map.get(key) {
48                Some(object) => match Self::downcast_object(object) {
49                    Ok(value) => Ok(Some(value)),
50                    Err(e) => Err(e),
51                },
52                None => Ok(None),
53            },
54            Err(_) => Err(CacheError::ReadError),
55        }
56    }
57
58    pub fn insert<T: 'static + CacheItem>(
59        &self,
60        key: K,
61        value: Option<T>,
62    ) -> CacheResult<Option<Arc<T>>> {
63        match self.items.write() {
64            Ok(mut map) => {
65                match map.insert(
66                    key,
67                    value.map(|value| {
68                        ArcSwap::new(Arc::new(Box::new(Arc::new(value)) as AnyObject))
69                    }),
70                ) {
71                    Some(object) => Self::downcast_object(&object),
72                    None => Ok(None),
73                }
74            }
75            Err(_) => Err(CacheError::WriteError),
76        }
77    }
78
79    pub fn remove<Q: ?Sized>(&self, key: &Q) -> CacheResult<Option<CacheObject>>
80    where
81        K: Borrow<Q>,
82        Q: Hash + Eq,
83    {
84        match self.items.write() {
85            Ok(mut map) => match map.remove(key) {
86                Some(value) => Ok(value),
87                None => Err(CacheError::NotFound),
88            },
89            Err(_) => Err(CacheError::WriteError),
90        }
91    }
92
93    fn downcast_object<T: 'static + CacheItem>(
94        object: &Option<CacheObject>,
95    ) -> CacheResult<Option<Arc<T>>> {
96        match object {
97            Some(object) => match object.load().downcast_ref::<Arc<T>>() {
98                Some(value) => Ok(Some(value.to_owned())),
99                None => Err(CacheError::ValueMismatch),
100            },
101            None => Ok(None),
102        }
103    }
104}
105
106impl<K> Default for Cache<K>
107where
108    K: Eq + Hash,
109{
110    fn default() -> Self {
111        Cache::new()
112    }
113}