kumo_template/
lib.rs

1use minijinja::Environment;
2pub use minijinja::{context, Error, Template, Value};
3use minijinja_contrib::add_to_environment;
4use self_cell::self_cell;
5
6/// Holds a set of templates
7pub struct TemplateEngine {
8    env: Environment<'static>,
9}
10
11impl Default for TemplateEngine {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl TemplateEngine {
18    pub fn new() -> Self {
19        let mut env = Environment::new();
20        env.set_unknown_method_callback(minijinja_contrib::pycompat::unknown_method_callback);
21        add_to_environment(&mut env);
22        Self { env }
23    }
24
25    /// Add a named template with the specified source.
26    /// If name ends with `.html` then automatical escaping of html entities
27    /// will be performed on substitutions.
28    pub fn add_template<N, S>(&mut self, name: N, source: S) -> Result<(), Error>
29    where
30        N: Into<String>,
31        S: Into<String>,
32    {
33        self.env.add_template_owned(name.into(), source.into())
34    }
35
36    /// Get a reference to a named template
37    pub fn get_template(&self, name: &str) -> Result<Template<'_, '_>, Error> {
38        self.env.get_template(name)
39    }
40
41    /// Define a global value that can be reference by all templates
42    pub fn add_global<N, V>(&mut self, name: N, value: V)
43    where
44        N: Into<String>,
45        V: Into<Value>,
46    {
47        self.env.add_global(name.into(), value)
48    }
49
50    pub fn render<CTX>(&self, name: &str, source: &str, context: CTX) -> Result<String, Error>
51    where
52        CTX: serde::Serialize,
53    {
54        self.env.render_named_str(name, source, context)
55    }
56}
57
58pub type TemplateList<'a> = Vec<Template<'a, 'a>>;
59
60self_cell!(
61    /// CompiledTemplates is useful when you have a set of templates
62    /// that you will expand frequently in a tight loop.
63    /// Because the underlying crate returns only references to `Template`s,
64    /// it is a covariant, self-referential structure that needs to be
65    /// constructed like this:
66    ///
67    /// ```rust
68    /// fn get_templates<'b>(
69    ///   engine: &'b TemplateEngine
70    /// ) -> anyhow::Result<TemplateList<'b>> {
71    ///   let mut templates = vec![];
72    ///   templates.push(engine.get_template("something")?);
73    ///   Ok(templates)
74    /// }
75    ///
76    /// let engine = TemplateEngine::new();
77    /// engine.add_template("something", "some text")?;
78    /// let compiled = CompiledTemplates::try_new(engine, |engine| {
79    ///   get_templates(engine)
80    /// });
81    /// ```
82    pub struct CompiledTemplates {
83        owner: TemplateEngine,
84        #[covariant]
85        dependent: TemplateList,
86    }
87);