blob: dc901cf98e91473b9109938ac5eddd84c32cca95 [file] [log] [blame]
use std::collections::{BTreeMap, HashMap};
use crate::context::Context;
use crate::error::{RenderError, RenderErrorReason};
use crate::helpers::HelperDef;
use crate::json::value::{PathAndJson, ScopedJson};
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};
use rhai::serde::{from_dynamic, to_dynamic};
use rhai::{Dynamic, Engine, Scope, AST};
use serde_json::value::Value as Json;
pub(crate) struct ScriptHelper {
pub(crate) script: AST,
}
#[inline]
fn call_script_helper<'reg: 'rc, 'rc>(
params: &[PathAndJson<'rc>],
hash: &BTreeMap<&'reg str, PathAndJson<'rc>>,
engine: &Engine,
script: &AST,
) -> Result<ScopedJson<'rc>, RenderError> {
let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::<Vec<&Json>>())
.map_err(RenderErrorReason::from)?;
let hash: Dynamic = to_dynamic(
hash.iter()
.map(|(k, v)| ((*k).to_owned(), v.value()))
.collect::<HashMap<String, &Json>>(),
)
.map_err(RenderErrorReason::from)?;
let mut scope = Scope::new();
scope.push_dynamic("params", params);
scope.push_dynamic("hash", hash);
let result = engine
.eval_ast_with_scope::<Dynamic>(&mut scope, script)
.map_err(RenderErrorReason::from)?;
let result_json: Json = from_dynamic(&result).map_err(RenderErrorReason::from)?;
Ok(ScopedJson::Derived(result_json))
}
impl HelperDef for ScriptHelper {
fn call_inner<'reg: 'rc, 'rc>(
&self,
h: &Helper<'rc>,
reg: &'reg Registry<'reg>,
_ctx: &'rc Context,
_rc: &mut RenderContext<'reg, 'rc>,
) -> Result<ScopedJson<'rc>, RenderError> {
call_script_helper(h.params(), h.hash(), &reg.engine, &self.script)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::json::value::{PathAndJson, ScopedJson};
use rhai::Engine;
#[test]
fn test_dynamic_convert() {
let j0 = json! {
[{"name": "tomcat"}, {"name": "jetty"}]
};
let d0 = to_dynamic(&j0).unwrap();
assert_eq!("array", d0.type_name());
let j1 = json!({
"name": "tomcat",
"value": 4000,
});
let d1 = to_dynamic(&j1).unwrap();
assert_eq!("map", d1.type_name());
}
#[test]
fn test_to_json() {
let d0 = Dynamic::from("tomcat".to_owned());
assert_eq!(
Json::String("tomcat".to_owned()),
from_dynamic::<Json>(&d0).unwrap()
);
}
#[test]
fn test_script_helper_value_access() {
let engine = Engine::new();
let script = "let plen = len(params); let p0 = params[0]; let hlen = len(hash); let hme = hash[\"me\"]; plen + \",\" + p0 + \",\" + hlen + \",\" + hme";
let ast = engine.compile(&script).unwrap();
let params = vec![PathAndJson::new(None, ScopedJson::Derived(json!(true)))];
let mut hash = BTreeMap::new();
hash.insert(
"me",
PathAndJson::new(None, ScopedJson::Derived(json!("no"))),
);
hash.insert(
"you",
PathAndJson::new(None, ScopedJson::Derived(json!("yes"))),
);
let result = call_script_helper(&params, &hash, &engine, &ast)
.unwrap()
.render();
assert_eq!("1,true,2,no", &result);
}
}