From b75f7ff26ef7085a4c3c0a99a111961b4157d8f2 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 19 Feb 2020 23:31:21 +0000 Subject: [PATCH 01/10] add "insert_fn2()" function which inserts 2-arg function that has Fn(String)->String as second arg - so you can render the inner content inside the function. --- src/builder.rs | 9 +++++++++ src/data.rs | 4 +++- src/template.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 83c5ca47..9e7f11d4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -149,6 +149,15 @@ impl MapBuilder { data.insert(key.to_string(), Data::Fun(RefCell::new(Box::new(f)))); MapBuilder { data: data } } + #[inline] + pub fn insert_fn2(self, key: K, f: F) -> MapBuilder + where + F: FnMut(String, &(FnMut(String) -> String)) -> String + Send + 'static, + { + let MapBuilder { mut data } = self; + data.insert(key.to_string(), Data::Fun2(RefCell::new(Box::new(f)))); + MapBuilder { data: data } + } /// Return the built `Data`. #[inline] diff --git a/src/data.rs b/src/data.rs index b71c79f4..f95874b4 100644 --- a/src/data.rs +++ b/src/data.rs @@ -9,6 +9,7 @@ pub enum Data { Vec(Vec), Map(HashMap), Fun(RefCell String + Send>>), + Fun2(RefCell String)) -> String + Send>>), } impl PartialEq for Data { @@ -35,6 +36,7 @@ impl fmt::Debug for Data { Data::Vec(ref v) => write!(f, "VecVal({:?})", v), Data::Map(ref v) => write!(f, "Map({:?})", v), Data::Fun(_) => write!(f, "Fun(...)"), + Data::Fun2(_) => write!(f, "Fun2(...)"), } } -} \ No newline at end of file +} diff --git a/src/template.rs b/src/template.rs index 1d6825ee..c1d9e112 100644 --- a/src/template.rs +++ b/src/template.rs @@ -291,6 +291,43 @@ impl<'a> RenderContext<'a> { let tokens = try!(self.render_fun(src, otag, ctag, f)); try!(self.render(wr, stack, &tokens)); } + Data::Fun2(ref fcell) => { + let f = &mut *fcell.borrow_mut(); + let ctx2 = self.template.ctx.clone(); + let partials2 = self.template.partials.clone(); + + let f0 = { + |src: String| { + let compiler = Compiler::new_with( + ctx2.clone(), + src.chars(), + partials2.clone(), + otag.to_string(), + ctag.to_string(), + ); + let mut vw: Vec = vec![]; + match compiler.compile() { + Ok((tokens, _)) => { + self.render(&mut vw, stack, &tokens).unwrap_or(()) + } + _ => (), + } + String::from_utf8_lossy(&vw).to_string() + } + }; + let src = f(src.to_string(), &f0); + + let compiler = Compiler::new_with( + self.template.ctx.clone(), + src.chars(), + self.template.partials.clone(), + otag.to_string(), + ctag.to_string(), + ); + + let (tokens, _) = try!(compiler.compile()); + try!(self.render(wr, stack, &tokens)); + } } } }; From d90a8b3fbff95cb0ea4d2be69865ea63dd6a5f6d Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 19 Feb 2020 23:47:11 +0000 Subject: [PATCH 02/10] make render function reference mutable --- src/builder.rs | 2 +- src/data.rs | 2 +- src/template.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 9e7f11d4..2ba84431 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -152,7 +152,7 @@ impl MapBuilder { #[inline] pub fn insert_fn2(self, key: K, f: F) -> MapBuilder where - F: FnMut(String, &(FnMut(String) -> String)) -> String + Send + 'static, + F: FnMut(String, &mut (FnMut(String) -> String)) -> String + Send + 'static, { let MapBuilder { mut data } = self; data.insert(key.to_string(), Data::Fun2(RefCell::new(Box::new(f)))); diff --git a/src/data.rs b/src/data.rs index f95874b4..ae518ce1 100644 --- a/src/data.rs +++ b/src/data.rs @@ -9,7 +9,7 @@ pub enum Data { Vec(Vec), Map(HashMap), Fun(RefCell String + Send>>), - Fun2(RefCell String)) -> String + Send>>), + Fun2(RefCell String)) -> String + Send>>), } impl PartialEq for Data { diff --git a/src/template.rs b/src/template.rs index c1d9e112..b48e1d8a 100644 --- a/src/template.rs +++ b/src/template.rs @@ -296,7 +296,7 @@ impl<'a> RenderContext<'a> { let ctx2 = self.template.ctx.clone(); let partials2 = self.template.partials.clone(); - let f0 = { + let mut f0 = { |src: String| { let compiler = Compiler::new_with( ctx2.clone(), @@ -315,7 +315,7 @@ impl<'a> RenderContext<'a> { String::from_utf8_lossy(&vw).to_string() } }; - let src = f(src.to_string(), &f0); + let src = f(src.to_string(), &mut f0); let compiler = Compiler::new_with( self.template.ctx.clone(), From 2fbfcdfd9d791082629533be33e065d6f1cd8ab2 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Thu, 20 Feb 2020 00:06:14 +0000 Subject: [PATCH 03/10] render either the within-fn2 rendered or after it - not both --- src/template.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/template.rs b/src/template.rs index b48e1d8a..c012421b 100644 --- a/src/template.rs +++ b/src/template.rs @@ -65,6 +65,7 @@ struct RenderContext<'a> { template: &'a Template, indent: String, line_start: bool, + inner_fn2_rendered: bool, } impl<'a> RenderContext<'a> { @@ -73,6 +74,7 @@ impl<'a> RenderContext<'a> { template: template, indent: "".to_string(), line_start: true, + inner_fn2_rendered: true, } } @@ -295,6 +297,7 @@ impl<'a> RenderContext<'a> { let f = &mut *fcell.borrow_mut(); let ctx2 = self.template.ctx.clone(); let partials2 = self.template.partials.clone(); + self.inner_fn2_rendered = false; let mut f0 = { |src: String| { @@ -308,6 +311,7 @@ impl<'a> RenderContext<'a> { let mut vw: Vec = vec![]; match compiler.compile() { Ok((tokens, _)) => { + self.inner_fn2_rendered = true; self.render(&mut vw, stack, &tokens).unwrap_or(()) } _ => (), @@ -316,17 +320,21 @@ impl<'a> RenderContext<'a> { } }; let src = f(src.to_string(), &mut f0); - - let compiler = Compiler::new_with( - self.template.ctx.clone(), - src.chars(), - self.template.partials.clone(), - otag.to_string(), - ctag.to_string(), - ); - - let (tokens, _) = try!(compiler.compile()); - try!(self.render(wr, stack, &tokens)); + if self.inner_fn2_rendered { + self.inner_fn2_rendered = false; + try!(self.render_text(wr, &src)); + } else { + let compiler = Compiler::new_with( + self.template.ctx.clone(), + src.chars(), + self.template.partials.clone(), + otag.to_string(), + ctag.to_string(), + ); + + let (tokens, _) = try!(compiler.compile()); + try!(self.render(wr, stack, &tokens)); + } } } } From f0349843ec90ea60416b8106f2bb12123fc80ad6 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Thu, 20 Feb 2020 00:17:42 +0000 Subject: [PATCH 04/10] allow to reset flag within fn2 render callback by rendering empty string --- src/template.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/template.rs b/src/template.rs index c012421b..e97b2061 100644 --- a/src/template.rs +++ b/src/template.rs @@ -311,7 +311,8 @@ impl<'a> RenderContext<'a> { let mut vw: Vec = vec![]; match compiler.compile() { Ok((tokens, _)) => { - self.inner_fn2_rendered = true; + /* a trick to reset the flag is to pass an empty string */ + self.inner_fn2_rendered = (src.len() > 0); self.render(&mut vw, stack, &tokens).unwrap_or(()) } _ => (), From b893cc783022a49607efb4c67ee8311f4f3c652d Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Thu, 5 Jun 2025 12:08:23 +0200 Subject: [PATCH 05/10] derive Debug for MapBuilder --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 2ba84431..82f21292 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -7,7 +7,7 @@ use encoder::Error; use super::{Data, to_data}; /// `MapBuilder` is a helper type that construct `Data` types. -#[derive(Default)] +#[derive(Default, Debug)] pub struct MapBuilder { data: HashMap, } From 606ca063fea14fefe3d2ebf556414e5b139898cc Mon Sep 17 00:00:00 2001 From: Erik Funder Carstensen Date: Tue, 27 Apr 2021 15:51:41 +0200 Subject: [PATCH 06/10] Fix broken link in readme The link to mustache documentation was previously broken, now it works. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c3cb778..89755a32 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ git push --tags origin master [1]: http://code.google.com/p/google-ctemplate/ [2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html [3]: https://mustache.github.io/ -[4]: http://mustache.github.com/mustache.5.html +[4]: https://mustache.github.io/mustache.5.html [5]: https://docs.rs/mustache # License From 9f1fa00762ea0abcca331eadad29ab03c055ff67 Mon Sep 17 00:00:00 2001 From: Ben Stern Date: Mon, 21 Jun 2021 22:15:01 -0400 Subject: [PATCH 07/10] Eliminate panics from live code (#73) * Eliminate panics from live code. As a library, panicking, even in the face of a bug, is a problem. Also, a lot of warnings (mostly `try!` vs `?` and `dyn`) were removed, as part of the edit/rebuild/test cycle. * Update rust dependencies to rust 1.46 If Slackware thinks Rust 1.46 is stable enough for everyday use (i.e., building Mozilla) then it should be stable enough for anyone who doesn't track "stable". * Prevent possible infinite recursion `cargo clippy` warned of infinite recursion, so let's heed the warning Co-authored-by: Ben Stern --- .travis.yml | 3 +- src/compiler.rs | 6 ++-- src/context.rs | 8 ++--- src/data.rs | 12 +++++-- src/encoder.rs | 30 +++++++--------- src/error.rs | 27 ++++++-------- src/macros.rs | 4 +-- src/parser.rs | 69 ++++++++++++++--------------------- src/template.rs | 92 +++++++++++++++++++++-------------------------- tests/template.rs | 11 +++--- 10 files changed, 112 insertions(+), 150 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55904342..02b75619 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,7 @@ cache: - target rust: -- 1.16.0 -- 1.17.0 +- 1.46.0 - stable - nightly - beta diff --git a/src/compiler.rs b/src/compiler.rs index dcd6eae2..b40e5581 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -51,7 +51,7 @@ impl> Compiler { pub fn compile(mut self) -> Result<(Vec, PartialsMap)> { let (tokens, partials) = { let parser = Parser::new(&mut self.reader, &self.otag, &self.ctag); - try!(parser.parse()) + parser.parse()? }; // Compile the partials if we haven't done so already. @@ -66,7 +66,7 @@ impl> Compiler { match File::open(&path) { Ok(mut file) => { let mut string = String::new(); - try!(file.read_to_string(&mut string)); + file.read_to_string(&mut string)?; let compiler = Compiler { ctx: self.ctx.clone(), @@ -76,7 +76,7 @@ impl> Compiler { ctag: "}}".to_string(), }; - let (tokens, subpartials) = try!(compiler.compile()); + let (tokens, subpartials) = compiler.compile()?; // Include subpartials self.partials.extend(subpartials.into_iter()); diff --git a/src/context.rs b/src/context.rs index e95aef69..16ef0dbc 100644 --- a/src/context.rs +++ b/src/context.rs @@ -37,7 +37,7 @@ impl Context { /// Compiles a template from a string pub fn compile>(&self, reader: IT) -> Result