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}