humphrey_json/
indexing.rs

1//! Provides functionality for indexing into JSON values.
2
3use crate::Value;
4
5use std::ops;
6
7/// Represents the ability of a type to be used as an index into a JSON value.
8pub trait Index {
9    /// Indexes into a JSON value, returning a shared reference to the value if found.
10    fn json_index<'v>(&self, v: &'v Value) -> Option<&'v Value>;
11    /// Indexes into a JSON value, returning a mutable reference to the value if found.
12    fn json_index_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
13}
14
15impl Index for usize {
16    fn json_index<'v>(&self, v: &'v Value) -> Option<&'v Value> {
17        match v {
18            Value::Array(a) => a.get(*self),
19            _ => None,
20        }
21    }
22
23    fn json_index_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
24        match v {
25            Value::Array(a) => a.get_mut(*self),
26            _ => None,
27        }
28    }
29}
30
31impl Index for &str {
32    fn json_index<'v>(&self, v: &'v Value) -> Option<&'v Value> {
33        match v {
34            Value::Object(o) => o.iter().find(|(k, _)| k == self).map(|(_, v)| v),
35            _ => None,
36        }
37    }
38
39    fn json_index_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
40        match v {
41            Value::Object(o) => {
42                if let Some(i) = o.iter().position(|(k, _)| k == self) {
43                    Some(&mut o[i].1)
44                } else {
45                    o.push((self.to_string(), Value::Null));
46                    o.last_mut().map(|(_, v)| v)
47                }
48            }
49            _ => None,
50        }
51    }
52}
53
54impl Index for String {
55    fn json_index<'v>(&self, v: &'v Value) -> Option<&'v Value> {
56        self.as_str().json_index(v)
57    }
58
59    fn json_index_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
60        self.as_str().json_index_mut(v)
61    }
62}
63
64impl<T> ops::Index<T> for Value
65where
66    T: Index,
67{
68    type Output = Value;
69
70    fn index(&self, index: T) -> &Self::Output {
71        index.json_index(self).unwrap_or(&Value::Null)
72    }
73}
74
75impl<T> ops::IndexMut<T> for Value
76where
77    T: Index,
78{
79    fn index_mut(&mut self, index: T) -> &mut Self::Output {
80        index
81            .json_index_mut(self)
82            .expect("Cannot get mutable index")
83    }
84}