summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRyan Leckey <ryan@launchbadge.com>2017-06-22 17:10:47 -0700
committerRyan Leckey <ryan@launchbadge.com>2017-06-22 17:10:47 -0700
commit6bfaf90fdf67197c511a7594b37d835e964edccd (patch)
treeaedca78e59887c30bd2e34626b06f24f29de0d81 /src
parent159bb52c595384fed44a2c669198d50f2a758a9a (diff)
Implement Source for Vec<T: Source> and From<Path> for File
Diffstat (limited to 'src')
-rw-r--r--src/config.rs22
-rw-r--r--src/file/mod.rs31
-rw-r--r--src/file/source/file.rs28
-rw-r--r--src/source.rs69
4 files changed, 104 insertions, 46 deletions
diff --git a/src/config.rs b/src/config.rs
index c8fc2e4..f1d5e93 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -89,26 +89,8 @@ impl Config {
}
// Add sources
- for source in sources {
- 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())
- }
- }
- }
+ if let Err(error) = sources.collect_to(&mut cache) {
+ return ConfigResult(Err(error));
}
// Add overrides
diff --git a/src/file/mod.rs b/src/file/mod.rs
index 6c45cb7..45deb92 100644
--- a/src/file/mod.rs
+++ b/src/file/mod.rs
@@ -5,7 +5,7 @@ use source::Source;
use error::*;
use value::Value;
use std::collections::HashMap;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use self::source::FileSource;
pub use self::format::FileFormat;
@@ -38,7 +38,7 @@ impl File<source::file::FileSourceFile> {
File {
format: Some(format),
required: true,
- source: source::file::FileSourceFile::new(name),
+ source: source::file::FileSourceFile::new(name.into()),
}
}
@@ -48,12 +48,37 @@ impl File<source::file::FileSourceFile> {
File {
format: None,
required: true,
- source: source::file::FileSourceFile::new(name),
+ source: source::file::FileSourceFile::new(name.into()),
+ }
+ }
+}
+
+impl<'a> From<&'a Path> for File<source::file::FileSourceFile> {
+ fn from(path: &'a Path) -> Self {
+ File {
+ format: None,
+ required: true,
+ source: source::file::FileSourceFile::new(path.to_path_buf()),
+ }
+ }
+}
+
+impl From<PathBuf> for File<source::file::FileSourceFile> {
+ fn from(path: PathBuf) -> Self {
+ File {
+ format: None,
+ required: true,
+ source: source::file::FileSourceFile::new(path),
}
}
}
impl<T: FileSource> File<T> {
+ pub fn format(mut self, format: FileFormat) -> Self {
+ self.format = Some(format);
+ self
+ }
+
pub fn required(mut self, required: bool) -> Self {
self.required = required;
self
diff --git a/src/file/source/file.rs b/src/file/source/file.rs
index 426c0b5..790933f 100644
--- a/src/file/source/file.rs
+++ b/src/file/source/file.rs
@@ -15,36 +15,20 @@ use super::{FileFormat, FileSource};
/// Describes a file sourced from a file
#[derive(Clone, Debug)]
pub struct FileSourceFile {
- /// Basename of configuration file
- name: String,
-
- /// Directory where configuration file is found
- /// When not specified, the current working directory (CWD) is considered
- path: Option<String>,
+ /// Path of configuration file
+ name: PathBuf,
}
impl FileSourceFile {
- pub fn new(name: &str) -> FileSourceFile {
- FileSourceFile {
- name: name.into(),
- path: None,
- }
+ pub fn new(name: PathBuf) -> FileSourceFile {
+ FileSourceFile { name: name }
}
fn find_file(&self,
format_hint: Option<FileFormat>)
-> Result<(PathBuf, FileFormat), Box<Error>> {
- // Build expected configuration file
- let mut basename = PathBuf::new();
-
- if let Some(ref path) = self.path {
- basename.push(path.clone());
- }
-
- basename.push(self.name.clone());
-
// First check for an _exact_ match
- let mut filename = env::current_dir()?.as_path().join(basename.clone());
+ let mut filename = env::current_dir()?.as_path().join(self.name.clone());
if filename.is_file() {
return match format_hint {
Some(format) => Ok((filename, format)),
@@ -92,7 +76,7 @@ impl FileSourceFile {
Err(Box::new(io::Error::new(io::ErrorKind::NotFound,
format!("configuration file \"{}\" not found",
- basename.to_string_lossy()))))
+ self.name.to_string_lossy()))))
}
}
diff --git a/src/source.rs b/src/source.rs
index c8a0e83..9bf28c5 100644
--- a/src/source.rs
+++ b/src/source.rs
@@ -1,7 +1,9 @@
use error::*;
use std::fmt::Debug;
-use value::Value;
+use std::str::FromStr;
+use value::{Value, ValueKind};
use std::collections::HashMap;
+use path;
/// Describes a generic _source_ of configuration properties.
pub trait Source: Debug {
@@ -10,6 +12,27 @@ pub trait Source: Debug {
/// Collect all configuration properties available from this source and return
/// a HashMap.
fn collect(&self) -> Result<HashMap<String, Value>>;
+
+ fn collect_to(&self, cache: &mut Value) -> Result<()> {
+ let props = match self.collect() {
+ Ok(props) => props,
+ Err(error) => {
+ return Err(error);
+ }
+ };
+
+ for (key, val) in &props {
+ match path::Expression::from_str(key) {
+ // Set using the path
+ Ok(expr) => expr.set(cache, val.clone()),
+
+ // Set diretly anyway
+ _ => path::Expression::Identifier(key.clone()).set(cache, val.clone()),
+ }
+ }
+
+ Ok(())
+ }
}
impl Clone for Box<Source + Send + Sync> {
@@ -17,3 +40,47 @@ impl Clone for Box<Source + Send + Sync> {
self.clone_into_box()
}
}
+
+impl Source for Vec<Box<Source + Send + Sync>> {
+ fn clone_into_box(&self) -> Box<Source + Send + Sync> {
+ Box::new((*self).clone())
+ }
+
+ fn collect(&self) -> Result<HashMap<String, Value>> {
+ let mut cache: Value = HashMap::<String, Value>::new().into();
+
+ for source in self {
+ source.collect_to(&mut cache)?;
+ }
+
+ if let ValueKind::Table(table) = cache.kind {
+ Ok(table)
+ } else {
+ unreachable!();
+ }
+ }
+}
+
+impl<T> Source for Vec<T>
+ where T: Source + Sync + Send,
+ T: Clone,
+ T: 'static
+{
+ fn clone_into_box(&self) -> Box<Source + Send + Sync> {
+ Box::new((*self).clone())
+ }
+
+ fn collect(&self) -> Result<HashMap<String, Value>> {
+ let mut cache: Value = HashMap::<String, Value>::new().into();
+
+ for source in self {
+ source.collect_to(&mut cache)?;
+ }
+
+ if let ValueKind::Table(table) = cache.kind {
+ Ok(table)
+ } else {
+ unreachable!();
+ }
+ }
+}