struct_string_template/
templater.rs1use std::{collections::HashMap};
2
3use crate::err::TemplateError;
4use crate::formatter::{TemplateElement, Formatter};
5
6pub struct Templater<T> {
7 mapping: HashMap<String, Box<dyn Fn(&T) -> Option<String> + 'static + Send + Sync>>
8}
9
10impl<T> Templater<T> {
11 pub fn new() -> Self {
12 Templater {
13 mapping: HashMap::new(),
14 }
15 }
16
17 pub fn insert<S, F>(&mut self, selector: S, accessor: F)
18 where
19 S: Into<String>,
20 F: Fn(&T) -> Option<String> + 'static + Send + Sync
21 {
22 self.mapping.insert(selector.into(), Box::new(accessor));
23 }
24
25 pub fn extend<I, S, U>(&mut self, selectors: I)
26 where
27 I: IntoIterator<Item = (S, U)>,
28 S: Into<String>,
29 U: Fn(&T) -> Option<String> + 'static + Send + Sync
30 {
31 for (selector, accessor) in selectors {
32 self.insert(selector, accessor);
33 }
34 }
35
36 pub fn remove<S>(&mut self, selector: S) -> bool
37 where S: Into<String>
38 {
39 self.mapping.remove(&selector.into()).is_some()
40 }
41
42 pub fn renderf(&self, obj: &T, formatter: &Formatter) -> Result<String, TemplateError> {
43 let strings: Vec<String> = formatter
44 .elements
45 .iter()
46 .map(|e| {
47 match e {
48 TemplateElement::Part { literal } => {
49 Ok(literal.clone())
50 }
51 TemplateElement::Replace { selector } => {
52 let accessor = self.mapping.get(selector);
53
54 match accessor {
59 Some(f) => {
60 let out = f(&obj).or(Some("NA".to_owned())).unwrap();
61 Ok(out)
62 },
63 None => Err(TemplateError::UnknownSelector {
64 selector: selector.clone(),
65 }),
66 }
67 }
68 }
69 })
70 .collect::<Result<Vec<String>, TemplateError>>()?;
71
72 Ok(strings
73 .into_iter()
74 .reduce(|a, b| a + &b)
75 .or(Some("".to_owned()))
76 .unwrap())
77 }
78
79 pub fn render<S>(&self, obj: &T, fmts: S) -> Result<String, TemplateError>
80 where S: Into<String>
81 {
82 let formatter = Formatter::build(fmts.into())?;
83 self.renderf(obj, &formatter)
84 }
85}