use crate::dataframe; #[derive(Debug)] pub struct Engine<'a> { engine: rhai::Engine, scope: rhai::Scope<'a>, } impl<'a> Default for Engine<'a> { fn default() -> Self { let mut engine = rhai::Engine::new(); engine.set_fast_operators(false); engine.register_static_module("physics", rhai::exported_module!(physics).into()); engine.register_static_module("math", rhai::exported_module!(math).into()); dataframe::setup_engine(&mut engine); Self { engine, scope: rhai::Scope::new(), } } } impl<'a> Engine<'a> { pub fn process_script(&mut self, script: &str) -> Output { match self .engine .eval_with_scope::(&mut self.scope, script) { Ok(res) if res.is::() => { let frame = rhai::Dynamic::cast::(res); Output::DataFrame(frame) } Ok(res) if res.is::<()>() => Output::None, Ok(res) if res.is::() => { let series = rhai::Dynamic::cast::(res); Output::Series(series) } Ok(res) => Output::Scalar(res.to_string()), Err(e) => Output::Error(e.to_string()), } } } #[derive(Debug, Clone)] pub enum Output { None, Scalar(String), DataFrame(dataframe::DataFrame), Series(dataframe::Series), Error(String), } impl Default for Output { fn default() -> Self { Output::None } } impl PartialEq for Output { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Scalar(l0), Self::Scalar(r0)) => *l0.to_string() == *r0.to_string(), (Self::DataFrame(l0), Self::DataFrame(r0)) => l0 == r0, (Self::Series(l0), Self::Series(r0)) => l0 == r0, (Self::Error(l0), Self::Error(r0)) => l0 == r0, _ => core::mem::discriminant(self) == core::mem::discriminant(other), } } } impl Output { pub fn into_frame(self) -> dataframe::DataFrame { if let Self::DataFrame(v) = self { return v; } panic!("Not a dataframe"); } pub fn into_series(self) -> dataframe::Series { if let Self::Series(v) = self { return v; } panic!("Not a series"); } pub fn into_scalar(self) -> String { if let Self::Scalar(v) = self { return v; } panic!("Not a scalar"); } } use rhai::plugin::*; #[rhai::export_module] mod physics { pub const PLANK: f64 = 6.626e-34; pub const G: f64 = 6.67430e-11; pub const COULUMN: f64 = 8.987; pub const STEFAN_BOLTZMANN: f64 = 5.670e-8; pub const BOLTZMANN: f64 = 1.380650e23; pub const C: f64 = 299792458.0; pub const AVOGADRO: f64 = 6.02214076e23; pub const ATOMIC_MASS: f64 = 1.66053906660e-27; pub const ELECTRON_MASS: f64 = 9.1093837015e-31; pub const PROTON_MASS: f64 = 1.67262192369e-27; pub const NEUTRON_MASS: f64 = 1.67492749804e-27; pub const HUBBLE: f64 = 69.3; } #[rhai::export_module] mod math { pub const PI: f64 = std::f64::consts::PI; pub const E: f64 = std::f64::consts::E; pub const SQRT2: f64 = std::f64::consts::SQRT_2; pub const TAU: f64 = std::f64::consts::TAU; } #[cfg(test)] pub mod tests { use super::*; pub fn process(script: &str) -> Output { let mut engine = super::Engine::default(); engine.process_script(script) } }