use std::collections::HashMap;
use std::fmt;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use crate::context::EvaluationContext;
use crate::error::EvalError;
use crate::value::Value;
pub(crate) const MAX_MACRO_DEPTH: usize = 64;
pub(crate) const MAX_CALL_DEPTH: usize = 64;
pub type NativeFn =
Arc<dyn Fn(&[Value], &EvaluationContext) -> Result<Value, EvalError> + Send + Sync>;
#[derive(Debug, Clone)]
pub struct Macro {
pub params: Vec<String>,
pub body: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct Function {
pub params: Vec<String>,
pub body: serde_json::Value,
}
#[derive(Default)]
pub struct Options {
pub(crate) macros: HashMap<String, Macro>,
pub(crate) functions: HashMap<String, Function>,
pub(crate) natives: HashMap<String, (usize, NativeFn)>,
pub(crate) depth: AtomicUsize,
}
impl Options {
pub fn new() -> Options {
Options::default()
}
pub fn macro_def(
&mut self,
name: impl Into<String>,
params: Vec<String>,
body: serde_json::Value,
) -> &mut Options {
self.macros.insert(name.into(), Macro { params, body });
self
}
pub fn function(
&mut self,
name: impl Into<String>,
params: Vec<String>,
body: serde_json::Value,
) -> &mut Options {
self.functions
.insert(name.into(), Function { params, body });
self
}
pub fn native<F>(&mut self, name: impl Into<String>, arity: usize, f: F) -> &mut Options
where
F: Fn(&[Value], &EvaluationContext) -> Result<Value, EvalError> + Send + Sync + 'static,
{
self.natives.insert(name.into(), (arity, Arc::new(f)));
self
}
}
impl fmt::Debug for Options {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Options")
.field("macros", &self.macros)
.field("functions", &self.functions)
.field("natives", &self.natives.keys().collect::<Vec<_>>())
.finish()
}
}