use std::collections::HashMap;
use std::ops::Deref;
use std::str::FromStr;
use std::fmt::Debug;
use serde::de::{Deserialize, Deserializer};
use error::*;
use source::Source;
use value::{Value, ValueWithKey};
use path;
#[derive(Clone, Debug)]
enum ConfigKind {
Mutable {
defaults: HashMap<path::Expression, Value>,
overrides: HashMap<path::Expression, Value>,
sources: Vec<Box<Source + Send + Sync>>,
},
Frozen,
}
impl Default for ConfigKind {
fn default() -> Self {
ConfigKind::Mutable {
defaults: HashMap::new(),
overrides: HashMap::new(),
sources: Vec::new(),
}
}
}
#[derive(Default, Clone, Debug)]
pub struct Config {
kind: ConfigKind,
pub cache: Value,
}
impl Config {
pub fn new() -> Self {
Config::default()
}
pub fn merge<T>(&mut self, source: T) -> Result<&mut Config>
where
T: 'static,
T: Source + Send + Sync,
{
match self.kind {
ConfigKind::Mutable {
ref mut sources, ..
} => {
sources.push(Box::new(source));
}
ConfigKind::Frozen => {
return Err(ConfigError::Frozen);
}
}
self.refresh()
}
pub fn refresh(&mut self) -> Result<&mut Config> {
self.cache = match self.kind {
ConfigKind::Mutable {
ref overrides,
ref sources,
ref defaults,
} => {
let mut cache: Value = HashMap::<String, Value>::new().into();
for (key, val) in defaults {
key.set(&mut cache, val.clone());
}
sources.collect_to(&mut cache)?;
for (key, val) in overrides {
key.set(&mut cache, val.clone());
}
cache
}
ConfigKind::Frozen => {
return Err(ConfigError::Frozen);
}
};
Ok(self)
}
pub fn set_default<T>(&mut self, key: &str, value: T) -> Result<&mut Config>
where
T: Into<Value>,
{
match self.kind {
ConfigKind::Mutable {
ref mut defaults, ..
} => {
defaults.insert(key.to_lowercase().parse()?, value.into());
}
ConfigKind::Frozen => return Err(ConfigError::Frozen),
};
self.refresh()
}
pub fn set<T>(&mut self, key: &str, value: T) -> Result<&mut Config>
where
T: Into<Value>,
{
match self.kind {
ConfigKind::Mutable {
ref mut overrides, ..
} => {
overrides.insert(key.to_lowercase().parse()?, value.into());
}
ConfigKind::Frozen => return Err(ConfigError::Frozen),
};
self.refresh()
}
pub fn get<'de, T: Deserialize<'de>>(&self, key: &'de str) -> Result<T> {
let expr: path::Expression = key.to_lowercase().parse()?;
let value = expr.get(&self.cache).cloned();
match value {
Some(value) => {
T::deserialize(ValueWithKey::new(value, key))
}
None => Err(ConfigError::NotFound(key.into())),
}
}
pub fn get_str(&self, key: &str) -> Result<String> {
self.get(key).and_then(Value::into_str)
}
pub fn get_int(&self, key: &str) -> Result<i64> {
self.get(key).and_then(Value::into_int)
}
pub fn get_float(&self, key: &str) -> Result<f64> {
self.get(key).and_then(Value::into_float)
}
pub fn get_bool(&self, key: &str) -> Result<bool> {
self.get(key).and_then(Value::into_bool)
}
pub fn get_table(&self, key: &str) -> Result<HashMap<String, Value>> {
self.get(key).and_then(Value::into_table)
}
pub fn get_array(&self, key: &str) -> Result<Vec<Value>> {
self.get(key).and_then(Value::into_array)
}
pub fn try_into<'de, T: Deserialize<'de>>(self) -> Result<T> {
T::deserialize(self)
}
#[deprecated(since="0.7.0", note="please use 'try_into' instead")]
pub fn deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
self.try_into()
}
}
impl Source for Config {
fn clone_into_box(&self) -> Box<Source + Send + Sync> {
Box::new((*self).clone())
}
fn collect(&self) -> Result<HashMap<String, Value>> {
self.cache.clone().into_table()
}
}