From 8b98e660b1adf8e1b7d086a7823b11d58910b06e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 May 2024 15:46:11 +0200 Subject: [PATCH 1/2] Fix block partial rendering --- askama_derive/src/generator.rs | 5 +++++ testing/tests/block_fragments.rs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index decb01cb..32a81284 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -90,6 +90,7 @@ impl<'a> Generator<'a> { buf.write(CRATE); buf.writeln("::Result<()> {")?; + buf.discard = self.buf_writable.discard; // Make sure the compiler understands that the generated code depends on the template files. for path in self.contexts.keys() { // Skip the fake path of templates defined in rust source. @@ -113,6 +114,7 @@ impl<'a> Generator<'a> { } else { self.handle(ctx, ctx.nodes, buf, AstLevel::Top) }?; + buf.discard = false; self.flush_ws(Ws(None, None)); buf.write(CRATE); @@ -987,6 +989,9 @@ impl<'a> Generator<'a> { if block_fragment_write { self.buf_writable.discard = true; } + if buf.discard != prev_buf_discard { + self.write_buf_writable(buf)?; + } buf.discard = prev_buf_discard; Ok(size_hint) diff --git a/testing/tests/block_fragments.rs b/testing/tests/block_fragments.rs index ae723b6d..502367db 100644 --- a/testing/tests/block_fragments.rs +++ b/testing/tests/block_fragments.rs @@ -103,3 +103,21 @@ fn test_specific_block() { let t = RenderInPlace { s1 }; assert_eq!(t.render().unwrap(), "\nSection: [abc]\n"); } + +#[derive(Template)] +#[template( + source = r#"{% block empty %} +{% endblock %} + +{% if let Some(var) = var %} +{{ var }} +{% endif %}"#, + block = "empty", + ext = "txt" +)] +struct Empty {} + +#[test] +fn test_render_only_block() { + assert_eq!(Empty {}.render().unwrap(), "\n"); +} From a4ae8b87701a646bcde8fdaac7928c0657dea069 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 May 2024 15:49:03 +0200 Subject: [PATCH 2/2] Avoid unnecessary allocations when no rendering is done --- askama_derive/src/generator.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 32a81284..de94b798 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -365,7 +365,7 @@ impl<'a> Generator<'a> { } if let Some(target) = target { - let mut expr_buf = Buffer::new(0); + let mut expr_buf = Buffer::from_buf_parameters(buf, 0); buf.write("let "); // If this is a chain condition, then we need to declare the variable after the // left expression has been handled but before the right expression is handled @@ -596,8 +596,8 @@ impl<'a> Generator<'a> { buf.writeln("{")?; self.prepare_ws(def.ws1); - let mut names = Buffer::new(0); - let mut values = Buffer::new(0); + let mut names = Buffer::from_buf_parameters(buf, 0); + let mut values = Buffer::from_buf_parameters(buf, 0); let mut is_first_variable = true; if args.len() != def.args.len() { return Err(CompileError::from(format!( @@ -661,7 +661,7 @@ impl<'a> Generator<'a> { .insert(Cow::Borrowed(arg), LocalMeta::with_ref(var)); } Expr::Attr(obj, attr) => { - let mut attr_buf = Buffer::new(0); + let mut attr_buf = Buffer::from_buf_parameters(buf, 0); self.visit_attr(&mut attr_buf, obj, attr)?; let var = self.locals.resolve(&attr_buf.buf).unwrap_or(attr_buf.buf); @@ -750,7 +750,7 @@ impl<'a> Generator<'a> { self.buf_writable.buf = current_buf; - let mut filter_buf = Buffer::new(buf.indent); + let mut filter_buf = Buffer::from_buf_parameters(buf, buf.indent); let Filter { name: filter_name, arguments, @@ -876,7 +876,7 @@ impl<'a> Generator<'a> { return buf.writeln(";"); }; - let mut expr_buf = Buffer::new(0); + let mut expr_buf = Buffer::from_buf_parameters(buf, 0); self.visit_expr(&mut expr_buf, val)?; let shadowed = self.is_shadowing_variable(&l.var)?; @@ -1847,6 +1847,15 @@ impl Buffer { } } + fn from_buf_parameters(other: &Buffer, indent: u8) -> Self { + Self { + buf: String::new(), + indent, + start: true, + discard: other.discard, + } + } + fn writeln(&mut self, s: &str) -> Result<(), CompileError> { if self.discard { return Ok(());