use serde_json::value::Value as Json; use crate::context::Context; use crate::error::RenderError; use crate::helpers::HelperDef; use crate::json::value::ScopedJson; use crate::registry::Registry; use crate::render::{Helper, RenderContext}; #[derive(Clone, Copy)] pub struct LookupHelper; impl HelperDef for LookupHelper { fn call_inner<'reg: 'rc, 'rc>( &self, h: &Helper<'reg, 'rc>, _: &'reg Registry<'reg>, _: &'rc Context, _: &mut RenderContext<'reg, 'rc>, ) -> Result>, RenderError> { let collection_value = h .param(0) .ok_or_else(|| RenderError::new("Param not found for helper \"lookup\""))?; let index = h .param(1) .ok_or_else(|| RenderError::new("Insufficient params for helper \"lookup\""))?; let value = match *collection_value.value() { Json::Array(ref v) => index .value() .as_u64() .and_then(|u| v.get(u as usize)) .map(|i| ScopedJson::Derived(i.clone())), Json::Object(ref m) => index .value() .as_str() .and_then(|k| m.get(k)) .map(|i| ScopedJson::Derived(i.clone())), _ => None, }; Ok(value) } } pub static LOOKUP_HELPER: LookupHelper = LookupHelper; #[cfg(test)] mod test { use crate::registry::Registry; use std::collections::BTreeMap; #[test] fn test_lookup() { let mut handlebars = Registry::new(); assert!(handlebars .register_template_string("t0", "{{#each v1}}{{lookup ../v2 @index}}{{/each}}") .is_ok()); assert!(handlebars .register_template_string("t1", "{{#each v1}}{{lookup ../v2 1}}{{/each}}") .is_ok()); assert!(handlebars .register_template_string("t2", "{{lookup kk \"a\"}}") .is_ok()); let mut m: BTreeMap> = BTreeMap::new(); m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]); m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]); let m2 = btreemap! { "kk".to_string() => btreemap!{"a".to_string() => "world".to_string()} }; let r0 = handlebars.render("t0", &m); assert_eq!(r0.ok().unwrap(), "987".to_string()); let r1 = handlebars.render("t1", &m); assert_eq!(r1.ok().unwrap(), "888".to_string()); let r2 = handlebars.render("t2", &m2); assert_eq!(r2.ok().unwrap(), "world".to_string()); } }