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}
26
27pub struct BindingGuard;
31
32impl Drop for BindingGuard {
33 fn drop(&mut self) {
34 pop_frame();
35 }
36}
37
38pub fn push_frame(bindings: HashMap<VarKey, Value>) -> BindingGuard {
42 BINDING_STACK.with(|s| s.borrow_mut().push(bindings));
43 BindingGuard
44}
45
46fn pop_frame() {
47 BINDING_STACK.with(|s| {
48 s.borrow_mut().pop();
49 });
50}
51
52pub fn deref_var(var: &GcPtr<Var>) -> Option<Value> {
57 let key = var_key_of(var);
58 let tl = BINDING_STACK.with(|s| {
59 s.borrow()
60 .iter()
61 .rev()
62 .find_map(|frame| frame.get(&key).cloned())
63 });
64 tl.or_else(|| var.get().deref())
65}
66
67pub fn is_thread_bound(var: &GcPtr<Var>) -> bool {
69 let key = var_key_of(var);
70 BINDING_STACK.with(|s| s.borrow().iter().any(|frame| frame.contains_key(&key)))
71}
72
73pub fn set_thread_local(var: &GcPtr<Var>, val: Value) -> bool {
77 let key = var_key_of(var);
78 BINDING_STACK.with(|s| {
79 for frame in s.borrow_mut().iter_mut().rev() {
80 if let std::collections::hash_map::Entry::Occupied(mut e) = frame.entry(key) {
81 e.insert(val);
82 return true;
83 }
84 }
85 false
86 })
87}
88
89pub fn capture_current() -> Vec<HashMap<VarKey, Value>> {
94 BINDING_STACK.with(|s| s.borrow().clone())
95}
96
97pub fn install_frames(frames: Vec<HashMap<VarKey, Value>>) {
99 BINDING_STACK.with(|s| *s.borrow_mut() = frames);
100}
101
102pub fn trace_current(visitor: &mut cljrs_gc::MarkVisitor) {
107 BINDING_STACK.with(|s| {
108 for frame in s.borrow().iter() {
109 for val in frame.values() {
110 val.trace(visitor);
111 }
112 }
113 });
114}