1use super::Value;
2use core::fmt::{self, Display};
3use core::ops;
4use std::collections::HashMap;
5
6pub trait Index: private::Sealed {
16 #[doc(hidden)]
23 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
24
25 #[doc(hidden)]
32 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
33
34 #[doc(hidden)]
43 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
44}
45
46impl Index for usize {
47 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
48 match v {
49 Value::Array(vec) => vec.get(*self),
50 _ => None,
51 }
52 }
53 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
54 match v {
55 Value::Array(vec) => vec.get_mut(*self),
56 _ => None,
57 }
58 }
59 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
60 match v {
61 Value::Array(vec) => {
62 let len = vec.len();
63 vec.get_mut(*self).unwrap_or_else(|| {
64 panic!(
65 "cannot access index {} of HOCON array of length {}",
66 self, len
67 )
68 })
69 }
70 _ => panic!("cannot access index {} of HOCON {}", self, Type(v)),
71 }
72 }
73}
74
75impl Index for str {
76 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
77 match v {
78 Value::Object(map) => map.get(self),
79 _ => None,
80 }
81 }
82 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
83 match v {
84 Value::Object(map) => map.get_mut(self),
85 _ => None,
86 }
87 }
88 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
89 if let Value::Null = v {
90 *v = Value::Object(HashMap::new());
91 }
92 match v {
93 Value::Object(map) => map.entry(self.to_owned()).or_insert(Value::Null),
94 _ => panic!("cannot access key {:?} in HOCON {}", self, Type(v)),
95 }
96 }
97}
98
99impl Index for String {
100 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
101 self[..].index_into(v)
102 }
103 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
104 self[..].index_into_mut(v)
105 }
106 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
107 self[..].index_or_insert(v)
108 }
109}
110
111impl<T> Index for &T
112where
113 T: ?Sized + Index,
114{
115 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
116 (**self).index_into(v)
117 }
118 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
119 (**self).index_into_mut(v)
120 }
121 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
122 (**self).index_or_insert(v)
123 }
124}
125
126mod private {
128 pub trait Sealed {}
129 impl Sealed for usize {}
130 impl Sealed for str {}
131 impl Sealed for String {}
132 impl<T> Sealed for &T where T: ?Sized + Sealed {}
133}
134
135struct Type<'a>(&'a Value);
137
138impl<'a> Display for Type<'a> {
139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 match *self.0 {
141 Value::Null => f.write_str("null"),
142 Value::Boolean(_) => f.write_str("boolean"),
143 Value::Number(_) => f.write_str("number"),
144 Value::String(_) => f.write_str("string"),
145 Value::Array(_) => f.write_str("array"),
146 Value::Object(_) => f.write_str("object"),
147 }
148 }
149}
150
151impl<I> ops::Index<I> for Value
152where
153 I: Index,
154{
155 type Output = Value;
156
157 fn index(&self, index: I) -> &Value {
162 static NULL: Value = Value::Null;
163 index.index_into(self).unwrap_or(&NULL)
164 }
165}
166
167impl<I> ops::IndexMut<I> for Value
168where
169 I: Index,
170{
171 fn index_mut(&mut self, index: I) -> &mut Value {
177 index.index_or_insert(self)
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use crate::Config;
185 use std::collections::HashMap;
186
187 const CONFIG: &str = r#"
188a = {
189 b = [
190 1.0,
191 {
192 c = [
193 {mikai = 233}
194 ],
195 d = "hello",
196 },
197 ]
198 }
199 "#;
200
201 fn make_test_value() -> Value {
202 Config::parse_str(CONFIG, None).unwrap()
203 }
204
205 #[test]
206 fn test_index_str_valid_and_invalid() {
207 let value = make_test_value();
208
209 assert_eq!(
211 value["a"]["b"][0],
212 Value::Number(serde_json::Number::from_f64(1.0).unwrap())
213 );
214 assert_eq!(value["a"]["b"][1]["d"], Value::String("hello".into()));
215 assert_eq!(
216 value["a"]["b"][1]["c"][0]["mikai"],
217 Value::Number(233.into())
218 );
219
220 assert_eq!(value["a"]["b"][1]["no_such_key"], Value::Null);
222
223 assert_eq!(value["a"]["b"][0]["not_object"], Value::Null);
225 }
226
227 #[test]
228 fn test_index_usize_valid_and_invalid() {
229 let value = make_test_value();
230
231 assert_eq!(value["a"]["b"][10], Value::Null);
233
234 assert_eq!(value["a"]["b"][1]["d"][0], Value::Null);
236 }
237
238 #[test]
239 #[should_panic(expected = "cannot access index 2 of HOCON array of length 2")]
240 fn test_index_or_insert_usize_out_of_bounds_panics() {
241 let mut value = make_test_value();
242 let _ = &mut value["a"]["b"][2]; }
244
245 #[test]
246 #[should_panic(expected = "cannot access index 0 of HOCON object")]
247 fn test_index_or_insert_usize_on_object_panics() {
248 let mut value = make_test_value();
249 let _ = &mut value["a"][0]; }
251
252 #[test]
253 #[should_panic(expected = "cannot access key")]
254 fn test_index_or_insert_str_on_array_panics() {
255 let mut value = make_test_value();
256 let _ = &mut value["a"]["b"][0]["new_key"]; }
258
259 #[test]
260 fn test_index_or_insert_str_on_null_creates_object() {
261 let mut v = Value::Null;
262 v["hello"] = Value::String("world".into());
263 assert_eq!(v["hello"], Value::String("world".into()));
264 }
265
266 #[test]
267 fn test_index_string_and_reference_equivalence() {
268 let value = make_test_value();
269 let key = "a".to_string();
270 let key_ref: &str = "a";
271
272 assert_eq!(value[&key], value["a"]);
273 assert_eq!(value[&key_ref], value["a"]);
274 }
275
276 #[test]
277 fn test_index_mut_inserts_new_field() {
278 let mut value = Value::Object(HashMap::new());
279 value["new_field"] = Value::String("hi".into());
280 assert_eq!(value["new_field"], Value::String("hi".into()));
281 }
282
283 #[test]
284 fn test_type_display() {
285 let vals = vec![
286 Value::Null,
287 Value::Boolean(true),
288 Value::Number(serde_json::Number::from_f64(3.15).unwrap()),
289 Value::String("abc".into()),
290 Value::Array(vec![]),
291 Value::Object(HashMap::new()),
292 ];
293 let expected = ["null", "boolean", "number", "string", "array", "object"];
294 for (v, exp) in vals.into_iter().zip(expected) {
295 assert_eq!(format!("{}", Type(&v)), exp);
296 }
297 }
298
299 #[test]
300 fn test_usize_index_into_mut_valid_and_invalid() {
301 let mut arr = Value::Array(vec![Value::Number(1.into()), Value::Number(2.into())]);
302 let i = 1usize;
304 assert!(i.index_into_mut(&mut arr).is_some());
305 let mut non_array = Value::String("not array".into());
307 assert!(i.index_into_mut(&mut non_array).is_none());
308 }
309
310 #[test]
311 fn test_str_index_into_mut_valid_and_invalid() {
312 let mut obj = Value::Object(HashMap::from([(
313 "x".to_string(),
314 Value::String("ok".into()),
315 )]));
316 let key = "x";
317 assert!(key.index_into_mut(&mut obj).is_some());
318 let mut non_obj = Value::Array(vec![]);
319 assert!(key.index_into_mut(&mut non_obj).is_none());
320 }
321
322 #[test]
323 fn test_string_index_into_mut_and_index_or_insert() {
324 let mut obj = Value::Object(HashMap::new());
325 let k = "new".to_string();
326 assert!(k.index_into_mut(&mut obj).is_none());
328 k.index_or_insert(&mut obj);
330 assert!(matches!(obj["new"], Value::Null));
331 }
332
333 #[test]
334 fn test_ref_index_into_mut_for_string() {
335 let mut obj = Value::Object(HashMap::from([("k".to_string(), Value::Number(10.into()))]));
336 let k = "k".to_string();
337 let ref_k = &k;
338 let result = ref_k.index_into_mut(&mut obj);
339 assert!(result.is_some());
340 }
341}