1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
use std::collections::{BTreeMap, HashMap};
use crate::context::Context;
use crate::error::RenderError;
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<'reg, 'rc>],
hash: &BTreeMap<&'reg str, PathAndJson<'reg, 'rc>>,
engine: &Engine,
script: &AST,
) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::<Vec<&Json>>())?;
let hash: Dynamic = to_dynamic(
hash.iter()
.map(|(k, v)| ((*k).to_owned(), v.value()))
.collect::<HashMap<String, &Json>>(),
)?;
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(RenderError::from)?;
let result_json: Json = from_dynamic(&result)?;
Ok(ScopedJson::Derived(result_json))
}
impl HelperDef for ScriptHelper {
fn call_inner<'reg: 'rc, 'rc>(
&self,
h: &Helper<'reg, 'rc>,
reg: &'reg Registry<'reg>,
_ctx: &'rc Context,
_rc: &mut RenderContext<'reg, 'rc>,
) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
call_script_helper(h.params(), h.hash(), ®.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 hash = btreemap! {
"me" => PathAndJson::new(None, ScopedJson::Derived(json!("no"))),
"you" => PathAndJson::new(None, ScopedJson::Derived(json!("yes"))),
};
let result = call_script_helper(¶ms, &hash, &engine, &ast)
.unwrap()
.render();
assert_eq!("1,true,2,no", &result);
}
}
|