2022-10-18 01:15:36 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-10-08 20:48:17 +00:00
|
|
|
use crate::dataframe;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2022-10-16 18:14:55 +00:00
|
|
|
pub struct Engine<'a> {
|
2022-10-08 20:48:17 +00:00
|
|
|
engine: rhai::Engine,
|
2022-10-16 18:14:55 +00:00
|
|
|
scope: rhai::Scope<'a>,
|
2022-10-08 20:48:17 +00:00
|
|
|
}
|
|
|
|
|
2022-10-16 18:14:55 +00:00
|
|
|
impl<'a> Default for Engine<'a> {
|
2022-10-08 20:48:17 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
let mut engine = rhai::Engine::new();
|
|
|
|
engine.set_fast_operators(false);
|
|
|
|
dataframe::setup_engine(&mut engine);
|
|
|
|
|
|
|
|
Self {
|
|
|
|
engine,
|
2022-10-16 18:14:55 +00:00
|
|
|
scope: rhai::Scope::new(),
|
2022-10-08 20:48:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-16 18:14:55 +00:00
|
|
|
impl<'a> Engine<'a> {
|
|
|
|
pub fn process_script(&mut self, script: &str) -> Output {
|
|
|
|
match self
|
|
|
|
.engine
|
|
|
|
.eval_with_scope::<rhai::Dynamic>(&mut self.scope, script)
|
|
|
|
{
|
|
|
|
Ok(res) if res.is::<dataframe::DataFrame>() => {
|
|
|
|
let frame = rhai::Dynamic::cast::<dataframe::DataFrame>(res);
|
|
|
|
Output::DataFrame(frame)
|
2022-10-08 20:48:17 +00:00
|
|
|
}
|
2022-10-16 18:14:55 +00:00
|
|
|
Ok(res) if res.is::<()>() => Output::None,
|
|
|
|
Ok(res) if res.is::<dataframe::Series>() => {
|
|
|
|
let series = rhai::Dynamic::cast::<dataframe::Series>(res);
|
|
|
|
Output::Series(series)
|
|
|
|
}
|
2022-10-18 01:15:36 +00:00
|
|
|
Ok(res) => Output::Scalar(res.to_string()),
|
2022-10-16 18:14:55 +00:00
|
|
|
Err(e) => Output::Error(e.to_string()),
|
2022-10-08 20:48:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum Output {
|
|
|
|
None,
|
2022-10-18 01:15:36 +00:00
|
|
|
Scalar(String),
|
2022-10-08 20:48:17 +00:00
|
|
|
DataFrame(dataframe::DataFrame),
|
|
|
|
Series(dataframe::Series),
|
|
|
|
Error(String),
|
|
|
|
}
|
|
|
|
|
2022-10-16 18:14:55 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-08 20:48:17 +00:00
|
|
|
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");
|
|
|
|
}
|
2022-10-18 01:15:36 +00:00
|
|
|
pub fn into_scalar(self) -> String {
|
2022-10-08 20:48:17 +00:00
|
|
|
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();
|
2022-10-16 18:14:55 +00:00
|
|
|
engine.process_script(script)
|
2022-10-08 20:48:17 +00:00
|
|
|
}
|
|
|
|
}
|