mod format; pub mod source; use source::Source; use error::*; use value::Value; use std::collections::HashMap; use self::source::FileSource; pub use self::format::FileFormat; pub struct File where T: FileSource { source: T, /// Namespace to restrict configuration from the file namespace: Option, /// Format of file (which dictates what driver to use). format: Option, /// A required File will error if it cannot be found required: bool, } impl File { pub fn from_str(s: &str, format: FileFormat) -> Self { File { format: Some(format), required: true, namespace: None, source: s.into(), } } } impl File { pub fn new(name: &str, format: FileFormat) -> Self { File { format: Some(format), required: true, namespace: None, source: source::file::FileSourceFile::new(name), } } } impl File { pub fn required(mut self, required: bool) -> Self { self.required = required; self } pub fn namespace(mut self, namespace: &str) -> Self { self.namespace = Some(namespace.into()); self } } impl Source for File { fn collect(&self) -> Result> { // Coerce the file contents to a string let (uri, contents) = match self.source.resolve(self.format).map_err(|err| { ConfigError::Foreign(err) }) { Ok((uri, contents)) => (uri, contents), Err(error) => { if !self.required { return Ok(HashMap::new()); } return Err(error); } }; // Parse the string using the given format let result = self.format.unwrap().parse(uri.as_ref(), &contents, self.namespace.as_ref()).map_err(|cause| { ConfigError::FileParse { uri: uri, cause: cause } }); if result.is_err() && !self.required { // Ignore fails and just go with it if its not required Ok(HashMap::new()) } else { result } } }