1use runmat_builtins::Value;
2use runmat_gc::{
3 gc_register_root, gc_unregister_root, GlobalRoot, RootId, StackRoot, VariableArrayRoot,
4};
5
6pub struct InterpretContext {
8 pub(crate) stack_root_id: Option<RootId>,
9 pub(crate) vars_root_id: Option<RootId>,
10 pub(crate) extra_root_ids: Vec<RootId>,
11}
12
13impl InterpretContext {
14 pub fn new(stack: &Vec<Value>, vars: &Vec<Value>) -> Result<Self, String> {
15 let stack_root = Box::new(unsafe {
16 StackRoot::new(stack as *const Vec<Value>, "interpreter_stack".to_string())
17 });
18 let vars_root = Box::new(unsafe {
19 VariableArrayRoot::new(vars as *const Vec<Value>, "interpreter_vars".to_string())
20 });
21
22 let stack_root_id = gc_register_root(stack_root)
23 .map_err(|e| format!("Failed to register stack root: {e:?}"))?;
24 let vars_root_id = gc_register_root(vars_root)
25 .map_err(|e| format!("Failed to register vars root: {e:?}"))?;
26
27 Ok(InterpretContext {
28 stack_root_id: Some(stack_root_id),
29 vars_root_id: Some(vars_root_id),
30 extra_root_ids: Vec::new(),
31 })
32 }
33
34 pub fn register_global_values(
35 &mut self,
36 values: Vec<Value>,
37 description: &str,
38 ) -> Result<(), String> {
39 if values.is_empty() {
40 return Ok(());
41 }
42 let root = Box::new(GlobalRoot::new(values, description.to_string()));
43 let id =
44 gc_register_root(root).map_err(|e| format!("Failed to register global root: {e:?}"))?;
45 self.extra_root_ids.push(id);
46 Ok(())
47 }
48}
49
50impl Drop for InterpretContext {
51 fn drop(&mut self) {
52 if let Some(id) = self.stack_root_id.take() {
53 let _ = gc_unregister_root(id);
54 }
55 if let Some(id) = self.vars_root_id.take() {
56 let _ = gc_unregister_root(id);
57 }
58 while let Some(id) = self.extra_root_ids.pop() {
59 let _ = gc_unregister_root(id);
60 }
61 }
62}