pako_tools/
config.rs

1use std::{io, str::FromStr};
2
3pub struct Config {
4    value: toml::Value,
5}
6
7impl Default for Config {
8    fn default() -> Config {
9        Config {
10            value: toml::Value::Table(toml::map::Map::new()),
11        }
12    }
13}
14
15impl Config {
16    fn get_value<T: AsRef<str>>(&self, k: T) -> Option<&toml::Value> {
17        let mut item = &self.value;
18        for key in k.as_ref().split('.') {
19            item = item.get(key)?;
20        }
21        Some(item)
22    }
23    /// Get an entry by path. If the input argument contains dots, the path is split
24    /// into keys, each key being requested recursively.
25    pub fn get<T: AsRef<str>>(&self, k: T) -> Option<&str> {
26        let item = self.get_value(k)?;
27        item.as_str()
28    }
29    /// Get an entry of type integer by path
30    pub fn get_usize<T: AsRef<str>>(&self, k: T) -> Option<usize> {
31        let item = self.get_value(k)?;
32        item.as_integer()
33            .and_then(|i| if i >= 0 { Some(i as usize) } else { None })
34    }
35    /// Get an entry of type boolean by path
36    pub fn get_bool<T: AsRef<str>>(&self, k: T) -> Option<bool> {
37        let item = self.get_value(k)?;
38        item.as_bool()
39    }
40    /// Add a new section at location path.
41    /// To insert at root, use an empty path.
42    pub fn add_section<T: AsRef<str>, V: ToString>(
43        &mut self,
44        parent: T,
45        table_name: V,
46    ) -> Option<()> {
47        let mut item = &mut self.value;
48        if !parent.as_ref().is_empty() {
49            for key in parent.as_ref().split('.') {
50                item = item.get_mut(key)?;
51            }
52        }
53        if let Some(t) = item.as_table_mut() {
54            t.insert(
55                table_name.to_string(),
56                toml::Value::Table(toml::map::Map::new()),
57            );
58            return Some(());
59        }
60        None
61    }
62
63    /// Set an entry by path. If the input argument contains dots, the path is split
64    /// into keys, each key being requested recursively.
65    /// Intermediate path elements must already exist
66    pub fn set<T, V>(&mut self, k: T, v: V) -> Option<()>
67    where
68        T: AsRef<str>,
69        toml::value::Value: std::convert::From<V>,
70    {
71        let mut item = &mut self.value;
72        let path: Vec<_> = k.as_ref().split('.').collect();
73        if path.len() > 1 {
74            for key in path.iter().take(path.len() - 1) {
75                item = item.get_mut(key)?;
76            }
77        }
78        if let Some(t) = item.as_table_mut() {
79            if let Some(p) = path.last() {
80                t.insert((*p).to_string(), toml::Value::from(v));
81                return Some(());
82            }
83        }
84        None
85    }
86
87    /// Load configuration from input object. If keys are already present, they are overwritten
88    pub fn load_config<R: io::Read>(&mut self, mut config: R) -> Result<(), io::Error> {
89        let mut s = String::new();
90        config.read_to_string(&mut s)?;
91        match toml::Value::from_str(&s) {
92            Ok(value) => {
93                self.value = value;
94                Ok(())
95            }
96            _ => Err(io::Error::new(
97                io::ErrorKind::Other,
98                "Load configuration failed",
99            )),
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::Config;
107    #[test]
108    fn config_add_values() {
109        let mut config = Config::default();
110        let res = config.set("key1", "value1");
111        assert!(res.is_some());
112        // println!("set -> {:?}", res);
113        let res = config.get("key1");
114        assert!(res.is_some());
115        // println!("get -> {:?}", res);
116        assert_eq!(res, Some("value1"));
117        let res = config.add_section("", "mod1");
118        assert!(res.is_some());
119        // println!("add_section -> {:?}", res);
120        let res = config.set("mod1.key1", "value2");
121        assert!(res.is_some());
122        // println!("set -> {:?}", res);
123        let res = config.get("mod1.key1");
124        // println!("get -> {:?}", res);
125        assert_eq!(res, Some("value2"));
126    }
127}