cratefield_core/
template.rs1use serde_json::Value;
17use std::collections::HashMap;
18use std::sync::Arc;
19use thiserror::Error;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct Rendered {
24 pub subject: String,
25 pub html: String,
26 pub text: String,
27}
28
29#[derive(Debug, Clone, Error)]
30pub enum TemplateError {
31 #[error("template {id:?} is not registered (locale {locale:?})")]
32 UnknownTemplate { id: String, locale: String },
33 #[error("template {id:?} failed to render: {reason}")]
34 RenderFailed { id: String, reason: String },
35}
36
37pub trait Template: Send + Sync {
41 fn render(&self, data: &Value, locale: &str) -> Result<Rendered, TemplateError>;
45}
46
47#[derive(Clone, Default)]
50pub struct TemplateRegistry {
51 templates: HashMap<String, Arc<dyn Template>>,
52}
53
54impl TemplateRegistry {
55 pub fn new() -> Self {
56 Self::default()
57 }
58
59 pub fn register(&mut self, id: impl Into<String>, template: Box<dyn Template>) {
61 self.templates.insert(id.into(), Arc::from(template));
62 }
63
64 pub fn register_all(
67 &mut self,
68 templates: impl IntoIterator<Item = (String, Box<dyn Template>)>,
69 ) {
70 for (id, template) in templates {
71 self.register(id, template);
72 }
73 }
74
75 pub fn render(&self, id: &str, data: &Value, locale: &str) -> Result<Rendered, TemplateError> {
82 let localized = format!("{id}@{locale}");
83 if let Some(template) = self.templates.get(&localized) {
84 return template.render(data, locale);
85 }
86 match self.templates.get(id) {
87 Some(template) => template.render(data, locale),
88 None => Err(TemplateError::UnknownTemplate {
89 id: id.to_string(),
90 locale: locale.to_string(),
91 }),
92 }
93 }
94
95 pub fn contains(&self, id: &str, locale: &str) -> bool {
97 self.templates.contains_key(&format!("{id}@{locale}")) || self.templates.contains_key(id)
98 }
99}
100
101impl std::fmt::Debug for TemplateRegistry {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 let mut ids: Vec<&String> = self.templates.keys().collect();
104 ids.sort();
105 f.debug_struct("TemplateRegistry")
106 .field("ids", &ids)
107 .finish()
108 }
109}