From 59013a3e62818b6c07f459cf343edb6d6e602982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Mon, 28 Mar 2022 16:10:45 +0200 Subject: [PATCH 1/2] Expose the fact that templates implement Display This is a quite useful feature, because you can use templates in format!(), format_args!(), etc. --- askama_shared/src/lib.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index b656c5338..ecf3d076a 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -29,7 +29,7 @@ mod parser; /// Main `Template` trait; implementations are generally derived /// /// If you need an object-safe template, use [`DynTemplate`]. -pub trait Template { +pub trait Template: fmt::Display { /// Helper method which allocates a new `String` and renders into it fn render(&self) -> Result { let mut buf = String::with_capacity(Self::SIZE_HINT); @@ -92,6 +92,12 @@ impl DynTemplate for T { } } +impl fmt::Display for dyn DynTemplate { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.dyn_render_into(f).map_err(|_| ::std::fmt::Error {}) + } +} + #[derive(Debug)] struct Config<'a> { dirs: Vec, @@ -603,10 +609,23 @@ mod tests { const MIME_TYPE: &'static str = "text/plain; charset=utf-8"; } + impl fmt::Display for Test { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.render_into(f).map_err(|_| fmt::Error {}) + } + } + fn render(t: &dyn DynTemplate) -> String { t.dyn_render().unwrap() } - assert_eq!(render(&Test), "test"); + let test = &Test as &dyn DynTemplate; + + assert_eq!(render(test), "test"); + + assert_eq!(test.to_string(), "test"); + + assert_eq!(format!("{}", test), "test"); } } From 02e9eaed5e9d6dc732d67a0a843c851677528d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Mon, 28 Mar 2022 16:19:59 +0200 Subject: [PATCH 2/2] Add io::writer helper methods It might not be immediately obvious to everyone how easy it is to use Askama template with std::io (e.g. files) instead of std::fmt, so this PR adds a few helper methods to make this more obvious to novice users. --- askama_shared/src/lib.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index ecf3d076a..5913eb31c 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -37,9 +37,15 @@ pub trait Template: fmt::Display { Ok(buf) } - /// Renders the template to the given `writer` buffer + /// Renders the template to the given `writer` fmt buffer fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>; + /// Renders the template to the given `writer` io buffer + #[inline] + fn write_into(&self, writer: &mut (impl std::io::Write + ?Sized)) -> std::io::Result<()> { + writer.write_fmt(format_args!("{}", self)) + } + /// The template's extension, if provided const EXTENSION: Option<&'static str>; @@ -57,9 +63,12 @@ pub trait DynTemplate { /// Helper method which allocates a new `String` and renders into it fn dyn_render(&self) -> Result; - /// Renders the template to the given `writer` buffer + /// Renders the template to the given `writer` fmt buffer fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>; + /// Renders the template to the given `writer` io buffer + fn dyn_write_into(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()>; + /// Helper function to inspect the template's extension fn extension(&self) -> Option<&'static str>; @@ -79,6 +88,11 @@ impl DynTemplate for T { ::render_into(self, writer) } + #[inline] + fn dyn_write_into(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> { + writer.write_fmt(format_args!("{}", self)) + } + fn extension(&self) -> Option<&'static str> { Self::EXTENSION } @@ -627,5 +641,9 @@ mod tests { assert_eq!(test.to_string(), "test"); assert_eq!(format!("{}", test), "test"); + + let mut vec = Vec::new(); + test.dyn_write_into(&mut vec).unwrap(); + assert_eq!(vec, vec![b't', b'e', b's', b't']); } }