use std::collections::HashMap;use std::sync::{Arc, Mutex};use rlua::prelude::*;use rlua_serde;use tera_v1::{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, TeraContext::new()) }, }.map_err(|err| { // https://github.com/Keats/tera/issues/381 //crate::error::create_lua_error(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(())}