use std::collections::HashMap;
#[cfg(feature = "protobuf")]
use protobuf::MessageDyn;
use serde_json::Value;
use crate::{interp::Interpreter, types::CelByteCode, CelError, CelResult, CelValue};
use super::default_macros::{load_compile_macros, load_default_macros};
use super::{default_funcs::load_default_funcs, type_funcs::load_default_types};
pub type RsCelFunction = dyn Fn(CelValue, Vec<CelValue>) -> CelValue;
pub type RsCelMacro =
dyn for<'a, 'b> Fn(&'a Interpreter<'a>, CelValue, &[&CelByteCode]) -> CelValue;
#[derive(Clone)]
pub struct BindContext<'a> {
params: HashMap<String, CelValue>,
funcs: HashMap<String, &'a RsCelFunction>,
macros: HashMap<String, &'a RsCelMacro>,
types: HashMap<String, CelValue>,
}
impl<'a> BindContext<'a> {
pub fn new() -> BindContext<'a> {
let mut ctx = BindContext {
params: HashMap::new(),
funcs: HashMap::new(),
macros: HashMap::new(),
types: HashMap::new(),
};
load_default_macros(&mut ctx);
load_default_funcs(&mut ctx);
load_default_types(&mut ctx);
ctx
}
pub fn for_compile() -> BindContext<'a> {
let mut ctx = BindContext {
params: HashMap::new(),
funcs: HashMap::new(),
macros: HashMap::new(),
types: HashMap::new(),
};
load_compile_macros(&mut ctx);
load_default_funcs(&mut ctx);
load_default_types(&mut ctx);
ctx
}
pub fn bind_param(&mut self, name: &str, value: CelValue) {
self.params.insert(name.to_owned(), value);
}
pub fn bind_params_from_json_obj(&mut self, values: Value) -> CelResult<()> {
let obj = if let Value::Object(o) = values {
o
} else {
return Err(CelError::misc("Binding must be an object"));
};
for (key, value) in obj.into_iter() {
self.params.insert(key, CelValue::from(value));
}
Ok(())
}
#[cfg(feature = "protobuf")]
pub fn bind_param_proto_msg(&mut self, name: &str, msg: Box<dyn MessageDyn>) {
self.params
.insert(name.to_owned(), CelValue::from_proto_msg(msg));
}
pub fn bind_func(&mut self, name: &str, func: &'a RsCelFunction) {
self.funcs.insert(name.to_owned(), func);
}
pub fn bind_macro(&mut self, name: &str, macro_: &'a RsCelMacro) {
self.macros.insert(name.to_owned(), macro_);
}
pub fn get_param<'l>(&'l self, name: &str) -> Option<&'l CelValue> {
Some(self.params.get(name)?)
}
pub fn get_func(&self, name: &str) -> Option<&'a RsCelFunction> {
Some(*self.funcs.get(name)?)
}
pub fn get_macro(&self, name: &str) -> Option<&'a RsCelMacro> {
Some(*self.macros.get(name)?)
}
pub fn is_bound(&self, name: &str) -> bool {
self.params.contains_key(name)
|| self.funcs.contains_key(name)
|| self.macros.contains_key(name)
}
pub(crate) fn add_type(&mut self, name: &str, r#type: CelValue) {
self.types.insert(name.to_string(), r#type);
}
pub(crate) fn get_type(&self, name: &str) -> Option<&CelValue> {
self.types.get(name)
}
}
#[cfg(test)]
mod test {
use super::BindContext;
#[test]
fn basic() {
let mut b = BindContext::new();
b.bind_param("foo", 4.into());
assert!(b.is_bound("foo"))
}
}