1use crate::{validation::Error, Ref, Value};
2use std::collections::HashMap;
3use std::sync::RwLock;
4
5pub struct Cache<T>(RwLock<HashMap<String, Ref<T>>>);
7
8impl<T> Default for Cache<T> {
9 #[inline]
10 fn default() -> Self {
11 Self(Default::default())
12 }
13}
14
15impl<T: Value> Cache<T> {
16 #[inline]
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn get_or_add(&self, name: &str, create: &dyn Fn(&str) -> Result<T, Error>) -> Result<Ref<T>, Error> {
29 let cache = self.0.read().unwrap();
30
31 if let Some(options) = cache.get(name) {
32 return Ok(options.clone());
33 }
34
35 drop(cache);
36
37 let options = Ref::new(create(name)?);
38 let mut cache = self.0.write().unwrap();
39
40 if let Some(options) = cache.get(name) {
41 Ok(options.clone())
42 } else {
43 cache.insert(name.to_owned(), options.clone());
44 Ok(options)
45 }
46 }
47
48 #[must_use]
59 pub fn try_add(&self, name: &str, options: T) -> bool {
60 let mut cache = self.0.write().unwrap();
61
62 if cache.contains_key(name) {
63 false
64 } else {
65 cache.insert(name.into(), Ref::new(options));
66 true
67 }
68 }
69
70 pub fn remove(&self, name: &str) -> bool {
80 self.0.write().unwrap().remove(name).is_some()
81 }
82
83 pub fn clear(&self) {
85 self.0.write().unwrap().clear()
86 }
87}