blob: 27b318dd89728b0b7ffc2004f1914ccf76449ae4 [file] [log] [blame]
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<path::Expression, Value>,
overrides: Map<path::Expression, Value>,
sources: Vec<Box<dyn Source + Send + Sync>>,
/// 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<DefaultState> {
ConfigBuilder::<DefaultState>::default()
}
/// Merge in a configuration property source.
#[deprecated(since = "0.12.0", note = "please use 'ConfigBuilder' instead")]
pub fn merge<T>(&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<T>(mut self, source: T) -> Result<Self>
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::<String, Value>::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<T>(&mut self, key: &str, value: T) -> Result<&mut Self>
where
T: Into<Value>,
{
self.defaults.insert(key.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<T>(&mut self, key: &str, value: T) -> Result<&mut Self>
where
T: Into<Value>,
{
self.overrides.insert(key.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.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(())
}
pub fn get<'de, T: Deserialize<'de>>(&self, key: &str) -> Result<T> {
// 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();
match value {
Some(value) => {
// Deserialize the received value into the requested type
T::deserialize(value).map_err(|e| e.extend_with_key(key))
}
None => Err(ConfigError::NotFound(key.into())),
}
}
pub fn get_string(&self, key: &str) -> Result<String> {
self.get(key).and_then(Value::into_string)
}
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<Map<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)
}
/// Attempt to deserialize the entire configuration into the requested type.
pub fn try_deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
T::deserialize(self)
}
/// Attempt to serialize the entire configuration from the given type.
pub fn try_from<T: Serialize>(from: &T) -> Result<Self> {
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<T> {
self.try_deserialize()
}
}
impl Source for Config {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new((*self).clone())
}
fn collect(&self) -> Result<Map<String, Value>> {
self.cache.clone().into_table()
}
}