blob: df0187fc75db64b370684e3d7e88e315bc1852e8 [file] [log] [blame]
/// The Toml Read extensions
use toml::Value;
use tokenizer::tokenize_with_seperator;
use error::*;
pub trait TomlValueReadExt<'doc> {
/// Extension function for reading a value from the current toml::Value document
/// using a custom seperator
fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;
/// Extension function for reading a value from the current toml::Value document mutably
/// using a custom seperator
fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>>;
/// Extension function for reading a value from the current toml::Value document
fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
self.read_with_seperator(query, '.')
}
/// Extension function for reading a value from the current toml::Value document mutably
fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
self.read_mut_with_seperator(query, '.')
}
}
impl<'doc> TomlValueReadExt<'doc> for Value {
fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
use resolver::non_mut_resolver::resolve;
tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
}
fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>> {
use resolver::mut_resolver::resolve;
tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
}
}
pub trait TomlValueReadTypeExt<'doc> : TomlValueReadExt<'doc> {
fn read_string(&'doc self, query: &str) -> Result<Option<String>>;
fn read_int(&'doc self, query: &str) -> Result<Option<i64>>;
fn read_float(&'doc self, query: &str) -> Result<Option<f64>>;
fn read_bool(&'doc self, query: &str) -> Result<Option<bool>>;
}
macro_rules! make_type_getter {
($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
fn $fnname(&'doc self, query: &str) -> Result<Option<$rettype>> {
self.read_with_seperator(query, '.').and_then(|o| match o {
$matcher => Ok(Some($implementation)),
Some(o) => Err(ErrorKind::TypeError($typename, ::util::name_of_val(&o)).into()),
None => Ok(None),
})
}
};
}
impl<'doc, T> TomlValueReadTypeExt<'doc> for T
where T: TomlValueReadExt<'doc>
{
make_type_getter!(read_string, String, "String", Some(&Value::String(ref obj)) => obj.clone());
make_type_getter!(read_int, i64, "Integer", Some(&Value::Integer(obj)) => obj);
make_type_getter!(read_float, f64, "Float", Some(&Value::Float(obj)) => obj);
make_type_getter!(read_bool, bool, "Boolean", Some(&Value::Boolean(obj)) => obj);
}
#[cfg(test)]
mod test {
use super::*;
use toml::from_str as toml_from_str;
#[test]
fn test_read_empty() {
let toml : Value = toml_from_str("").unwrap();
let val = toml.read_with_seperator(&String::from("a"), '.');
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_none());
}
#[test]
fn test_read_table() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read_with_seperator(&String::from("table"), '.');
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_some());
let val = val.unwrap();
assert!(is_match!(val, &Value::Table(_)));
match val {
&Value::Table(ref t) => assert!(t.is_empty()),
_ => panic!("What just happened?"),
}
}
#[test]
fn test_read_table_value() {
let toml : Value = toml_from_str(r#"
[table]
a = 1
"#).unwrap();
let val = toml.read_with_seperator(&String::from("table.a"), '.');
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_some());
let val = val.unwrap();
assert!(is_match!(val, &Value::Integer(1)));
}
#[test]
fn test_read_empty_table_value() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read_with_seperator(&String::from("table.a"), '.');
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_none());
}
#[test]
fn test_read_table_index() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read_with_seperator(&String::from("table.[0]"), '.');
assert!(val.is_err());
let err = val.unwrap_err();
assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
}
///
///
/// Querying without specifying the seperator
///
///
#[test]
fn test_read_empty_without_seperator() {
let toml : Value = toml_from_str("").unwrap();
let val = toml.read(&String::from("a"));
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_none());
}
#[test]
fn test_read_table_without_seperator() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read(&String::from("table"));
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_some());
let val = val.unwrap();
assert!(is_match!(val, &Value::Table(_)));
match val {
&Value::Table(ref t) => assert!(t.is_empty()),
_ => panic!("What just happened?"),
}
}
#[test]
fn test_read_table_value_without_seperator() {
let toml : Value = toml_from_str(r#"
[table]
a = 1
"#).unwrap();
let val = toml.read(&String::from("table.a"));
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_some());
let val = val.unwrap();
assert!(is_match!(val, &Value::Integer(1)));
}
#[test]
fn test_read_empty_table_value_without_seperator() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read(&String::from("table.a"));
assert!(val.is_ok());
let val = val.unwrap();
assert!(val.is_none());
}
#[test]
fn test_read_table_index_without_seperator() {
let toml : Value = toml_from_str(r#"
[table]
"#).unwrap();
let val = toml.read(&String::from("table.[0]"));
assert!(val.is_err());
let err = val.unwrap_err();
assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
}
}
#[cfg(test)]
mod high_level_fn_test {
use super::*;
use toml::from_str as toml_from_str;
#[test]
fn test_read_table_value() {
let toml : Value = toml_from_str(r#"
[table]
a = 1
"#).unwrap();
let val = toml.read_int("table.a").unwrap();
assert_eq!(val.unwrap(), 1);
}
}