1use std::collections::HashMap;
2
3use aiscript_arena::{Gc, RefLock};
4
5use crate::{
6 NativeFn, ReturnValue, Value,
7 builtins::response,
8 object::{Instance, Object},
9};
10
11use super::Vm;
12
13impl Vm {
14 pub fn get_global(&mut self, name: &'static str) -> Option<ReturnValue> {
15 self.arena.mutate_root(|_mc, state| {
16 let name = state.intern_static(name);
17 state.globals.get(&name).copied().map(ReturnValue::from)
18 })
19 }
20
21 pub fn register_extra_native_functions(&mut self) {
22 self.arena.mutate_root(|_mc, state| {
23 state.define_native_function("response", NativeFn(response::response));
24 state.define_native_function(
25 "temporary_redirect",
26 NativeFn(response::temporary_redirect),
27 );
28 state.define_native_function(
29 "permanent_redirect",
30 NativeFn(response::permanent_redirect),
31 );
32 });
33 }
34
35 pub fn inject_sso_instance<K>(&mut self, fields: HashMap<K, serde_json::Value>)
36 where
37 K: AsRef<str> + Eq,
38 {
39 self.arena.mutate_root(|mc, state| {
40 let ctx = state.get_context();
41 let name = state.intern_static("sso");
42 let class = crate::builtins::sso::create_sso_provider_class(ctx);
43 let mut instance = Instance::new(class);
44 for (key, value) in fields {
45 instance.fields.insert(
46 state.intern(key.as_ref().as_bytes()),
47 Value::from_serde_value(ctx, &value),
48 );
49 }
50 state
51 .globals
52 .insert(name, Gc::new(mc, RefLock::new(instance)).into());
53 });
54 }
55
56 pub fn inject_variables(&mut self, variables: HashMap<String, serde_json::Value>) {
57 self.arena.mutate_root(|_mc, state| {
58 let ctx = state.get_context();
59 for (key, value) in variables {
60 let name = state.intern(key.as_bytes());
61 state
62 .globals
63 .insert(name, Value::from_serde_value(ctx, &value));
64 }
65 });
66 }
67
68 pub fn inject_object<K>(&mut self, name: &'static str, fields: HashMap<K, serde_json::Value>)
69 where
70 K: AsRef<str> + Eq,
71 {
72 self.arena.mutate_root(|mc, state| {
73 let ctx = state.get_context();
74 let name = state.intern_static(name);
75 let mut obj = Object::default();
76 for (key, value) in fields {
77 obj.fields.insert(
78 state.intern(key.as_ref().as_bytes()),
79 Value::from_serde_value(ctx, &value),
80 );
81 }
82 state
83 .globals
84 .insert(name, Value::Object(Gc::new(mc, RefLock::new(obj))));
85 });
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::ReturnValue;
92
93 use super::*;
94
95 #[test]
96 fn test_inject_variables() {
97 let mut vm = Vm::default();
98 vm.inject_variables({
99 let mut map = HashMap::new();
100 map.insert("test".into(), "abc".into());
101 map.insert("test2".into(), 123.into());
102 map.insert("test3".into(), true.into());
103 map
104 });
105 vm.compile("return test;").unwrap();
106 let result = vm.interpret().unwrap();
107 assert_eq!(result, ReturnValue::String("abc".into()));
108 vm.compile("return test2;").unwrap();
109 let result = vm.interpret().unwrap();
110 assert_eq!(result, ReturnValue::Number(123.0));
111 vm.compile("return test3;").unwrap();
112 let result = vm.interpret().unwrap();
113 assert_eq!(result, ReturnValue::Boolean(true));
114 }
115
116 #[test]
117 fn test_inject_instance() {
118 let mut vm = Vm::default();
119 vm.inject_object("request", {
120 let mut map = HashMap::new();
121 map.insert("method", "get".into());
122 map.insert("code", 200.0.into());
123 map.insert("test", true.into());
124 map
125 });
126 vm.compile("return request;").unwrap();
127 let result = vm.interpret().unwrap();
128 let request = result.as_object().unwrap();
129 assert_eq!(request.get("method").unwrap(), "get");
130 assert_eq!(request.get("code").unwrap(), 200.0);
131 assert_eq!(request.get("test").unwrap(), true);
132 assert!(request.get("abc").is_none());
133 }
134}