1mod moudle;
2#[cfg(test)]
3mod tests;
4mod value;
5
6use crate::{ActError, Result, ShareLock, Vars};
7use core::fmt;
8use rquickjs::{Context as JsContext, Ctx as JsCtx, FromJs, Runtime as JsRuntime};
9use serde::{de::DeserializeOwned, Deserialize, Serialize};
10use std::sync::{Arc, RwLock};
11
12use self::value::ActValue;
13
14pub trait ActModule: Send + Sync {
28 fn init(&self, ctx: &JsCtx<'_>) -> Result<()>;
29}
30
31pub struct Enviroment {
32 vars: ShareLock<Vars>,
33 modules: ShareLock<Vec<Box<dyn ActModule>>>,
34}
35
36impl fmt::Debug for Enviroment {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.debug_struct("Enviroment")
39 .field("vars", &self.vars.read().unwrap())
40 .finish()
41 }
42}
43
44unsafe impl Send for Enviroment {}
45unsafe impl Sync for Enviroment {}
46
47impl Default for Enviroment {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl Enviroment {
54 pub fn new() -> Self {
55 let mut env = Enviroment {
56 modules: Arc::new(RwLock::new(Vec::new())),
57 vars: Arc::new(RwLock::new(Vars::new())),
58 };
59 env.init();
60 env
61 }
62
63 #[cfg(test)]
64 pub fn modules_count(&self) -> usize {
65 self.modules.read().unwrap().len()
66 }
67
68 pub fn register_module<T: ActModule + Clone + 'static>(&self, module: &T) {
69 let mut modules = self.modules.write().unwrap();
70 modules.push(Box::new(module.clone()));
71 }
72
73 pub fn get<T>(&self, name: &str) -> Option<T>
74 where
75 T: for<'de> Deserialize<'de> + Clone,
76 {
77 self.vars.read().unwrap().get::<T>(name)
78 }
79
80 pub fn set<T>(&self, name: &str, value: T)
81 where
82 T: Serialize + Clone,
83 {
84 self.vars.write().unwrap().set(name, value);
85 }
86
87 pub fn update<F: FnOnce(&mut Vars)>(&self, f: F) {
88 let mut vars = self.vars.write().unwrap();
89 f(&mut vars);
90 }
91
92 pub fn eval<T>(&self, expr: &str) -> Result<T>
93 where
94 T: DeserializeOwned,
95 {
96 let runtime = JsRuntime::new().unwrap();
97 let ctx = JsContext::full(&runtime).unwrap();
98 ctx.with(|ctx| {
99 let modules = self.modules.read().unwrap();
100 for m in modules.iter() {
101 m.init(&ctx)?;
102 }
103
104 let result = ctx.eval::<ActValue, &str>(expr);
105 if let Err(rquickjs::Error::Exception) = result {
106 let exception = rquickjs::Exception::from_js(&ctx, ctx.catch()).unwrap();
107 eprintln!("error: {exception:?}");
108 return Err(ActError::Exception {
109 ecode: "".to_string(),
110 message: exception.message().unwrap_or_default(),
111 });
112 }
113
114 let value = result.map_err(ActError::from)?;
115 let ret = serde_json::from_value::<T>(value.into()).map_err(ActError::from)?;
116 Ok(ret)
117 })
118 }
119}