diff options
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 132 |
1 files changed, 128 insertions, 4 deletions
diff --git a/src/config.rs b/src/config.rs index 126d31b..6c81244 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use value::Value; use source::{Source, SourceBuilder}; +use path; use std::error::Error; use std::fmt; @@ -213,8 +214,55 @@ impl Config { Ok(()) } - pub fn get<'a>(&'a self, key: &str) -> Option<&'a Value> { - self.cache.get(key) + // Child ( Child ( Identifier( "x" ), "y" ), "z" ) + fn path_get<'a, 'b>(&'a self, expr: path::Expression) -> Option<&'a Value> { + match expr { + path::Expression::Identifier(text) => { + self.cache.get(&text) + } + + path::Expression::Child(expr, member) => { + match self.path_get(*expr) { + Some(&Value::Table(ref table)) => { + table.get(&member) + } + + _ => None + } + } + + path::Expression::Subscript(expr, mut index) => { + match self.path_get(*expr) { + Some(&Value::Array(ref array)) => { + let len = array.len() as i32; + + if index < 0 { + index = len + index; + } + + if index < 0 || index >= len { + None + } else { + Some(&array[index as usize]) + } + } + + _ => None + } + } + } + } + + pub fn get<'a>(&'a self, key_path: &str) -> Option<&'a Value> { + let key_expr: path::Expression = match key_path.parse() { + Ok(expr) => expr, + Err(_) => { + // TODO: Log warning here + return None; + } + }; + + self.path_get(key_expr) } pub fn get_str<'a>(&'a self, key: &str) -> Option<Cow<'a, str>> { @@ -236,6 +284,10 @@ impl Config { pub fn get_map<'a>(&'a self, key: &str) -> Option<&'a HashMap<String, Value>> { self.get(key).and_then(Value::as_map) } + + pub fn get_slice<'a>(&'a self, key: &str) -> Option<&'a [Value]> { + self.get(key).and_then(Value::as_slice) + } } #[cfg(test)] @@ -392,9 +444,41 @@ mod test { assert_eq!(c.get_bool("key_11"), None); } - // Deep merge of tables #[test] - fn test_merge() { + fn test_slice() { + let mut c = Config::new(); + + c.set("values", vec![ + Value::Integer(10), + Value::Integer(325), + Value::Integer(12), + ]).unwrap(); + + let values = c.get_slice("values").unwrap(); + + assert_eq!(values.len(), 3); + assert_eq!(values[1].as_int(), Some(325)); + } + + #[test] + fn test_slice_into() { + let mut c = Config::new(); + + c.set("values", vec![ + 10, + 325, + 12, + ]).unwrap(); + + let values = c.get_slice("values").unwrap(); + + assert_eq!(values.len(), 3); + assert_eq!(values[1].as_int(), Some(325)); + + } + + #[test] + fn test_map() { let mut c = Config::new(); { @@ -428,4 +512,44 @@ mod test { assert_eq!(m.get("db").unwrap().as_str().unwrap(), "1"); } } + + #[test] + fn test_path() { + use file::{File, FileFormat}; + + let mut c = Config::new(); + + c.merge(File::from_str(r#" + [redis] + address = "localhost:6379" + + [[databases]] + name = "test_db" + options = { trace = true } + "#, FileFormat::Toml)).unwrap(); + + assert_eq!(c.get_str("redis.address").unwrap(), "localhost:6379"); + assert_eq!(c.get_str("databases[0].name").unwrap(), "test_db"); + assert_eq!(c.get_str("databases[0].options.trace").unwrap(), "true"); + } + + #[test] + fn test_map_into() { + let mut c = Config::new(); + + { + let mut m = HashMap::new(); + m.insert("port".into(), 6379); + m.insert("db".into(), 2); + + c.set("redis", m).unwrap(); + } + + { + let m = c.get_map("redis").unwrap(); + + assert_eq!(m.get("port").unwrap().as_int().unwrap(), 6379); + assert_eq!(m.get("db").unwrap().as_int().unwrap(), 2); + } + } } |