#[cfg(feature = "serde_json")]
use serde_json::Value;
#[cfg_attr(
feature = "serde_json",
doc = r##"
# Examples
When the `serde_json` feature is enabled, [`Value`] implements `Dig`:
```
# use digger::Dig;
# use serde_json::{json, Value};
let value = json!({
"foo": {
"bar": {
"baz": "hello there"
}
}
});
let expected = Value::String(String::from("hello there"));
assert_eq!(value.dig("foo.bar.baz"), Some(&expected));
```
[`Value`]: https://docs.serde.rs/serde_json/value/enum.Value.html
"##
)]
pub trait Dig {
fn value_for_name(&self, name: &str) -> Option<&Self>;
fn dig(&self, selector: impl AsRef<str>) -> Option<&Self> {
selector
.as_ref()
.split('.')
.skip_while(|&s| s == "$")
.filter(|&s| !s.is_empty())
.fold(Some(self), |res, name| match res {
Some(d) => d.value_for_name(name),
None => None,
})
}
}
#[cfg(feature = "serde_json")]
impl Dig for Value {
fn value_for_name(&self, name: &str) -> Option<&Self> {
match self {
Value::Object(o) => o.get(name),
_ => None,
}
}
}
#[cfg(test)]
#[cfg(feature = "serde_json")]
mod json_tests {
use serde_json::{json, Value};
use super::Dig;
#[test]
fn not_found_at_end() {
let value = json!({
"foo": {
"bar": {
"baz": true
}
}
});
let result = value.dig("foo.bar.quux");
assert_eq!(None, result);
}
#[test]
fn not_found_at_start() {
let value = json!({
"foo": {
"bar": {
"baz": true
}
}
});
let result = value.dig("rust.bar.baz");
assert_eq!(None, result);
}
#[test]
fn empty_selector_is_identity() {
let value = json!({
"foo": {
"bar": {
"baz": true
}
}
});
let result = value.dig("");
assert_eq!(Some(&value), result);
}
#[test]
fn sigil_alone_is_identity() {
let value = json!({
"foo": {
"bar": {
"baz": true
}
}
});
let result = value.dig("$");
assert_eq!(Some(&value), result);
}
#[test]
fn sigil_prefix_is_ignored() {
let value = json!({
"foo": {
"bar": {
"baz": true
}
}
});
let result = value.dig("$.foo.bar.baz");
let expected = Value::Bool(true);
assert_eq!(Some(&expected), result);
}
}