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); 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), Err(e) => Output::Error(e.to_string()), } } } #[derive(Debug, Clone)] pub enum Output { None, Scalar(rhai::Dynamic), 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) -> rhai::Dynamic { if let Self::Scalar(v) = self { return v; } panic!("Not a scalar"); } } #[cfg(test)] pub mod tests { use super::*; pub fn process(script: &str) -> Output { let mut engine = Engine::default(); engine.process_script(script) } }