1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;
use std::cmp::PartialEq;
use crate::utils::{
BoxRefCell,
EqBox,
};
type CreateType<K, V> = EqBox<Box<dyn Fn(&K) -> V>>;
#[derive(PartialEq, Clone)]
pub struct AutoMap<K: Eq + Hash + Clone, V: PartialEq + Clone + 'static> {
create: Rc<CreateType<K, V>>,
values: Rc<EqBox<BoxRefCell<HashMap<K, V>>>>,
}
impl<K: Eq + Hash + Clone, V: PartialEq + Clone + 'static> AutoMap<K, V> {
pub fn new<C: Fn(&K) -> V + 'static>(create: C) -> AutoMap<K, V> {
AutoMap {
create: Rc::new(EqBox::new(Box::new(create))),
values: Rc::new(EqBox::new(BoxRefCell::new(HashMap::new(), "auto map box values"))),
}
}
pub fn get_value(&self, key: &K) -> V {
let item: Option<V> = self.values.get_with_context(
key,
|state, key| -> Option<V> {
let item = (*state).get(key);
if let Some(item) = item {
return Some(item.clone());
}
None
}
);
if let Some(item) = item {
return item;
}
let new_item = {
let create = &self.create;
create(key)
};
self.values.change(
(key, &new_item),
|state, (key, new_item)| {
(*state).insert(key.clone(), new_item.clone());
}
);
new_item
}
}