use std::ops::Deref;
pub fn toml_select_value<S: AsRef<str>, K: Deref<Target = [S]>>(
keys: K,
value: &toml::Value,
) -> Option<&toml::Value> {
if keys.is_empty() {
Some(value)
} else {
match &value {
toml::Value::Table(table) => keys.split_first().and_then(|(head, tail)| {
table
.get(head.as_ref())
.and_then(|next_value| toml_select_value(tail, next_value))
}),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use crate::toml::toml_select_value;
use std::collections::HashMap;
use toml::toml;
#[test]
fn test_common_case() {
let toml = toml! {
[bogus]
value = "Will it trip it up?"
[now]
this = "is podracing!"
};
assert_eq!(
toml_select_value(vec!["now", "this"], &toml),
Some(&toml::Value::from("is podracing!"))
);
}
#[test]
fn test_value_from_dotted_keys() {
let toml = toml! {
now.this.is = "podracing"
[bogus]
value = "Will it trip it up?"
};
assert_eq!(
toml_select_value(vec!["now", "this", "is"], &toml),
Some(&toml::Value::from("podracing"))
);
}
#[test]
fn test_value_from_table() {
let toml = toml! {
[bogus]
value = "Will it trip it up?"
[now.this]
is = "podracing"
};
assert_eq!(
toml_select_value(vec!["now", "this", "is"], &toml),
Some(&toml::Value::from("podracing"))
);
}
#[test]
fn test_partial_match() {
let toml = toml! {
[bogus]
value = "Will it trip it up?"
[now.this]
is = "podracing"
};
assert_eq!(toml_select_value(vec!["now", "this", "was"], &toml), None);
}
#[test]
fn test_does_not_modify_value_types() {
let toml = toml! {
[translations]
leet = 1337
};
assert_eq!(
toml_select_value(vec!["translations", "leet"], &toml),
Some(&toml::Value::from(1337))
);
}
#[test]
fn test_works_without_keys() {
let toml = toml! {
foo = "bar"
};
let mut hash_map = HashMap::new();
hash_map.insert(String::from("foo"), String::from("bar"));
assert_eq!(
toml_select_value::<&str, Vec<&str>>(vec![], &toml),
Some(&toml::Value::from(hash_map))
);
}
}