rocket_include_tera/debug/
reloadable.rs

1use std::{
2    collections::HashMap,
3    ops::{Deref, DerefMut},
4    path::PathBuf,
5    time::SystemTime,
6};
7
8use tera::{Error as TeraError, Tera};
9
10#[derive(Debug)]
11/// Reloadable Tera.
12pub struct ReloadableTera {
13    tera:  Tera,
14    files: HashMap<&'static str, (PathBuf, Option<SystemTime>)>,
15}
16
17impl ReloadableTera {
18    /// Create an instance of `ReloadableTera`.
19    #[inline]
20    pub fn new() -> ReloadableTera {
21        let tera = Tera::default();
22
23        ReloadableTera {
24            tera,
25            files: HashMap::new(),
26        }
27    }
28
29    /// Register a template from a path and it can be reloaded automatically.
30    #[inline]
31    pub fn register_template_file<P: Into<PathBuf>>(
32        &mut self,
33        name: &'static str,
34        file_path: P,
35    ) -> Result<(), TeraError> {
36        let file_path = file_path.into();
37
38        let metadata = file_path.metadata()?;
39
40        let mtime = metadata.modified().ok();
41
42        self.tera.add_template_file(&file_path, Some(name))?;
43
44        self.files.insert(name, (file_path, mtime));
45
46        Ok(())
47    }
48
49    /// Unregister a template from a file by a name.
50    #[inline]
51    pub fn unregister_template_file<S: AsRef<str>>(&mut self, name: S) -> Option<PathBuf> {
52        let name = name.as_ref();
53
54        self.files.remove(name).map(|(file_path, _)| {
55            // TODO Remove template
56            file_path
57        })
58    }
59
60    /// Reload templates if needed.
61    #[inline]
62    pub fn reload_if_needed(&mut self) -> Result<(), TeraError> {
63        for (name, (file_path, mtime)) in &mut self.files {
64            let metadata = file_path.metadata()?;
65
66            let (reload, new_mtime) = match mtime {
67                Some(mtime) => match metadata.modified() {
68                    Ok(new_mtime) => (new_mtime > *mtime, Some(new_mtime)),
69                    Err(_) => (true, None),
70                },
71                None => match metadata.modified() {
72                    Ok(new_mtime) => (true, Some(new_mtime)),
73                    Err(_) => (true, None),
74                },
75            };
76
77            if reload {
78                self.tera.add_template_file(&file_path, Some(name))?;
79
80                *mtime = new_mtime;
81            }
82        }
83
84        Ok(())
85    }
86}
87
88impl Default for ReloadableTera {
89    #[inline]
90    fn default() -> Self {
91        ReloadableTera::new()
92    }
93}
94
95impl Deref for ReloadableTera {
96    type Target = Tera;
97
98    #[inline]
99    fn deref(&self) -> &Self::Target {
100        &self.tera
101    }
102}
103
104impl DerefMut for ReloadableTera {
105    #[inline]
106    fn deref_mut(&mut self) -> &mut Self::Target {
107        &mut self.tera
108    }
109}