summaryrefslogtreecommitdiffstats
path: root/src/config.rs
diff options
context:
space:
mode:
authorRyan Leckey <ryan@launchbadge.com>2017-06-22 14:14:29 -0700
committerRyan Leckey <ryan@launchbadge.com>2017-06-22 14:30:51 -0700
commit2b438ed9b53fee5689032f3b5fcdda8d15becd5f (patch)
tree48374e66a6594c7d11d19fe38f7e23df731b52be /src/config.rs
parent04d3ee8f70337e4899932b92262fbeec2dbb1bd9 (diff)
Add builder API to Config
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs185
1 files changed, 158 insertions, 27 deletions
diff --git a/src/config.rs b/src/config.rs
index 44c51d1..c8fc2e4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,5 +1,7 @@
use std::collections::HashMap;
+use std::ops::Deref;
use std::str::FromStr;
+use std::fmt::Debug;
use serde::de::Deserialize;
use error::*;
@@ -8,6 +10,7 @@ use source::Source;
use value::{Value, ValueWithKey};
use path;
+#[derive(Clone, Debug)]
enum ConfigKind {
// A mutable configuration. This is the default.
Mutable {
@@ -34,7 +37,7 @@ impl Default for ConfigKind {
/// 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)]
+#[derive(Default, Clone, Debug)]
pub struct Config {
kind: ConfigKind,
@@ -48,7 +51,7 @@ impl Config {
}
/// Merge in a configuration property source.
- pub fn merge<T>(&mut self, source: T) -> Result<()>
+ pub fn merge<T>(&mut self, source: T) -> ConfigResult
where T: 'static,
T: Source + Send + Sync
{
@@ -58,7 +61,7 @@ impl Config {
}
ConfigKind::Frozen => {
- return Err(ConfigError::Frozen);
+ return ConfigResult(Err(ConfigError::Frozen));
}
}
@@ -70,7 +73,7 @@ impl Config {
///
/// Configuration is automatically refreshed after a mutation
/// operation (`set`, `merge`, `set_default`, etc.).
- pub fn refresh(&mut self) -> Result<()> {
+ pub fn refresh(&mut self) -> ConfigResult {
self.cache = match self.kind {
// TODO: We need to actually merge in all the stuff
ConfigKind::Mutable {
@@ -87,14 +90,23 @@ impl Config {
// Add sources
for source in sources {
- let props = source.collect()?;
+ let props = match source.collect() {
+ Ok(props) => props,
+ Err(error) => {
+ return ConfigResult(Err(error));
+ }
+ };
+
for (key, val) in &props {
match path::Expression::from_str(key) {
// Set using the path
Ok(expr) => expr.set(&mut cache, val.clone()),
// Set diretly anyway
- _ => path::Expression::Identifier(key.clone()).set(&mut cache, val.clone())
+ _ => {
+ path::Expression::Identifier(key.clone())
+ .set(&mut cache, val.clone())
+ }
}
}
}
@@ -105,14 +117,14 @@ impl Config {
}
cache
- },
+ }
ConfigKind::Frozen => {
- return Err(ConfigError::Frozen);
+ return ConfigResult(Err(ConfigError::Frozen));
}
};
- Ok(())
+ ConfigResult(Ok(self))
}
/// Deserialize the entire configuration.
@@ -120,39 +132,41 @@ impl Config {
T::deserialize(self.cache.clone())
}
- pub fn set_default<T>(&mut self, key: &str, value: T) -> Result<()>
+ pub fn set_default<T>(&mut self, key: &str, value: T) -> ConfigResult
where T: Into<Value>
{
match self.kind {
- ConfigKind::Mutable {
- ref mut defaults,
- ..
- } => {
- defaults.insert(key.to_lowercase().parse()?, value.into());
+ ConfigKind::Mutable { ref mut defaults, .. } => {
+ defaults.insert(match key.to_lowercase().parse() {
+ Ok(expr) => expr,
+ Err(error) => {
+ return ConfigResult(Err(error));
+ }
+ },
+ value.into());
}
- ConfigKind::Frozen => {
- return Err(ConfigError::Frozen)
- }
+ ConfigKind::Frozen => return ConfigResult(Err(ConfigError::Frozen)),
};
self.refresh()
}
- pub fn set<T>(&mut self, key: &str, value: T) -> Result<()>
+ pub fn set<T>(&mut self, key: &str, value: T) -> ConfigResult
where T: Into<Value>
{
match self.kind {
- ConfigKind::Mutable {
- ref mut overrides,
- ..
- } => {
- overrides.insert(key.to_lowercase().parse()?, value.into());
+ ConfigKind::Mutable { ref mut overrides, .. } => {
+ overrides.insert(match key.to_lowercase().parse() {
+ Ok(expr) => expr,
+ Err(error) => {
+ return ConfigResult(Err(error));
+ }
+ },
+ value.into());
}
- ConfigKind::Frozen => {
- return Err(ConfigError::Frozen)
- }
+ ConfigKind::Frozen => return ConfigResult(Err(ConfigError::Frozen)),
};
self.refresh()
@@ -199,3 +213,120 @@ impl Config {
self.get(key).and_then(Value::into_array)
}
}
+
+pub struct ConfigResult<'a>(Result<&'a mut Config>);
+
+#[inline]
+fn unwrap_failed<E: Debug>(msg: &str, error: E) -> ! {
+ panic!("{}: {:?}", msg, error)
+}
+
+impl<'a> ConfigResult<'a> {
+ pub fn merge<T>(self, source: T) -> ConfigResult<'a>
+ where T: 'static,
+ T: Source + Send + Sync
+ {
+ match self.0 {
+ // If OK, Proceed to nested method
+ Ok(instance) => instance.merge(source),
+
+ // Else, Forward the error
+ error => ConfigResult(error),
+ }
+ }
+
+ pub fn set_default<T>(self, key: &str, value: T) -> ConfigResult<'a>
+ where T: Into<Value>,
+ T: 'static
+ {
+ match self.0 {
+ // If OK, Proceed to nested method
+ Ok(instance) => instance.set_default(key, value),
+
+ // Else, Forward the error
+ error => ConfigResult(error),
+ }
+ }
+
+ pub fn set<T>(self, key: &str, value: T) -> ConfigResult<'a>
+ where T: Into<Value>,
+ T: 'static
+ {
+ match self.0 {
+ // If OK, Proceed to nested method
+ Ok(instance) => instance.set(key, value),
+
+ // Else, Forward the error
+ error => ConfigResult(error),
+ }
+ }
+
+ /// Forwards `Result::is_ok`
+ #[inline]
+ pub fn is_ok(&self) -> bool {
+ match self.0 {
+ Ok(_) => true,
+ Err(_) => false,
+ }
+ }
+
+ /// Forwards `Result::is_err`
+ #[inline]
+ pub fn is_err(&self) -> bool {
+ !self.is_ok()
+ }
+
+ /// Forwards `Result::ok`
+ #[inline]
+ pub fn ok(self) -> Option<Config> {
+ match self.0 {
+ Ok(x) => Some(x.clone()),
+ Err(_) => None,
+ }
+ }
+
+ /// Forwards `Result::err`
+ #[inline]
+ pub fn err(self) -> Option<ConfigError> {
+ match self.0 {
+ Ok(_) => None,
+ Err(x) => Some(x),
+ }
+ }
+
+ /// Forwards `Result::unwrap`
+ #[inline]
+ pub fn unwrap(self) -> Config {
+ match self.0 {
+ Ok(instance) => instance.clone(),
+ Err(error) => unwrap_failed("called `Result::unwrap()` on an `Err` value", error),
+ }
+ }
+
+ /// Forwards `Result::expect`
+ #[inline]
+ pub fn expect(self, msg: &str) -> Config {
+ match self.0 {
+ Ok(instance) => instance.clone(),
+ Err(error) => unwrap_failed(msg, error),
+ }
+ }
+
+ /// Forwards `Result::unwrap_err`
+ #[inline]
+ pub fn unwrap_err(self) -> ConfigError {
+ match self.0 {
+ Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", t),
+ Err(e) => e,
+ }
+ }
+
+ /// Forwards `Result::expect_err`
+ #[inline]
+ pub fn expect_err(self, msg: &str) -> ConfigError {
+ match self.0 {
+ Ok(t) => unwrap_failed(msg, t),
+ Err(e) => e,
+ }
+ }
+}