vertigo/computed/
auto_map.rs

1use std::fmt::Debug;
2use std::{hash::Hash, rc::Rc};
3
4use crate::computed::struct_mut::HashMapMut;
5
6type CreateType<K, V> = Box<dyn Fn(&AutoMap<K, V>, &K) -> V>;
7
8fn get_unique_id() -> u64 {
9    use std::sync::atomic::{AtomicU64, Ordering};
10    static COUNTER: AtomicU64 = AtomicU64::new(1);
11    COUNTER.fetch_add(1, Ordering::Relaxed)
12}
13
14/// A structure similar to HashMap
15/// but allows to provide a function `create` for creating a new value if particular key doesn't exists.
16///
17/// Such a function can for example [fetch](struct.Driver.html#method.fetch) data from internet.
18///
19/// ```rust
20/// use vertigo::AutoMap;
21///
22/// let my_map = AutoMap::<i32, i32>::new(|_, x| x*2);
23/// assert_eq!(my_map.get(&5), 10);
24/// ```
25#[derive(Clone)]
26pub struct AutoMap<K, V> {
27    id: u64,
28    create: Rc<CreateType<K, V>>,
29    values: Rc<HashMapMut<K, V>>,
30}
31
32impl<K, V> Debug for AutoMap<K, V> {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("AutoMap").finish()
35    }
36}
37
38impl<K, V> PartialEq for AutoMap<K, V> {
39    fn eq(&self, other: &Self) -> bool {
40        self.id == other.id
41    }
42}
43
44impl<K: Eq + Hash + Clone, V: Clone> AutoMap<K, V> {
45    pub fn new<C: Fn(&AutoMap<K, V>, &K) -> V + 'static>(create: C) -> AutoMap<K, V> {
46        AutoMap {
47            id: get_unique_id(),
48            create: Rc::new(Box::new(create)),
49            values: Rc::new(HashMapMut::new()),
50        }
51    }
52
53    pub fn get(&self, key: &K) -> V {
54        let item: Option<V> = self.values.get(key);
55
56        if let Some(item) = item {
57            return item;
58        }
59
60        let new_item = {
61            let create = &self.create;
62            create(self, key)
63        };
64
65        self.values.insert(key.clone(), new_item.clone());
66
67        new_item
68    }
69}