Skip to main content

mhtemplate/
context.rs

1// Copyright 2020 Magnus Aa. Hirth. All rights reserved.
2//
3// The module `context` implements the `Context` type used to create scopes 
4// during evaluation of templates.
5
6use std::collections::{hash_map, HashMap};
7use std::ops::{Index, IndexMut};
8
9/// Evaluation context containing variable values.
10///
11/// A context can be created from the programs enviroment:
12/// ```Rust
13/// # use mhtemplate::Context;
14/// let vars = std::env::vars();
15/// let ctx  = Context::from(vars);
16/// ```
17///
18#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub struct Context(HashMap<String, String>);
20
21impl Context {
22    pub fn new() -> Self {
23        Context {
24            ..Default::default()
25        }
26    }
27
28    pub fn var(&self, name: &str) -> Option<&String> {
29        self.0.get(name)
30    }
31
32    pub fn var_mut(&mut self, name: &str) -> Option<&mut String> {
33        self.0.get_mut(name)
34    }
35
36    pub fn set_var(&mut self, name: String, val: String) -> Option<String> {
37        self.0.insert(name, val)
38    }
39
40    pub fn iter_vars(&self) -> hash_map::Iter<'_, String, String> {
41        self.0.iter()
42    }
43
44    pub fn iter_vars_mut(&mut self) -> hash_map::IterMut<'_, String, String> {
45        self.0.iter_mut()
46    }
47}
48
49impl From<std::env::Vars> for Context {
50
51    /// ```
52    /// # use mhtemplate::Context;
53    /// let vars = std::env::vars();
54    /// let ctx  = Context::from(vars);
55    /// ```
56    /// 
57    fn from(vars: std::env::Vars) -> Self {
58        let mut ctx = Context {
59            ..Default::default()
60        };
61        for (name, val) in vars {
62            ctx.set_var(name, val);
63        }
64        ctx
65    }
66}
67
68impl From<HashMap<String, String>> for Context {
69
70    /// ```
71    /// # use mhtemplate::Context;
72    /// # use std::collections::HashMap;
73    /// let mut vars = HashMap::new();
74    /// vars.insert(String::from("one"), String::from("1"));
75    /// let mut ctx = Context::from(vars);
76    /// ```
77    /// 
78    fn from(vars: HashMap<String, String>) -> Self {
79        Context(vars.clone())
80    }
81}
82
83impl From<&Context> for Context {
84    fn from(ctx: &Context) -> Self {
85        ctx.clone()
86    }
87}
88
89impl Index<&str> for Context {
90    type Output = String;
91
92    fn index(&self, index: &str) -> &Self::Output {
93        self.0.index(index)
94    }
95}
96
97impl IndexMut<&str> for Context {
98    fn index_mut(&mut self, index: &str) -> &mut Self::Output {
99        if !self.0.contains_key(index) {
100            self.0.insert(String::from(index), String::new());
101        }
102        self.0.get_mut(index).unwrap()
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn test_context() {
112        let s1 = String::from("one");
113        let i1 = String::from("1");
114        let s2 = String::from("two");
115        let i2 = String::from("2");
116
117        let mut vars = HashMap::new();
118        vars.insert(s1.clone(), i1.clone());
119        let mut ctx = Context::from(vars);
120
121        ctx[&s2] = i2.clone();
122        assert_eq!(ctx[&s1], i1);
123        assert_eq!(ctx[&s2], i2);
124    }
125}