From 6bfaf90fdf67197c511a7594b37d835e964edccd Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Thu, 22 Jun 2017 17:10:47 -0700 Subject: Implement Source for Vec and From for File --- src/config.rs | 22 ++-------------- src/file/mod.rs | 31 +++++++++++++++++++--- src/file/source/file.rs | 28 +++++--------------- src/source.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 46 deletions(-) (limited to 'src') 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 { 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 { 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 { + fn from(path: &'a Path) -> Self { + File { + format: None, + required: true, + source: source::file::FileSourceFile::new(path.to_path_buf()), + } + } +} + +impl From for File { + fn from(path: PathBuf) -> Self { + File { + format: None, + required: true, + source: source::file::FileSourceFile::new(path), } } } impl File { + 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, + /// 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) -> Result<(PathBuf, FileFormat), Box> { - // 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>; + + 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 { @@ -17,3 +40,47 @@ impl Clone for Box { self.clone_into_box() } } + +impl Source for Vec> { + fn clone_into_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn collect(&self) -> Result> { + let mut cache: Value = HashMap::::new().into(); + + for source in self { + source.collect_to(&mut cache)?; + } + + if let ValueKind::Table(table) = cache.kind { + Ok(table) + } else { + unreachable!(); + } + } +} + +impl Source for Vec + where T: Source + Sync + Send, + T: Clone, + T: 'static +{ + fn clone_into_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn collect(&self) -> Result> { + let mut cache: Value = HashMap::::new().into(); + + for source in self { + source.collect_to(&mut cache)?; + } + + if let ValueKind::Table(table) = cache.kind { + Ok(table) + } else { + unreachable!(); + } + } +} -- cgit v1.2.3