use std::{io, str::FromStr};
pub struct Config {
value: toml::Value,
}
impl Default for Config {
fn default() -> Config {
Config {
value: toml::Value::Table(toml::map::Map::new()),
}
}
}
impl Config {
fn get_value<T: AsRef<str>>(&self, k: T) -> Option<&toml::Value> {
let mut item = &self.value;
for key in k.as_ref().split('.') {
item = item.get(key)?;
}
Some(item)
}
pub fn get<T: AsRef<str>>(&self, k: T) -> Option<&str> {
let item = self.get_value(k)?;
item.as_str()
}
pub fn get_usize<T: AsRef<str>>(&self, k: T) -> Option<usize> {
let item = self.get_value(k)?;
item.as_integer()
.and_then(|i| if i >= 0 { Some(i as usize) } else { None })
}
pub fn get_bool<T: AsRef<str>>(&self, k: T) -> Option<bool> {
let item = self.get_value(k)?;
item.as_bool()
}
pub fn add_section<T: AsRef<str>, V: ToString>(
&mut self,
parent: T,
table_name: V,
) -> Option<()> {
let mut item = &mut self.value;
if !parent.as_ref().is_empty() {
for key in parent.as_ref().split('.') {
item = item.get_mut(key)?;
}
}
if let Some(t) = item.as_table_mut() {
t.insert(
table_name.to_string(),
toml::Value::Table(toml::map::Map::new()),
);
return Some(());
}
None
}
pub fn set<T, V>(&mut self, k: T, v: V) -> Option<()>
where
T: AsRef<str>,
toml::value::Value: std::convert::From<V>,
{
let mut item = &mut self.value;
let path: Vec<_> = k.as_ref().split('.').collect();
if path.len() > 1 {
for key in path.iter().take(path.len() - 1) {
item = item.get_mut(key)?;
}
}
if let Some(t) = item.as_table_mut() {
if let Some(p) = path.last() {
t.insert((*p).to_string(), toml::Value::from(v));
return Some(());
}
}
None
}
pub fn load_config<R: io::Read>(&mut self, mut config: R) -> Result<(), io::Error> {
let mut s = String::new();
config.read_to_string(&mut s)?;
match toml::Value::from_str(&s) {
Ok(value) => {
self.value = value;
Ok(())
}
_ => Err(io::Error::new(
io::ErrorKind::Other,
"Load configuration failed",
)),
}
}
}
#[cfg(test)]
mod tests {
use super::Config;
#[test]
fn config_add_values() {
let mut config = Config::default();
let res = config.set("key1", "value1");
assert!(res.is_some());
let res = config.get("key1");
assert!(res.is_some());
assert_eq!(res, Some("value1"));
let res = config.add_section("", "mod1");
assert!(res.is_some());
let res = config.set("mod1.key1", "value2");
assert!(res.is_some());
let res = config.get("mod1.key1");
assert_eq!(res, Some("value2"));
}
}