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 pub fn get<T: AsRef<str>>(&self, k: T) -> Option<&str> {
26 let item = self.get_value(k)?;
27 item.as_str()
28 }
29 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 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 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 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 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 let res = config.get("key1");
114 assert!(res.is_some());
115 assert_eq!(res, Some("value1"));
117 let res = config.add_section("", "mod1");
118 assert!(res.is_some());
119 let res = config.set("mod1.key1", "value2");
121 assert!(res.is_some());
122 let res = config.get("mod1.key1");
124 assert_eq!(res, Some("value2"));
126 }
127}