aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--askama_shared/src/lib.rs88
1 files changed, 88 insertions, 0 deletions
diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs
index 81500e1..b656c53 100644
--- a/askama_shared/src/lib.rs
+++ b/askama_shared/src/lib.rs
@@ -26,6 +26,72 @@ mod heritage;
mod input;
mod parser;
+/// Main `Template` trait; implementations are generally derived
+///
+/// If you need an object-safe template, use [`DynTemplate`].
+pub trait Template {
+ /// Helper method which allocates a new `String` and renders into it
+ fn render(&self) -> Result<String> {
+ let mut buf = String::with_capacity(Self::SIZE_HINT);
+ self.render_into(&mut buf)?;
+ Ok(buf)
+ }
+
+ /// Renders the template to the given `writer` buffer
+ fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;
+
+ /// The template's extension, if provided
+ const EXTENSION: Option<&'static str>;
+
+ /// Provides a conservative estimate of the expanded length of the rendered template
+ const SIZE_HINT: usize;
+
+ /// The MIME type (Content-Type) of the data that gets rendered by this Template
+ const MIME_TYPE: &'static str;
+}
+
+/// Object-safe wrapper trait around [`Template`] implementers
+///
+/// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
+pub trait DynTemplate {
+ /// Helper method which allocates a new `String` and renders into it
+ fn dyn_render(&self) -> Result<String>;
+
+ /// Renders the template to the given `writer` buffer
+ fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;
+
+ /// Helper function to inspect the template's extension
+ fn extension(&self) -> Option<&'static str>;
+
+ /// Provides a conservative estimate of the expanded length of the rendered template
+ fn size_hint(&self) -> usize;
+
+ /// The MIME type (Content-Type) of the data that gets rendered by this Template
+ fn mime_type(&self) -> &'static str;
+}
+
+impl<T: Template> DynTemplate for T {
+ fn dyn_render(&self) -> Result<String> {
+ <Self as Template>::render(self)
+ }
+
+ fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
+ <Self as Template>::render_into(self, writer)
+ }
+
+ fn extension(&self) -> Option<&'static str> {
+ Self::EXTENSION
+ }
+
+ fn size_hint(&self) -> usize {
+ Self::SIZE_HINT
+ }
+
+ fn mime_type(&self) -> &'static str {
+ Self::MIME_TYPE
+ }
+}
+
#[derive(Debug)]
struct Config<'a> {
dirs: Vec<PathBuf>,
@@ -521,4 +587,26 @@ mod tests {
]
);
}
+
+ #[test]
+ fn dyn_template() {
+ struct Test;
+ impl Template for Test {
+ fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()> {
+ Ok(writer.write_str("test")?)
+ }
+
+ const EXTENSION: Option<&'static str> = Some("txt");
+
+ const SIZE_HINT: usize = 4;
+
+ const MIME_TYPE: &'static str = "text/plain; charset=utf-8";
+ }
+
+ fn render(t: &dyn DynTemplate) -> String {
+ t.dyn_render().unwrap()
+ }
+
+ assert_eq!(render(&Test), "test");
+ }
}