rumtk_core/
cache.rs

1/*
2 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
3 * This toolkit aims to be reliable, simple, performant, and standards compliant.
4 * Copyright (C) 2024  Luis M. Santos, M.D.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21pub use ahash::AHashMap;
22use core::hash::Hash;
23pub use once_cell::unsync::Lazy;
24use std::sync::Arc;
25pub use std::sync::Mutex;
26/**************************** Constants**************************************/
27pub const DEFAULT_CACHE_PAGE_SIZE: usize = 10;
28/// I don't think most scenarios will need more than 10 items worth of memory pre-allocated at a time.
29/**************************** Caches ****************************************/
30
31/**************************** Types *****************************************/
32///
33/// Generic Cache store object. One use case will be to use a search string as the key and store
34/// the search parsing object here.
35///
36pub type RUMCache<K, V> = AHashMap<K, V>;
37pub type LazyRUMCache<K, V> = Lazy<Arc<RUMCache<K, V>>>;
38
39/**************************** Traits ****************************************/
40
41/**************************** Helpers ***************************************/
42pub const fn new_cache<K, V>() -> LazyRUMCache<K, V> {
43    LazyRUMCache::new(|| Arc::new(RUMCache::with_capacity(DEFAULT_CACHE_PAGE_SIZE)))
44}
45
46pub fn get_or_set_from_cache<'a, K, V, F>(
47    cache: &'a mut LazyRUMCache<K, V>,
48    expr: &K,
49    new_fn: F,
50) -> &'a V
51where
52    K: Hash + Eq + Clone,
53    V: Clone,
54    F: Fn(&K) -> V,
55{
56    if !cache.contains_key(expr) {
57        let mut cache_ref = Arc::get_mut(cache).unwrap();
58        cache_ref.insert(expr.clone(), new_fn(expr).clone());
59    }
60    cache.get(expr).unwrap()
61}
62
63pub mod cache_macros {
64    ///
65    /// Searches for item in global cache. If global cache lacks item, create item using factory
66    /// function passed to this macro.
67    ///
68    /// ```
69    /// use crate::rumtk_core::rumtk_cache_fetch;
70    /// use crate::rumtk_core::cache::{new_cache, LazyRUMCache};
71    /// use std::sync::Arc;
72    ///
73    /// type StringCache = LazyRUMCache<String, String>;
74    ///
75    /// fn init_cache(k: &String) -> String {
76    ///    String::from(k)
77    /// }
78    ///
79    /// let mut cache: StringCache = new_cache();
80    ///
81    /// let test_key: String = String::from("Hello World");
82    /// let v = rumtk_cache_fetch!(
83    ///     &mut cache,
84    ///     &test_key,
85    ///     init_cache
86    /// );
87    ///
88    /// assert_eq!(test_key.as_str(), v.as_str(), "The inserted key is not the same to what was passed as input!");
89    ///
90    ///
91    /// ```
92    ///
93    #[macro_export]
94    macro_rules! rumtk_cache_fetch {
95        ( $cache:expr, $key:expr, $func:expr ) => {{
96            use $crate::cache::get_or_set_from_cache;
97            unsafe { get_or_set_from_cache($cache, $key, $func) }
98        }};
99    }
100}