Skip to main content

tera_hot/
lib.rs

1use std::sync::{Arc, RwLock};
2
3#[derive(Clone)]
4pub struct Template {
5    template_dir: String,
6    tera: Arc<RwLock<tera::Tera>>,
7}
8
9impl Template {
10    #[must_use]
11    pub fn new(template_dir: &str) -> Self {
12        let mut tera = tera::Tera::default();
13
14        let path = format!("{template_dir}/**/*");
15        if let Err(err) = tera.load_from_glob(&path) {
16            panic!("Parsing error(s): {err}");
17        }
18
19        Self {
20            tera: Arc::new(RwLock::new(tera)),
21            template_dir: template_dir.to_string(),
22        }
23    }
24
25    pub fn render(&self, template: &str, context: &tera::Context) -> tera::TeraResult<String> {
26        let tera = self.tera.read().unwrap();
27
28        tera.render(template, context)
29    }
30
31    #[cfg(debug_assertions)]
32    pub fn watch(self) {
33        use notify::Watcher;
34
35        let mut watcher = notify::recommended_watcher(move |res| match res {
36            Ok(event) => {
37                log::info!("reloading templates: {event:?}");
38
39                let mut tera = self.tera.write().unwrap();
40
41                match tera.full_reload() {
42                    Ok(_) => log::info!("templates reloaded"),
43                    Err(e) => log::error!("failed to reload templates: {e}"),
44                }
45            }
46            Err(e) => log::warn!("watch error: {e:?}"),
47        })
48        .unwrap();
49
50        log::debug!("watching {} for changes", self.template_dir);
51
52        watcher
53            .watch(
54                &std::path::PathBuf::from(&self.template_dir),
55                notify::RecursiveMode::Recursive,
56            )
57            .unwrap();
58    }
59
60    pub fn register_function<Func, Res>(
61        &mut self,
62        name: impl Into<std::borrow::Cow<'static, str>>,
63        function: Func,
64    ) where
65        Func: Fn(tera::Kwargs, &tera::State<'_>) -> Res + Sync + Send + 'static,
66        Res: tera::FunctionResult,
67    {
68        let mut tera = self.tera.write().unwrap();
69
70        tera.register_function(name, function);
71    }
72
73    pub fn register_filter<Func, Arg, Res>(
74        &mut self,
75        name: impl Into<std::borrow::Cow<'static, str>>,
76        filter: Func,
77    ) where
78        Func: tera::Filter<Arg, Res>
79            + for<'a> tera::Filter<<Arg as tera::ArgFromValue<'a>>::Output, Res>,
80        Arg: for<'a> tera::ArgFromValue<'a>,
81        Res: tera::FunctionResult,
82    {
83        let mut tera = self.tera.write().unwrap();
84
85        tera.register_filter(name, filter);
86    }
87
88    pub fn register_test<Func, Arg, Res>(
89        &mut self,
90        name: impl Into<std::borrow::Cow<'static, str>>,
91        test: Func,
92    ) where
93        Func:
94            tera::Test<Arg, Res> + for<'a> tera::Test<<Arg as tera::ArgFromValue<'a>>::Output, Res>,
95        Arg: for<'a> tera::ArgFromValue<'a>,
96        Res: tera::TestResult,
97    {
98        let mut tera = self.tera.write().unwrap();
99
100        tera.register_test(name, test);
101    }
102
103    #[cfg(not(debug_assertions))]
104    pub fn watch(self) {}
105}