use super::handlebars_ext::HandlebarsExt;
use handlebars::{HelperDef, RenderError, Renderable};
use serde_json::Value;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
pub const GET_HELPER: &str = "get";
pub const SET_HELPER: &str = "set";
pub const CLEAR_HELPER: &str = "clear";
pub const IF_SET_HELPER: &str = "if_set";
pub const WITH_SET_HELPER: &str = "with_set";
pub struct GetHelper {
values: Arc<RwLock<HashMap<String, Value>>>,
}
impl GetHelper {
pub fn new(values: &Arc<RwLock<HashMap<String, Value>>>) -> Self {
Self { values: values.clone() }
}
}
impl HelperDef for GetHelper {
fn call_inner<'reg: 'rc, 'rc>(
&self,
h: &handlebars::Helper<'reg, 'rc>,
_: &'reg handlebars::Handlebars<'reg>,
_: &'rc handlebars::Context,
_: &mut handlebars::RenderContext<'reg, 'rc>,
) -> Result<handlebars::ScopedJson<'reg, 'rc>, RenderError> {
h.ensure_arguments_count(1, GET_HELPER)?;
let key = h.get_param_as_str_or_fail(0, GET_HELPER)?.to_string();
let value = get_value(&self.values, &key, GET_HELPER)?;
match value {
Some(v) => Ok(v.into()),
None => Err(RenderError::new(format!(
"Value is not set for key `{}` in `{}` helper.",
key, GET_HELPER
))),
}
}
}
pub struct SetHelper {
values: Arc<RwLock<HashMap<String, Value>>>,
}
impl SetHelper {
pub fn new(values: &Arc<RwLock<HashMap<String, Value>>>) -> Self {
Self { values: values.clone() }
}
}
impl HelperDef for SetHelper {
fn call<'reg: 'rc, 'rc>(
&self,
h: &handlebars::Helper<'reg, 'rc>,
_handle: &'reg handlebars::Handlebars<'reg>,
_ctx: &'rc handlebars::Context,
_render_ctx: &mut handlebars::RenderContext<'reg, 'rc>,
_out: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
h.ensure_arguments_count(2, SET_HELPER)?;
let key = h.get_param_as_str_or_fail(0, SET_HELPER)?.to_string();
let value = h.get_param_as_json_or_fail(1, SET_HELPER)?;
set_value(&self.values, key, value.clone(), SET_HELPER)?;
Ok(())
}
}
pub struct WithSetHelper {
values: Arc<RwLock<HashMap<String, Value>>>,
}
impl WithSetHelper {
pub fn new(values: &Arc<RwLock<HashMap<String, Value>>>) -> Self {
Self { values: values.clone() }
}
}
impl HelperDef for WithSetHelper {
fn call<'reg: 'rc, 'rc>(
&self,
h: &handlebars::Helper<'reg, 'rc>,
handle: &'reg handlebars::Handlebars<'reg>,
ctx: &'rc handlebars::Context,
render_ctx: &mut handlebars::RenderContext<'reg, 'rc>,
out: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
h.ensure_arguments_count(2, WITH_SET_HELPER)?;
let key = h.get_param_as_str_or_fail(0, WITH_SET_HELPER)?.to_string();
let value = h.get_param_as_json_or_fail(1, WITH_SET_HELPER)?;
set_value(&self.values, key.clone(), value.clone(), WITH_SET_HELPER)?;
if let Some(t) = h.template() {
t.render(handle, ctx, render_ctx, out)?;
}
rem_value(&self.values, &key, WITH_SET_HELPER)
}
}
pub struct IfGetHelper {
values: Arc<RwLock<HashMap<String, Value>>>,
}
impl IfGetHelper {
pub fn new(values: &Arc<RwLock<HashMap<String, Value>>>) -> Self {
Self { values: values.clone() }
}
}
impl HelperDef for IfGetHelper {
fn call<'reg: 'rc, 'rc>(
&self,
h: &handlebars::Helper<'reg, 'rc>,
handle: &'reg handlebars::Handlebars<'reg>,
ctx: &'rc handlebars::Context,
render_ctx: &mut handlebars::RenderContext<'reg, 'rc>,
out: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
h.ensure_arguments_count(1, IF_SET_HELPER)?;
let key = h.get_param_as_str_or_fail(0, IF_SET_HELPER)?.to_string();
let has_value = has_value(&self.values, &key, IF_SET_HELPER)?;
let temp = if has_value { h.template() } else { h.inverse() };
if let Some(t) = temp {
t.render(handle, ctx, render_ctx, out)?
};
Ok(())
}
}
pub struct ClearHelper {
values: Arc<RwLock<HashMap<String, Value>>>,
}
impl ClearHelper {
pub fn new(values: &Arc<RwLock<HashMap<String, Value>>>) -> Self {
Self { values: values.clone() }
}
}
impl HelperDef for ClearHelper {
fn call<'reg: 'rc, 'rc>(
&self,
h: &handlebars::Helper<'reg, 'rc>,
_: &'reg handlebars::Handlebars<'reg>,
_: &'rc handlebars::Context,
_: &mut handlebars::RenderContext<'reg, 'rc>,
_: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
h.ensure_arguments_count(1, GET_HELPER)?;
let key = h.get_param_as_str_or_fail(0, CLEAR_HELPER)?.to_string();
rem_value(&self.values, &key, CLEAR_HELPER)?;
Ok(())
}
}
fn get_value(values: &Arc<RwLock<HashMap<String, Value>>>, key: &str, helper_name: &str) -> Result<Option<Value>, RenderError> {
let lock = values
.read()
.map_err(|_e| RenderError::new(format!("Could not acquire lock in `{}` helper", helper_name)))?;
Ok(lock.get(key).map(Clone::clone))
}
fn has_value(values: &Arc<RwLock<HashMap<String, Value>>>, key: &str, helper_name: &str) -> Result<bool, RenderError> {
let lock = values
.read()
.map_err(|_e| RenderError::new(format!("Could not acquire lock in `{}` helper", helper_name)))?;
Ok(lock.get(key).is_some())
}
fn set_value(values: &Arc<RwLock<HashMap<String, Value>>>, key: String, value: Value, helper_name: &str) -> Result<(), RenderError> {
let mut lock = values
.write()
.map_err(|_| RenderError::new(format!("Could not acquire lock in `{}` helper", helper_name)))?;
lock.insert(key, value);
Ok(())
}
fn rem_value(values: &Arc<RwLock<HashMap<String, Value>>>, key: &str, helper_name: &str) -> Result<(), RenderError> {
let mut lock = values
.write()
.map_err(|_| RenderError::new(format!("Could not acquire lock in `{}` helper", helper_name)))?;
lock.remove(key);
Ok(())
}