imbl_value/
index.rs

1use std::fmt::{self, Display};
2
3use yasi::InternedString;
4
5use crate::{InOMap, Value};
6
7/// Used in panic messages.
8struct Type<'a>(&'a Value);
9
10impl<'a> Display for Type<'a> {
11    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
12        match *self.0 {
13            Value::Null => formatter.write_str("null"),
14            Value::Bool(_) => formatter.write_str("boolean"),
15            Value::Number(_) => formatter.write_str("number"),
16            Value::String(_) => formatter.write_str("string"),
17            Value::Array(_) => formatter.write_str("array"),
18            Value::Object(_) => formatter.write_str("object"),
19        }
20    }
21}
22pub trait Index {
23    /// Return None if the key is not already in the array or object.
24    #[doc(hidden)]
25    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
26
27    /// Return None if the key is not already in the array or object.
28    #[doc(hidden)]
29    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
30
31    /// Return None if the key is not already in the array or object.
32    #[doc(hidden)]
33    fn index_into_owned(&self, v: Value) -> Option<Value>;
34
35    /// Panic if array index out of bounds. If key is not already in the object,
36    /// insert it with a value of null. Panic if Value is a type that cannot be
37    /// indexed into, except if Value is null then it can be treated as an empty
38    /// object.
39    #[doc(hidden)]
40    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
41}
42
43impl Index for usize {
44    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
45        match v {
46            Value::Array(vec) => vec.get(*self),
47            _ => None,
48        }
49    }
50    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
51        match v {
52            Value::Array(vec) => vec.get_mut(*self),
53            _ => None,
54        }
55    }
56    fn index_into_owned(&self, v: Value) -> Option<Value> {
57        match v {
58            Value::Array(mut vec) => {
59                if vec.len() > *self {
60                    Some(vec.remove(*self))
61                } else {
62                    None
63                }
64            }
65            _ => None,
66        }
67    }
68    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
69        match v {
70            Value::Array(vec) => {
71                let len = vec.len();
72                vec.get_mut(*self).unwrap_or_else(|| {
73                    panic!(
74                        "cannot access index {} of JSON array of length {}",
75                        self, len
76                    )
77                })
78            }
79            _ => panic!("cannot access index {} of JSON {}", self, Type(v)),
80        }
81    }
82}
83
84impl Index for str {
85    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
86        match v {
87            Value::Object(map) => map.get(self),
88            _ => None,
89        }
90    }
91    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
92        match v {
93            Value::Object(map) => map.get_mut(self),
94            _ => None,
95        }
96    }
97    fn index_into_owned(&self, v: Value) -> Option<Value> {
98        match v {
99            Value::Object(mut map) => map.remove(self),
100            _ => None,
101        }
102    }
103    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
104        if let Value::Null = v {
105            *v = Value::Object(InOMap::new());
106        }
107        match v {
108            Value::Object(map) => map
109                .entry(InternedString::intern(self))
110                .or_insert(Value::Null),
111            _ => panic!("cannot access key {:?} in JSON {}", self, Type(v)),
112        }
113    }
114}
115
116impl Index for String {
117    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
118        self[..].index_into(v)
119    }
120    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
121        self[..].index_into_mut(v)
122    }
123    fn index_into_owned(&self, v: Value) -> Option<Value> {
124        self[..].index_into_owned(v)
125    }
126    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
127        self[..].index_or_insert(v)
128    }
129}
130
131impl<'a, T> Index for &'a T
132where
133    T: ?Sized + Index,
134{
135    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
136        (**self).index_into(v)
137    }
138    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
139        (**self).index_into_mut(v)
140    }
141    fn index_into_owned(&self, v: Value) -> Option<Value> {
142        (**self).index_into_owned(v)
143    }
144    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
145        (**self).index_or_insert(v)
146    }
147}
148
149impl<I> std::ops::Index<I> for Value
150where
151    I: Index,
152{
153    type Output = Value;
154
155    /// Index into a `serde_json::Value` using the syntax `value[0]` or
156    /// `value["k"]`.
157    ///
158    /// Returns `Value::Null` if the type of `self` does not match the type of
159    /// the index, for example if the index is a string and `self` is an array
160    /// or a number. Also returns `Value::Null` if the given key does not exist
161    /// in the map or the given index is not within the bounds of the array.
162    ///
163    /// For retrieving deeply nested values, you should have a look at the
164    /// `Value::pointer` method.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use imbl_value::json;
170    ///
171    /// let data = json!({
172    ///     "x": {
173    ///         "y": ["z", "zz"]
174    ///     }
175    /// });
176    ///
177    /// assert_eq!(data["x"]["y"], json!(["z", "zz"]));
178    /// assert_eq!(data["x"]["y"][0], json!("z"));
179    ///
180    /// assert_eq!(data["a"], json!(null)); // returns null for undefined values
181    /// assert_eq!(data["a"]["b"], json!(null)); // does not panic
182    /// ```
183    fn index(&self, index: I) -> &Value {
184        static NULL: Value = Value::Null;
185        index.index_into(self).unwrap_or(&NULL)
186    }
187}
188
189impl<I> std::ops::IndexMut<I> for Value
190where
191    I: Index,
192{
193    /// Write into a `serde_json::Value` using the syntax `value[0] = ...` or
194    /// `value["k"] = ...`.
195    ///
196    /// If the index is a number, the value must be an array of length bigger
197    /// than the index. Indexing into a value that is not an array or an array
198    /// that is too small will panic.
199    ///
200    /// If the index is a string, the value must be an object or null which is
201    /// treated like an empty object. If the key is not already present in the
202    /// object, it will be inserted with a value of null. Indexing into a value
203    /// that is neither an object nor null will panic.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// use imbl_value::json;
209    ///
210    /// let mut data = json!({ "x": 0 });
211    ///
212    /// // replace an existing key
213    /// data["x"] = json!(1);
214    ///
215    /// // insert a new key
216    /// data["y"] = json!([false, false, false]);
217    ///
218    /// // replace an array value
219    /// data["y"][0] = json!(true);
220    ///
221    /// // inserted a deeply nested key
222    /// data["a"]["b"]["c"]["d"] = json!(true);
223    ///
224    /// println!("{}", data);
225    /// ```
226    fn index_mut(&mut self, index: I) -> &mut Value {
227        index.index_or_insert(self)
228    }
229}