use std::fmt::Debug; use crate::builder::{ConfigBuilder, DefaultState}; use serde::de::Deserialize; use serde::ser::Serialize; use crate::error::{ConfigError, Result}; use crate::map::Map; use crate::path; use crate::ser::ConfigSerializer; use crate::source::Source; use crate::value::{Table, Value}; /// A prioritized configuration repository. It maintains a set of /// configuration sources, fetches values to populate those, and provides /// them according to the source's priority. #[derive(Clone, Debug)] pub struct Config { defaults: Map, overrides: Map, sources: Vec>, /// Root of the cached configuration. pub cache: Value, } impl Default for Config { fn default() -> Self { Self { defaults: Default::default(), overrides: Default::default(), sources: Default::default(), cache: Value::new(None, Table::new()), } } } impl Config { pub(crate) fn new(value: Value) -> Self { Self { cache: value, ..Self::default() } } /// Creates new [`ConfigBuilder`] instance pub fn builder() -> ConfigBuilder { ConfigBuilder::::default() } /// Merge in a configuration property source. #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn merge(&mut self, source: T) -> Result<&mut Self> where T: 'static, T: Source + Send + Sync, { self.sources.push(Box::new(source)); #[allow(deprecated)] self.refresh() } /// Merge in a configuration property source. #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn with_merged(mut self, source: T) -> Result where T: 'static, T: Source + Send + Sync, { self.sources.push(Box::new(source)); #[allow(deprecated)] self.refresh()?; Ok(self) } /// Refresh the configuration cache with fresh /// data from added sources. /// /// Configuration is automatically refreshed after a mutation /// operation (`set`, `merge`, `set_default`, etc.). #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn refresh(&mut self) -> Result<&mut Self> { self.cache = { let mut cache: Value = Map::::new().into(); // Add defaults for (key, val) in &self.defaults { key.set(&mut cache, val.clone()); } // Add sources self.sources.collect_to(&mut cache)?; // Add overrides for (key, val) in &self.overrides { key.set(&mut cache, val.clone()); } cache }; Ok(self) } /// Set a default `value` at `key` #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn set_default(&mut self, key: &str, value: T) -> Result<&mut Self> where T: Into, { self.defaults .insert(key.to_lowercase().as_str().parse()?, value.into()); #[allow(deprecated)] self.refresh() } /// Set an overwrite /// /// This function sets an overwrite value. /// The overwrite `value` is written to the `key` location on every `refresh()` /// /// # Warning /// /// Errors if config is frozen #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn set(&mut self, key: &str, value: T) -> Result<&mut Self> where T: Into, { self.overrides .insert(key.to_lowercase().as_str().parse()?, value.into()); #[allow(deprecated)] self.refresh() } #[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")] pub fn set_once(&mut self, key: &str, value: Value) -> Result<()> { let expr: path::Expression = key.to_lowercase().as_str().parse()?; // Traverse the cache using the path to (possibly) retrieve a value if let Some(ref mut val) = expr.get_mut(&mut self.cache) { **val = value; } else { expr.set(&mut self.cache, value); } Ok(()) } fn get_value(&self, key: &str) -> Result { let k = key.to_lowercase(); let key = k.as_str(); // Parse the key into a path expression let expr: path::Expression = key.parse()?; // Traverse the cache using the path to (possibly) retrieve a value let value = expr.get(&self.cache).cloned(); value.ok_or_else(|| ConfigError::NotFound(key.into())) } pub fn get<'de, T: Deserialize<'de>>(&self, key: &str) -> Result { self.get_value(key).and_then(|value| { // Deserialize the received value into the requested type T::deserialize(value).map_err(|e| e.extend_with_key(key)) }) } pub fn get_string(&self, key: &str) -> Result { self.get_value(key) .and_then(|value| value.into_string().map_err(|e| e.extend_with_key(key))) } pub fn get_int(&self, key: &str) -> Result { self.get_value(key) .and_then(|value| value.into_int().map_err(|e| e.extend_with_key(key))) } pub fn get_float(&self, key: &str) -> Result { self.get_value(key) .and_then(|value| value.into_float().map_err(|e| e.extend_with_key(key))) } pub fn get_bool(&self, key: &str) -> Result { self.get_value(key) .and_then(|value| value.into_bool().map_err(|e| e.extend_with_key(key))) } pub fn get_table(&self, key: &str) -> Result> { self.get_value(key) .and_then(|value| value.into_table().map_err(|e| e.extend_with_key(key))) } pub fn get_array(&self, key: &str) -> Result> { self.get_value(key) .and_then(|value| value.into_array().map_err(|e| e.extend_with_key(key))) } /// Attempt to deserialize the entire configuration into the requested type. pub fn try_deserialize<'de, T: Deserialize<'de>>(self) -> Result { T::deserialize(self) } /// Attempt to serialize the entire configuration from the given type. pub fn try_from(from: &T) -> Result { let mut serializer = ConfigSerializer::default(); from.serialize(&mut serializer)?; Ok(serializer.output) } #[deprecated(since = "0.7.0", note = "please use 'try_deserialize' instead")] pub fn deserialize<'de, T: Deserialize<'de>>(self) -> Result { self.try_deserialize() } } impl Source for Config { fn clone_into_box(&self) -> Box { Box::new((*self).clone()) } fn collect(&self) -> Result> { self.cache.clone().into_table() } }