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
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use rlua::prelude::*;
use rlua_serde;
use tera::{Tera, Value as JsonValue, Context as TeraContext};
use crate::error::Error;
struct LuaTera (Arc<Mutex<Tera>>);
fn get_tera_context_from_table(table: &HashMap<String, LuaValue>) -> Result<TeraContext, LuaError> {
let mut context = TeraContext::new();
for (key, value) in table.iter() {
match value {
LuaValue::Integer(num) => context.insert(key, num),
LuaValue::Number(num) => context.insert(key, num),
LuaValue::String(string) => context.insert(key, string.to_str()?),
LuaValue::Boolean(boolean) => context.insert(key, boolean),
value @ LuaValue::Table(_) => {
let value: JsonValue = rlua_serde::from_value(value.clone())
.map_err(|err| LuaError::external(err))?;
context.insert(key, &value);
},
LuaValue::Nil => context.insert(key, &()),
value @ _ => unimplemented!("Value {:?} is not implemented as a template parameter", value),
}
}
Ok(context)
}
impl LuaUserData for LuaTera {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("extend", |_, this, dir: String| {
let mut tera = this.0.try_lock().unwrap();
let new_tera = Tera::parse(&dir).map_err(|err| {
LuaError::external(format_err!("{}", err.to_string()))
})?;
tera.extend(&new_tera).map_err(|err| {
LuaError::external(format_err!("{}", err.to_string()))
})
});
methods.add_method("reload", |_, this, _: ()| {
let mut tera = this.0.try_lock().unwrap();
tera.full_reload().map_err(|err| {
LuaError::external(format_err!("{}", err.to_string()))
})
});
methods.add_method("add_raw_templates", |_, this, hashmap: HashMap<String, String>| {
let mut templates = Vec::new();
for (key, val) in &hashmap {
templates.push( (key.as_str(), val.as_str()) );
}
let mut tera = this.0.try_lock().unwrap();
tera.add_raw_templates(templates).map_err(|err| {
LuaError::external(format_err!("{}", err.to_string()))
})
});
methods.add_method("render", |_, this, (path, params): (String, Option<HashMap<String, LuaValue>>)| {
let tera = this.0.try_lock().unwrap();
let text = match params {
Some(params) => {
let context = get_tera_context_from_table(¶ms)?;
tera.render(&path, &context)
},
None => {
tera.render(&path, &())
},
}.map_err(|err| {
LuaError::external(format_err!("{}", err.to_string()))
})?;
Ok(text)
});
}
}
pub fn init(lua: &Lua) -> crate::Result<()> {
let new_tera = lua.create_function(move |_, dir: String| {
let tera = Tera::new(&dir).unwrap();
let arc_mutex = Arc::new(Mutex::new(tera));
Ok(LuaTera(arc_mutex))
})?;
let module = lua.create_table()?;
module.set("new", new_tera)?;
lua.globals().set("tera", module).map_err(Error::from)?;
Ok(())
}