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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use gcmodule::{Cc, Trace, Tracer};
use std::cell::RefCell;
use std::collections::HashMap;
#[derive(Clone)]
pub struct KvEnv<V: Trace>(Cc<RefCell<Inner<V>>>);
#[derive(Trace)]
struct Inner<V: Trace> {
parent: Option<KvEnv<V>>,
names: HashMap<String, V>,
}
impl<V: Trace> Trace for KvEnv<V> {
fn trace(&self, tracer: &mut Tracer) {
self.0.trace(tracer)
}
fn is_type_tracked() -> bool {
true
}
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
}
impl<V: Trace> Default for KvEnv<V> {
fn default() -> Self {
let inner = Inner {
parent: None,
names: HashMap::new(),
};
KvEnv(Cc::new(RefCell::new(inner)))
}
}
impl<V: Trace + Clone> KvEnv<V> {
pub fn get(&self, name: &str) -> Option<V> {
self.lookup(name).map(|v| v.1)
}
pub fn set_local(&self, name: &str, value: V) {
let mut inner = self.0.borrow_mut();
if let Some(existing_value) = inner.names.get_mut(name) {
*existing_value = value;
} else {
inner.names.insert(name.to_string(), value);
}
}
pub fn set(&self, name: &str, value: V) {
match self.lookup(name) {
Some((env, _)) => env.set_local(name, value),
None => self.set_local(name, value),
}
}
pub fn nested(&self) -> Self {
let inner = Inner {
parent: Some(self.clone()),
names: HashMap::new(),
};
KvEnv(Cc::new(RefCell::new(inner)))
}
fn lookup(&self, name: &str) -> Option<(Self, V)> {
let inner = self.0.borrow();
match inner.names.get(name) {
Some(v) => Some((self.clone(), v.clone())),
None => inner.parent.clone().and_then(|p| p.lookup(name)),
}
}
}