From b75f7ff26ef7085a4c3c0a99a111961b4157d8f2 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Wed, 19 Feb 2020 23:31:21 +0000 Subject: [PATCH 1/4] 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 83c5ca4..9e7f11d 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 b71c79f..f95874b 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 1d6825e..c1d9e11 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 2/4] 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 9e7f11d..2ba8443 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 f95874b..ae518ce 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 c1d9e11..b48e1d8 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 3/4] 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 b48e1d8..c012421 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 4/4] 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 c012421..e97b206 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(()) } _ => (),