Skip to main content

options/
cache.rs

1use crate::{validation::Error, Ref, Value};
2use std::collections::HashMap;
3use std::sync::RwLock;
4
5/// Represents a monitored cache of configured options.
6pub 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    /// Initializes a new options [Cache].
17    #[inline]
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    /// Gets or adds options with the specified name.
23    ///
24    /// # Arguments
25    ///
26    /// * `name` - The optional name of the options
27    /// * `create` - The function used to create options when added
28    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    /// Attempts to add options with the specified name.
49    ///
50    /// # Arguments
51    ///
52    /// * `name` - The optional name of the options
53    /// * `options` - The options to add
54    ///
55    /// # Remarks
56    ///
57    /// Returns `true` if the options were added; otherwise, `false`. Options are not added if they already exist.
58    #[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    /// Removes options with the specified name, if any.
71    ///
72    /// # Arguments
73    ///
74    /// * `name` - The optional name of the options
75    ///
76    /// # Remarks
77    ///
78    /// Returns `true` if any options were removed; otherwise, `false`.
79    pub fn remove(&self, name: &str) -> bool {
80        self.0.write().unwrap().remove(name).is_some()
81    }
82
83    /// Clears all options from the cache.
84    pub fn clear(&self) {
85        self.0.write().unwrap().clear()
86    }
87}