1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use {
    super::{Value, ValueError},
    crate::result::Result,
    std::{
        collections::HashMap,
        ops::ControlFlow::{Break, Continue},
    },
};

enum Selectable<'a> {
    Map(&'a HashMap<String, Value>),
    List(&'a Vec<Value>),
    Other(&'a Value),
}

impl Value {
    pub fn selector(&self, selector: &str) -> Result<Value> {
        let selectable = match self {
            Value::Map(v) => Selectable::Map(v),
            Value::List(v) => Selectable::List(v),
            _ => return Err(ValueError::SelectorRequiresMapOrListTypes.into()),
        };

        let result = selector.split('.').try_fold(selectable, |selectable, key| {
            let value = match selectable {
                Selectable::Map(map) => map.get(key),
                Selectable::List(list) => key.parse::<usize>().ok().and_then(|i| list.get(i)),
                Selectable::Other(_) => return Break(()),
            };

            match value {
                Some(Value::Map(map)) => Continue(Selectable::Map(map)),
                Some(Value::List(list)) => Continue(Selectable::List(list)),
                Some(value) => Continue(Selectable::Other(value)),
                None => Break(()),
            }
        });

        let value = match result {
            Continue(Selectable::Map(map)) => Value::Map(map.clone()),
            Continue(Selectable::List(list)) => Value::List(list.clone()),
            Continue(Selectable::Other(value)) => value.clone(),
            Break(_) => Value::Null,
        };

        Ok(value)
    }
}