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;
10use std::sync::{Arc, RwLock};
11
12use self::value::ActValue;
13
14pub trait ActModule: Send + Sync {
15 fn init(&self, ctx: &JsCtx<'_>) -> Result<()>;
16}
17
18pub trait ActUserVar: Send + Sync {
37 fn name(&self) -> String;
41
42 fn default_data(&self) -> Option<Vars> {
45 None
46 }
47}
48
49#[derive(Clone)]
50pub struct Enviroment {
51 modules: ShareLock<Vec<Box<dyn ActModule>>>,
52 pub(crate) user_vars: ShareLock<Vec<Box<dyn ActUserVar>>>,
53}
54
55impl fmt::Debug for Enviroment {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.debug_struct("Enviroment").finish()
58 }
59}
60
61unsafe impl Send for Enviroment {}
62unsafe impl Sync for Enviroment {}
63
64impl Default for Enviroment {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl Enviroment {
71 pub fn new() -> Self {
72 let mut env = Enviroment {
73 modules: Arc::new(RwLock::new(Vec::new())),
74 user_vars: Arc::new(RwLock::new(Vec::new())),
75 };
76 env.init();
77 env
78 }
79
80 #[cfg(test)]
81 pub fn user_env_count(&self) -> usize {
82 self.user_vars.read().unwrap().len()
83 }
84
85 pub fn register_var<T: ActUserVar + Clone + 'static>(&self, module: &T) {
86 let mut user_envs = self.user_vars.write().unwrap();
87 user_envs.push(Box::new(module.clone()));
88 }
89
90 pub fn eval<T>(&self, expr: &str) -> Result<T>
91 where
92 T: DeserializeOwned,
93 {
94 let runtime = JsRuntime::new().unwrap();
95 let ctx = JsContext::full(&runtime).unwrap();
96 ctx.with(|ctx| {
97 let modules = self.modules.read().unwrap();
98 for m in modules.iter() {
99 m.init(&ctx)?;
100 }
101
102 let result = ctx.eval::<ActValue, &str>(expr);
103 if let Err(rquickjs::Error::Exception) = result {
104 let exception = rquickjs::Exception::from_js(&ctx, ctx.catch()).unwrap();
105 eprintln!("error: {exception:?}");
106 return Err(ActError::Exception {
107 ecode: "".to_string(),
108 message: exception.message().unwrap_or_default(),
109 });
110 }
111
112 let value = result.map_err(ActError::from)?;
113 let ret = serde_json::from_value::<T>(value.into()).map_err(ActError::from)?;
114 Ok(ret)
115 })
116 }
117}