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
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use crate::json::JsValue;

use crate::query::Path;
use crate::query::PathComponent;
use crate::query::Query;

impl<'v> Query<'v> for JsValue {
    type Item = Self;
    type ItemRef = &'v Self::Item;

    fn lookup<'p, P>(&'v self, path: P) -> Option<Self::ItemRef>
    where
        P: Path<'p>,
    {
        lookup(self, path.path())
    }

    fn take<'p, P>(self, path: P) -> (Option<Self>, Option<Self::Item>)
    where
        P: Path<'p>,
    {
        take(self, path.path())
    }

    fn insert<'p, P>(&mut self, path: P, insertee: Self::Item) -> Result<(), Self::Item>
    where
        P: Path<'p>,
    {
        insert(self, path.path(), insertee)
    }
}

fn lookup<'v, 'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
    v: &'v JsValue,
    mut components: I,
) -> Option<&'v JsValue> {
    if let Some(component) = components.next() {
        match *v {
            JsValue::Object(ref fields) => fields
                .get(component.as_str_slice())
                .and_then(move |child| lookup(child, components)),
            _ => None,
        }
    } else {
        Some(v)
    }
}

fn take<'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
    v: JsValue,
    mut components: I,
) -> (Option<JsValue>, Option<JsValue>) {
    if let Some(component) = components.next() {
        match v {
            JsValue::Object(mut fields) => {
                let child_key = component.as_str_slice();
                if let Some(child) = fields.remove(child_key) {
                    let (child_opt, taken_opt) = take(child, components);
                    
                    if let Some(child) = child_opt {
                        fields.insert(child_key.to_owned(), child);
                    };

                    if fields.is_empty() {
                        (None, taken_opt)
                    } else {
                        (Some(JsValue::Object(fields)), taken_opt)
                    }
                } else {
                    (Some(JsValue::Object(fields)), None)
                }
            }
            as_is => (Some(as_is), None),
        }
    } else {
        (None, Some(v))
    }
}

fn insert<'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
    v: &mut JsValue,
    mut components: I,
    insertee: JsValue,
) -> Result<(), JsValue> {
    if let Some(component) = components.next() {
        match *v {
            JsValue::Object(ref mut fields) => {
                let child_key = component.as_str_slice();

                if let Some(ref mut child) = fields.get_mut(child_key) {
                    insert(child, components, insertee)
                } else {
                    let mut child = json!({});

                    let () = insert(&mut child, components, insertee)
                        .expect("Failed to insert into a newly created ObjectNode");

                    fields.insert(child_key.to_owned(), child);
                    Ok(())
                }
            }
            _ => Err(insertee),
        }
    } else {
        *v = insertee;
        Ok(())
    }
}