codegenr_lib/helpers/
distinct.rs

1use super::handlebars_ext::HandlebarsExt;
2use handlebars::{HelperDef, RenderError, Renderable};
3use std::{
4  collections::{HashMap, HashSet},
5  sync::RwLock,
6};
7
8pub const DISTINCTIVE: &str = "distinctive";
9
10/// Execute template if the first argument is equal to any other argument, otherwise execute the inverse
11/// (all arguments are converted to string and case insensitive compared)
12/// ```
13/// # use codegenr_lib::helpers::*;
14/// # use serde_json::json;
15/// assert_eq!(
16///   exec_template(json!({ "a": "42", "b": "42" }), r#"{{#each this}}{{@key}}/{{this}} {{/each}}"#),
17///   "a/42 b/42 "
18/// );
19/// assert_eq!(
20///   exec_template(json!({ "a": "42", "b": "42" }), r#"{{#each this}}{{#distinctive "values" this}}{{@key}}/{{this}} {{/distinctive}}{{/each}}"#),
21///   "a/42 "
22/// );
23/// ```
24#[derive(Default)]
25pub struct DistinctiveHelper {
26  values: RwLock<HashMap<String, HashSet<String>>>,
27}
28
29impl HelperDef for DistinctiveHelper {
30  fn call<'reg: 'rc, 'rc>(
31    &self,
32    h: &handlebars::Helper<'reg, 'rc>,
33    handle: &'reg handlebars::Handlebars<'reg>,
34    ctx: &'rc handlebars::Context,
35    render_ctx: &mut handlebars::RenderContext<'reg, 'rc>,
36    out: &mut dyn handlebars::Output,
37  ) -> handlebars::HelperResult {
38    h.ensure_arguments_count(2, DISTINCTIVE)?;
39    let key = h.get_param_as_str_or_fail(0, DISTINCTIVE)?;
40    let value = h.get_param_as_str_or_fail(1, DISTINCTIVE)?;
41
42    let mut lock = self
43      .values
44      .write()
45      .map_err(|_| RenderError::new(format!("Could not acquire lock in `{}` helper", DISTINCTIVE)))?;
46    let values_for_this_key = lock.entry(key.into()).or_default();
47
48    let inserted = values_for_this_key.insert(value.into());
49    let temp = if inserted { h.template() } else { h.inverse() };
50
51    match temp {
52      Some(t) => t.render(handle, ctx, render_ctx, out),
53      None => Ok(()),
54    }
55  }
56}