diff --git a/src/builder.rs b/src/builder.rs index 83c5ca4..996fd24 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,6 +4,8 @@ use std::collections::HashMap; use serde::Serialize; use encoder::Error; +use crate::Template; + use super::{Data, to_data}; /// `MapBuilder` is a helper type that construct `Data` types. @@ -150,6 +152,21 @@ impl MapBuilder { MapBuilder { data: data } } + /// Adds a template to the `MapBuilder`. + /// + /// ```rust + /// use mustache::{MapBuilder, compile_str}; + /// let user_template = compile_str("{{username}}").unwrap(); + /// let data = MapBuilder::new() + /// .insert_template("user", user_template) + /// .build(); + /// ``` + #[inline] + pub fn insert_template(mut self, key: K, value: Template) -> MapBuilder { + self.data.insert(key.to_string(), Data::Template(value)); + self + } + /// Return the built `Data`. #[inline] pub fn build(self) -> Data { diff --git a/src/data.rs b/src/data.rs index dbb7b20..b452dea 100644 --- a/src/data.rs +++ b/src/data.rs @@ -5,12 +5,15 @@ use std::fmt; // for bug! use log::{log, error}; +use crate::Template; + pub enum Data { Null, String(String), Bool(bool), Vec(Vec), Map(HashMap), + Template(Template), Fun(RefCell String + Send>>), } @@ -40,6 +43,7 @@ impl fmt::Debug for Data { Data::Bool(v) => write!(f, "Bool({:?})", v), Data::Vec(ref v) => write!(f, "VecVal({:?})", v), Data::Map(ref v) => write!(f, "Map({:?})", v), + Data::Template(ref v) => write!(f, "Template({:?})", v), Data::Fun(_) => write!(f, "Fun(...)"), } } diff --git a/src/template.rs b/src/template.rs index 49be26a..2c7c1c2 100644 --- a/src/template.rs +++ b/src/template.rs @@ -274,6 +274,7 @@ impl<'a> RenderContext<'a> { self.render(wr, stack, children)?; stack.pop(); } + Data::Template(_) => {} Data::Fun(ref fcell) => { let f = &mut *fcell.borrow_mut(); let tokens = self.render_fun(src, otag, ctag, f)?; @@ -291,9 +292,16 @@ impl<'a> RenderContext<'a> { stack: &mut Vec<&Data>, name: &str, indent: &str) -> Result<()> { - match self.template.partials.get(name) { + match self + .find(&[name], stack) + .and_then(|d| match d { + Data::Template(t) => Some(&t.tokens), + _ => None, + }) + .or_else(|| self.template.partials.get(name)) + { None => (), - Some(ref tokens) => { + Some(tokens) => { let mut indent = self.indent.clone() + indent; mem::swap(&mut self.indent, &mut indent); @@ -323,7 +331,7 @@ impl<'a> RenderContext<'a> { Ok(tokens) } - fn find<'c>(&self, path: &[String], stack: &mut Vec<&'c Data>) -> Option<&'c Data> { + fn find<'c>(&self, path: &[impl AsRef], stack: &mut Vec<&'c Data>) -> Option<&'c Data> { // If we have an empty path, we just want the top value in our stack. if path.is_empty() { match stack.last() { @@ -342,7 +350,7 @@ impl<'a> RenderContext<'a> { for data in stack.iter().rev() { match **data { Data::Map(ref m) => { - if let Some(v) = m.get(&path[0]) { + if let Some(v) = m.get(path[0].as_ref()) { value = Some(v); break; } @@ -362,7 +370,7 @@ impl<'a> RenderContext<'a> { for part in path[1..].iter() { match *value { Data::Map(ref m) => { - match m.get(part) { + match m.get(part.as_ref()) { Some(v) => { value = v; } diff --git a/tests/template.rs b/tests/template.rs index f6053a9..4422bee 100644 --- a/tests/template.rs +++ b/tests/template.rs @@ -431,6 +431,15 @@ fn assert_partials_data(template: Template) { assert_eq!(render_data(&template, &Data::Map(ctx0)), "

Names

\n a\n\n".to_string()); + let mut ctx0 = HashMap::new(); + let mut ctx1 = HashMap::new(); + ctx1.insert("name".to_string(), Data::String("a".to_string())); + ctx0.insert("names".to_string(), Data::Vec(vec![Data::Map(ctx1)])); + let user_partial = compile_str("{{>username}}\n"); + ctx0.insert("user".to_string(), Data::Template(user_partial)); + assert_eq!(render_data(&template, &Data::Map(ctx0)), + "

Names

\n a\n\n".to_string()); + let mut ctx0 = HashMap::new(); let mut ctx1 = HashMap::new(); ctx1.insert("name".to_string(), Data::String("a".to_string()));