diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/file.rs | 143 | ||||
-rw-r--r-- | src/lib.rs | 7 | ||||
-rw-r--r-- | src/source.rs | 127 | ||||
-rw-r--r-- | src/value.rs | 11 |
4 files changed, 152 insertions, 136 deletions
diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..2ffc836 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,143 @@ +use std::fs; +use std::env; +use std::error::Error; +use std::io::Read; +use std::collections::HashMap; + +use toml; + +use value::Value; +use source::Source; + +#[derive(Default)] +pub struct File { + /// 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>, + + /// Namespace to restrict configuration from the file + namespace: Option<String>, + + /// A required File will error if it cannot be found + required: bool, +} + +impl File { + pub fn with_name(name: &str) -> File { + File { + name: name.into(), + required: true, + + ..Default::default() + } + } + + pub fn path(&mut self, path: &str) -> &mut File { + self.path = Some(path.into()); + self + } + + pub fn namespace(&mut self, namespace: &str) -> &mut File { + self.namespace = Some(namespace.into()); + self + } + + pub fn required(&mut self, required: bool) -> &mut File { + self.required = required; + self + } +} + +fn toml_collect(content: &mut HashMap<String, Value>, + table: &toml::Table, + prefix: Option<String>) { + for (key, value) in table { + // Construct full key from prefix + let key = if let Some(ref prefix) = prefix { + prefix.clone() + "." + key + } else { + key.clone() + }; + + match *value { + // Recurse into nested table + toml::Value::Table(ref table) => toml_collect(content, table, Some(key)), + + toml::Value::String(ref value) => { + content.insert(key, value.clone().into()); + } + + toml::Value::Integer(value) => { + content.insert(key, value.into()); + } + + toml::Value::Float(value) => { + content.insert(key, value.into()); + } + + toml::Value::Boolean(value) => { + content.insert(key, value.into()); + } + + _ => { + // Unhandled + } + } + } +} + +impl Source for File { + fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>> { + let mut content = HashMap::new(); + + // Find file + // TODO: Use a nearest algorithm rather than strictly CWD + let cwd = match env::current_dir() { + Ok(cwd) => cwd, + Err(err) => { + if self.required { + return Err(From::from(err)); + } else { + return Ok(content); + } + } + }; + + let filename = cwd.join(self.name.clone() + ".toml"); + + // Read contents from file + let mut file = match fs::File::open(filename) { + Ok(file) => file, + Err(err) => { + if self.required { + return Err(From::from(err)); + } else { + return Ok(content); + } + } + }; + + let mut buffer = String::new(); + let res = file.read_to_string(&mut buffer); + if res.is_err() { + if self.required { + return Err(From::from(res.err().unwrap())); + } else { + return Ok(content); + } + } + + // Parse + let mut parser = toml::Parser::new(&buffer); + // TODO: Get a solution to make this return an Error-able + let document = parser.parse().unwrap(); + + // Iterate through document and fill content + toml_collect(&mut content, &document, None); + + Ok(content) + } +} @@ -5,6 +5,7 @@ extern crate toml; mod value; mod source; +mod file; mod config; use std::error::Error; @@ -12,7 +13,7 @@ use std::borrow::Cow; use std::sync::{Once, ONCE_INIT}; pub use source::Source; -pub use source::File; +pub use file::File; pub use value::Value; @@ -25,9 +26,7 @@ static CONFIG_INIT: Once = ONCE_INIT; // Get the global configuration instance fn global() -> &'static mut Config { unsafe { - CONFIG_INIT.call_once(|| { - CONFIG = Some(Default::default()); - }); + CONFIG_INIT.call_once(|| { CONFIG = Some(Default::default()); }); CONFIG.as_mut().unwrap() } diff --git a/src/source.rs b/src/source.rs index b608097..95785a6 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,135 +1,8 @@ -use std::fs; -use std::env; use std::error::Error; -use std::io::Read; use std::collections::HashMap; -use toml; - use value::Value; pub trait Source { fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>>; } - -#[derive(Default)] -pub struct File { - // Basename of configuration file - name: String, - - // Namespace to restrict configuration from the file - namespace: Option<String>, - - // A required File will error if it cannot be found - required: bool, -} - -impl File { - pub fn with_name(name: &str) -> File { - File { - name: name.into(), - required: true, - - ..Default::default() - } - } - - pub fn namespace(&mut self, namespace: &str) -> &mut File { - self.namespace = Some(namespace.into()); - self - } - - pub fn required(&mut self, required: bool) -> &mut File { - self.required = required; - self - } -} - -fn collect(content: &mut HashMap<String, Value>, table: &toml::Table, prefix: Option<String>) { - for (key, value) in table { - // Construct full key from prefix - let key = if let Some(ref prefix) = prefix { - prefix.clone() + "." + key - } else { - key.clone() - }; - - match *value { - // Recurse into nested table - toml::Value::Table(ref table) => collect(content, table, Some(key)), - - toml::Value::String(ref value) => { - content.insert(key, value.clone().into()); - } - - toml::Value::Integer(value) => { - content.insert(key, value.into()); - } - - toml::Value::Float(value) => { - content.insert(key, value.into()); - } - - toml::Value::Boolean(value) => { - content.insert(key, value.into()); - } - - _ => { - // Unhandled - } - } - } -} - -impl Source for File { - fn build(&mut self) -> Result<HashMap<String, Value>, Box<Error>> { - let mut content = HashMap::new(); - - // Find file - // TODO: Use a nearest algorithm rather than strictly CWD - let cwd = match env::current_dir() { - Ok(cwd) => cwd, - Err(err) => { - if self.required { - return Err(From::from(err)); - } else { - return Ok(content); - } - } - }; - - let filename = cwd.join(self.name.clone() + ".toml"); - - // Read contents from file - let mut file = match fs::File::open(filename) { - Ok(file) => file, - Err(err) => { - if self.required { - return Err(From::from(err)); - } else { - return Ok(content); - } - } - }; - - let mut buffer = String::new(); - let res = file.read_to_string(&mut buffer); - if res.is_err() { - if self.required { - return Err(From::from(res.err().unwrap())); - } else { - return Ok(content); - } - } - - // Parse - let mut parser = toml::Parser::new(&buffer); - // TODO: Get a solution to make this return an Error-able - let document = parser.parse().unwrap(); - - // Iterate through document and fill content - collect(&mut content, &document, None); - - Ok(content) - } -} diff --git a/src/value.rs b/src/value.rs index 192632b..52a2103 100644 --- a/src/value.rs +++ b/src/value.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; /// /// Has an underlying or native type that comes from the configuration source /// but will be coerced into the requested type. -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum Value { String(String), Integer(i64), @@ -35,10 +35,11 @@ impl Value { if let Value::Boolean(value) = *self { Some(value) } else if let Value::String(ref value) = *self { - Some(match value.to_lowercase().as_ref() { - "1" | "true" | "on" | "yes" => true, - _ => false, - }) + match value.to_lowercase().as_ref() { + "1" | "true" | "on" | "yes" => Some(true), + "0" | "false" | "off" | "no" => Some(false), + _ => None, + } } else if let Value::Integer(value) = *self { Some(value != 0) } else if let Value::Float(value) = *self { |