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}