From bfc44c331a77d8c341c076e72df5ed0b56fbd422 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Thu, 1 Jun 2017 23:22:04 -0700 Subject: Move things around and get some tests in place --- src/config.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/config.rs (limited to 'src/config.rs') diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..4d24a1d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,104 @@ +use std::collections::HashMap; +use serde::de::Deserialize; + +use error::*; +use source::Source; +use value::Value; +use path; + +enum ConfigKind { + // A mutable configuration. This is the default. + Mutable { + defaults: HashMap, + overrides: HashMap, + sources: Vec>, + }, + + // A frozen configuration. + // Configuration can no longer be mutated. + Frozen, +} + +impl Default for ConfigKind { + fn default() -> Self { + ConfigKind::Mutable { + defaults: HashMap::new(), + overrides: HashMap::new(), + sources: Vec::new(), + } + } +} + +/// 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(Default)] +pub struct Config { + kind: ConfigKind, + + /// Root of the cached configuration. + pub cache: Value, +} + +impl Config { + /// Merge in a configuration property source. + pub fn merge(&mut self, source: T) -> Result<()> + 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() + } + + /// Refresh the configuration cache with fresh + /// data from added sources. + /// + /// Configuration is automatically refreshed after a mutation + /// operation (`set`, `merge`, `set_default`, etc.). + pub fn refresh(&mut self) -> Result<()> { + self.cache = match self.kind { + // TODO: We need to actually merge in all the stuff + ConfigKind::Mutable { + ref overrides, + ref sources, + ref defaults, + } => sources[0].collect()?, + + ConfigKind::Frozen => { + return Err(ConfigError::Frozen); + } + }; + + Ok(()) + } + + pub fn deserialize(&self) -> Result { + return T::deserialize(self.cache.clone()); + } + + pub fn get(&self, key: &str) -> Result { + // Parse the key into a path expression + let expr: path::Expression = key.to_lowercase().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) + } + + None => Err(ConfigError::NotFound(key.into())), + } + } +} -- cgit v1.2.3