tiny_web/sys/
cache.rs

1use std::{
2    collections::{btree_map::Entry, BTreeMap},
3    sync::Arc,
4};
5
6use tokio::sync::Mutex;
7
8use crate::fnv1a_64;
9
10use super::data::Data;
11
12/// Data caching module.
13///
14/// # Values
15///
16/// * `data: BTreeMap<u64, Data>` - Cache data;
17/// * `keys: Vec<String>` - Stored keys.
18///
19/// # Notice
20///
21/// All `Keys` encode in fnv1a_64.
22///
23/// A cache is a simple set of `Key`=`Value`.
24/// A `key` is a unique string, but can be grouped by pattern.
25/// To do this, you need to insert the symbol `:` into the line.
26/// This does not change the logic of the cache in any way, other than removing data from it.
27///
28/// If `key` ends with a `:`, all data beginning with that key is deleted.
29///
30/// # Security
31///
32/// With a large cache, the `del` operation can block it for a long time.
33#[derive(Debug)]
34pub(crate) struct CacheSys {
35    /// Cache data.
36    data: CacheKey,
37}
38
39#[derive(Debug)]
40enum CacheKey {
41    Last(Data),
42    More(BTreeMap<i64, CacheKey>),
43}
44
45impl CacheSys {
46    /// Initializes data caching module
47    pub async fn new() -> Arc<Mutex<CacheSys>> {
48        Arc::new(Mutex::new(CacheSys { data: CacheKey::More(BTreeMap::new()) }))
49    }
50
51    /// Returns cloned data
52    pub async fn get(cache: Arc<Mutex<CacheSys>>, keys: &[i64]) -> Option<Data> {
53        if keys.is_empty() {
54            return None;
55        }
56
57        let c = cache.lock().await;
58        let mut last = &c.data;
59        for key in keys {
60            match last {
61                CacheKey::Last(_) => return None,
62                CacheKey::More(m) => {
63                    last = m.get(key)?;
64                }
65            }
66        }
67        match last {
68            CacheKey::Last(d) => Some(d.clone()),
69            CacheKey::More(_) => None,
70        }
71    }
72
73    /// Inserts a data
74    pub async fn set<T>(cache: Arc<Mutex<CacheSys>>, keys: &[i64], data: T)
75    where
76        T: Into<Data>,
77    {
78        if keys.is_empty() {
79            return;
80        }
81        let key_last = unsafe { keys.get_unchecked(keys.len() - 1) };
82        let mut c = cache.lock().await;
83        let mut last = &mut c.data;
84
85        for key in &keys[..keys.len() - 1] {
86            match last {
87                CacheKey::Last(_) => {
88                    *last = CacheKey::More(BTreeMap::new());
89                    match last {
90                        CacheKey::More(m) => {
91                            last = m.entry(*key).or_insert_with(|| CacheKey::More(BTreeMap::new()));
92                        }
93                        _ => unreachable!(),
94                    }
95                }
96                CacheKey::More(m) => {
97                    last = m.entry(*key).or_insert_with(|| CacheKey::More(BTreeMap::new()));
98                }
99            }
100        }
101        match last {
102            CacheKey::Last(_) => {
103                *last = CacheKey::More(BTreeMap::new());
104                match last {
105                    CacheKey::More(m) => match m.entry(*key_last) {
106                        Entry::Vacant(v) => {
107                            v.insert(CacheKey::Last(data.into()));
108                        }
109                        Entry::Occupied(mut o) => {
110                            let v = o.get_mut();
111                            *v = CacheKey::Last(data.into());
112                        }
113                    },
114                    _ => unreachable!(),
115                }
116            }
117            CacheKey::More(m) => match m.entry(*key_last) {
118                Entry::Vacant(v) => {
119                    v.insert(CacheKey::Last(data.into()));
120                }
121                Entry::Occupied(mut o) => {
122                    let v = o.get_mut();
123                    *v = CacheKey::Last(data.into());
124                }
125            },
126        }
127    }
128
129    /// Removes a key.
130    ///
131    /// If `key` ends with a `:` character, all data beginning with that `key` is deleted.
132    ///
133    /// # Safety
134    ///
135    /// With a large cache, this operation can block it for a long time.
136    pub async fn del(cache: Arc<Mutex<CacheSys>>, keys: &[i64]) {
137        if keys.is_empty() {
138            return;
139        }
140        let key_last = unsafe { keys.get_unchecked(keys.len() - 1) };
141        let mut c = cache.lock().await;
142        let mut last = &mut c.data;
143        for key in &keys[..keys.len() - 1] {
144            match last {
145                CacheKey::Last(_) => return,
146                CacheKey::More(m) => {
147                    match m.get_mut(key) {
148                        Some(s) => last = s,
149                        None => return,
150                    };
151                }
152            }
153        }
154        if let CacheKey::More(m) = last {
155            m.remove(key_last);
156        }
157    }
158
159    /// Clear all cache
160    pub async fn clear(cache: Arc<Mutex<CacheSys>>) {
161        let mut c = cache.lock().await;
162        if let CacheKey::More(m) = &mut c.data {
163            m.clear()
164        }
165    }
166
167    /// Converts &str to Vec<i64> with ":" separator and hash function fnv1a_64
168    pub fn get_hash(key: &str) -> Vec<i64> {
169        let mut count = 1;
170        let keys = key.as_bytes();
171        for item in keys {
172            if *item == b':' {
173                count += 1;
174            }
175        }
176        let mut vec = Vec::with_capacity(count);
177        if count > 1 {
178            let mut start = 0;
179            let mut index = 0;
180            for item in keys {
181                if *item == b':' {
182                    vec.push(fnv1a_64(&keys[start..index]));
183                    start = index + 1;
184                }
185                index += 1;
186            }
187            vec.push(fnv1a_64(&keys[start..index]));
188        } else {
189            vec.push(fnv1a_64(key.as_bytes()));
190        }
191        vec
192    }
193
194    pub async fn show(cache: Arc<Mutex<CacheSys>>) {
195        let c = cache.lock().await;
196        println!("{:?}", c.data)
197    }
198}
199
200pub trait StrOrArrI64 {
201    fn to_arr(self) -> Vec<i64>;
202}
203
204impl StrOrArrI64 for &str {
205    fn to_arr(self) -> Vec<i64> {
206        CacheSys::get_hash(self)
207    }
208}
209impl StrOrArrI64 for Vec<i64> {
210    fn to_arr(self) -> Vec<i64> {
211        self
212    }
213}
214
215/// Cache struct
216#[derive(Debug)]
217pub struct Cache {
218    cache: Arc<Mutex<CacheSys>>,
219}
220
221impl Cache {
222    /// Create new Cache instanse
223    pub(crate) fn new(cache: Arc<Mutex<CacheSys>>) -> Cache {
224        Cache { cache }
225    }
226
227    /// Get cache
228    pub async fn get<T>(&mut self, keys: T) -> (Option<Data>, Vec<i64>)
229    where
230        T: StrOrArrI64,
231    {
232        let key = keys.to_arr();
233        (CacheSys::get(Arc::clone(&self.cache), &key).await, key)
234    }
235
236    /// Set cache
237    pub async fn set<T, K>(&mut self, keys: T, data: K)
238    where
239        T: StrOrArrI64,
240        K: Into<Data>,
241    {
242        CacheSys::set(Arc::clone(&self.cache), &keys.to_arr(), data).await
243    }
244
245    /// Removes a key from the Cache.
246    ///
247    /// If `key` ends with a `:` character, all data beginning with that `key` is deleted.
248    pub async fn remove<T>(&mut self, keys: T)
249    where
250        T: StrOrArrI64,
251    {
252        CacheSys::del(Arc::clone(&self.cache), &keys.to_arr()).await
253    }
254
255    /// Clear all cache
256    pub async fn clear(&mut self) {
257        CacheSys::clear(Arc::clone(&self.cache)).await
258    }
259
260    /// Show all data in cache
261    pub async fn show(&mut self) {
262        CacheSys::show(Arc::clone(&self.cache)).await
263    }
264}