cljrs_runtime/env/
dynamics.rs1use std::cell::RefCell;
8use std::collections::HashMap;
9
10use cljrs_gc::GcPtr;
11use cljrs_gc::Trace as _;
12use cljrs_value::{Value, Var};
13
14pub type VarKey = usize;
17
18pub fn var_key_of(var: &GcPtr<Var>) -> VarKey {
19 var.get() as *const Var as usize
20}
21
22thread_local! {
23 static BINDING_STACK: RefCell<Vec<HashMap<VarKey, Value>>> =
24 const { RefCell::new(Vec::new()) };
25}
26cljrs_gc::mutator_slot!("cljrs-runtime/BINDING_STACK", refcell BINDING_STACK: Vec<HashMap<VarKey, Value>>);
27
28pub struct BindingGuard;
32
33impl Drop for BindingGuard {
34 fn drop(&mut self) {
35 pop_frame();
36 }
37}
38
39pub fn push_frame(bindings: HashMap<VarKey, Value>) -> BindingGuard {
43 BINDING_STACK.with(|s| s.borrow_mut().push(bindings));
44 BindingGuard
45}
46
47pub fn take_frame(guard: BindingGuard) -> HashMap<VarKey, Value> {
52 std::mem::forget(guard);
53 BINDING_STACK.with(|s| s.borrow_mut().pop().unwrap_or_default())
54}
55
56fn pop_frame() {
57 BINDING_STACK.with(|s| {
58 s.borrow_mut().pop();
59 });
60}
61
62pub fn deref_var(var: &GcPtr<Var>) -> Option<Value> {
67 let key = var_key_of(var);
68 let tl = BINDING_STACK.with(|s| {
69 s.borrow()
70 .iter()
71 .rev()
72 .find_map(|frame| frame.get(&key).cloned())
73 });
74 tl.or_else(|| var.get().deref())
75}
76
77pub fn is_thread_bound(var: &GcPtr<Var>) -> bool {
79 let key = var_key_of(var);
80 BINDING_STACK.with(|s| s.borrow().iter().any(|frame| frame.contains_key(&key)))
81}
82
83pub fn set_thread_local(var: &GcPtr<Var>, val: Value) -> bool {
87 let key = var_key_of(var);
88 BINDING_STACK.with(|s| {
89 for frame in s.borrow_mut().iter_mut().rev() {
90 if let std::collections::hash_map::Entry::Occupied(mut e) = frame.entry(key) {
91 e.insert(val);
92 return true;
93 }
94 }
95 false
96 })
97}
98
99pub fn capture_current() -> Vec<HashMap<VarKey, Value>> {
104 BINDING_STACK.with(|s| s.borrow().clone())
105}
106
107pub fn install_frames(frames: Vec<HashMap<VarKey, Value>>) {
109 BINDING_STACK.with(|s| *s.borrow_mut() = frames);
110}
111
112pub fn trace_current(visitor: &mut cljrs_gc::MarkVisitor) {
117 BINDING_STACK.with(|s| {
118 for frame in s.borrow().iter() {
119 for val in frame.values() {
120 val.trace(visitor);
121 }
122 }
123 });
124}