anvil_tera/
lib.rs

1use anvil::Anvil;
2use serde::Serialize;
3
4pub mod extensions;
5
6// General newtype wrapper for tera context to allow user-implementations of the trait.
7// pub struct Earth<'a, T: Serialize>(&'a T);
8pub trait Earth: Serialize {
9    fn tera(&self, writer: &mut (impl std::io::Write + ?Sized)) -> tera::Result<()>;
10}
11
12pub struct Firma<'a, T: Earth>(&'a T);
13
14impl<T: Earth> Anvil for Firma<'_, T> {
15    type Error = tera::Error;
16    fn anvil(&self, writer: &mut (impl std::io::Write + ?Sized)) -> Result<(), Self::Error> {
17        self.0.tera(writer)
18    }
19}
20
21pub mod prelude {
22    pub use crate::extensions::{
23        append::{append, TeraAppendExt},
24        generate::{generate, TeraGenerateExt},
25    };
26    pub use crate::Earth;
27}
28
29#[cfg(test)]
30mod test {
31    use std::sync::LazyLock;
32
33    use crate::Firma;
34
35    static TEMPLATES: LazyLock<Tera> = LazyLock::new(|| {
36        let mut tera = Tera::default();
37        tera.add_raw_template("test", "Hello, {{ name }}!\n")
38            .unwrap();
39        tera
40    });
41
42    use super::*;
43    use serde::Serialize;
44    use tera::Tera;
45
46    #[derive(Serialize)]
47    struct TestEarth {
48        name: String,
49    }
50
51    impl Earth for TestEarth {
52        fn tera(&self, writer: &mut (impl std::io::Write + ?Sized)) -> tera::Result<()> {
53            let context = ::tera::Context::from_serialize(self)?;
54            // Use the extracted tera instance expression
55            TEMPLATES.render_to("test", &context, writer)
56        }
57    }
58
59    #[test]
60    fn it_can_render_template() {
61        let earth = TestEarth {
62            name: "World".to_string(),
63        };
64
65        let mut buf = Vec::new();
66
67        let firma = Firma(&earth);
68
69        firma.anvil(&mut buf).unwrap();
70
71        let result = String::from_utf8(buf).unwrap();
72
73        assert_eq!(result, "Hello, World!\n");
74    }
75}