use crate::{Function, Functions, Context, Contexts, Compiled, Value};
use crate::tree::Tree;
use crate::error::Error;
use serde::Serialize;
use crate::to_value;
use std::fmt;
pub struct Expr {
expression: String,
compiled: Option<Compiled>,
functions: Functions,
contexts: Contexts,
}
impl Expr {
pub fn new<T: Into<String>>(expr: T) -> Self {
Self {
expression: expr.into(),
compiled: None,
functions: Functions::new(),
contexts: create_empty_contexts(),
}
}
pub fn function<T, F>(mut self, name: T, function: F) -> Self
where T: Into<String>,
F: 'static + Fn(Vec<Value>) -> Result<Value, Error> + Sync + Send
{
self.functions.insert(name.into(), Function::new(function));
self
}
pub fn value<T, V>(mut self, name: T, value: V) -> Self
where T: Into<String>,
V: Serialize
{
self.contexts.last_mut().unwrap().insert(name.into(), to_value(value));
self
}
pub fn compile(mut self) -> Result<Self, Error> {
self.compiled = Some(Tree::new(self.expression.clone()).compile()?);
Ok(self)
}
pub fn exec(&self) -> Result<Value, Error> {
if let Some(compiled) = self.compiled.as_ref() {
compiled(&self.contexts, &self.functions)
} else {
Tree::new(self.expression.clone()).compile()?(&self.contexts, &self.functions)
}
}
fn get_compiled(&self) -> Option<&Compiled> {
self.compiled.as_ref()
}
}
impl Clone for Expr {
fn clone(&self) -> Self {
Self {
expression: self.expression.clone(),
compiled: if self.compiled.is_some() {
Some(Tree::new(self.expression.clone()).compile().unwrap())
} else {
None
},
contexts: self.contexts.clone(),
functions: Functions::new(),
}
}
}
impl fmt::Debug for Expr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(formatter, "{:?}", self.expression)
}
}
pub struct ExecOptions<'a> {
expr: &'a Expr,
contexts: Option<&'a [Context]>,
functions: Option<&'a Functions>,
}
impl<'a> ExecOptions<'a> {
#[must_use] pub const fn new(expr: &'a Expr) -> Self {
ExecOptions {
expr,
contexts: None,
functions: None,
}
}
pub const fn contexts(&mut self, contexts: &'a [Context]) -> &mut ExecOptions<'a> {
self.contexts = Some(contexts);
self
}
pub const fn functions(&mut self, functions: &'a Functions) -> &mut ExecOptions<'a> {
self.functions = Some(functions);
self
}
pub fn exec(&self) -> Result<Value, Error> {
let empty_contexts = create_empty_contexts();
let empty_functions = Functions::new();
let contexts = self.contexts.unwrap_or(&empty_contexts);
let functions = self.functions.unwrap_or(&empty_functions);
if let Some(compiled) = self.expr.get_compiled() {
compiled(contexts, functions)
} else {
Tree::new(self.expr.expression.clone()).compile()?(contexts, functions)
}
}
}
fn create_empty_contexts() -> Contexts {
vec![Context::new()]
}