1 use crate::mapping::Entry;
2 use crate::{mapping, private, Mapping, Value};
3 use std::fmt::{self, Debug};
4 use std::ops;
5 
6 /// A type that can be used to index into a `serde_yaml::Value`. See the `get`
7 /// and `get_mut` methods of `Value`.
8 ///
9 /// This trait is sealed and cannot be implemented for types outside of
10 /// `serde_yaml`.
11 pub trait Index: private::Sealed {
12     /// Return None if the key is not already in the sequence or object.
13     #[doc(hidden)]
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>14     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
15 
16     /// Return None if the key is not already in the sequence or object.
17     #[doc(hidden)]
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>18     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
19 
20     /// Panic if sequence index out of bounds. If key is not already in the object,
21     /// insert it with a value of null. Panic if Value is a type that cannot be
22     /// indexed into, except if Value is null then it can be treated as an empty
23     /// object.
24     #[doc(hidden)]
index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value25     fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
26 }
27 
28 impl Index for usize {
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>29     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
30         match v.untag_ref() {
31             Value::Sequence(vec) => vec.get(*self),
32             Value::Mapping(vec) => vec.get(&Value::Number((*self).into())),
33             _ => None,
34         }
35     }
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>36     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
37         match v.untag_mut() {
38             Value::Sequence(vec) => vec.get_mut(*self),
39             Value::Mapping(vec) => vec.get_mut(&Value::Number((*self).into())),
40             _ => None,
41         }
42     }
index_or_insert<'v>(&self, mut v: &'v mut Value) -> &'v mut Value43     fn index_or_insert<'v>(&self, mut v: &'v mut Value) -> &'v mut Value {
44         loop {
45             match v {
46                 Value::Sequence(vec) => {
47                     let len = vec.len();
48                     return vec.get_mut(*self).unwrap_or_else(|| {
49                         panic!(
50                             "cannot access index {} of YAML sequence of length {}",
51                             self, len
52                         )
53                     });
54                 }
55                 Value::Mapping(map) => {
56                     let n = Value::Number((*self).into());
57                     return map.entry(n).or_insert(Value::Null);
58                 }
59                 Value::Tagged(tagged) => v = &mut tagged.value,
60                 _ => panic!("cannot access index {} of YAML {}", self, Type(v)),
61             }
62         }
63     }
64 }
65 
index_into_mapping<'v, I>(index: &I, v: &'v Value) -> Option<&'v Value> where I: ?Sized + mapping::Index,66 fn index_into_mapping<'v, I>(index: &I, v: &'v Value) -> Option<&'v Value>
67 where
68     I: ?Sized + mapping::Index,
69 {
70     match v.untag_ref() {
71         Value::Mapping(map) => map.get(index),
72         _ => None,
73     }
74 }
75 
index_into_mut_mapping<'v, I>(index: &I, v: &'v mut Value) -> Option<&'v mut Value> where I: ?Sized + mapping::Index,76 fn index_into_mut_mapping<'v, I>(index: &I, v: &'v mut Value) -> Option<&'v mut Value>
77 where
78     I: ?Sized + mapping::Index,
79 {
80     match v.untag_mut() {
81         Value::Mapping(map) => map.get_mut(index),
82         _ => None,
83     }
84 }
85 
index_or_insert_mapping<'v, I>(index: &I, mut v: &'v mut Value) -> &'v mut Value where I: ?Sized + mapping::Index + ToOwned + Debug, Value: From<I::Owned>,86 fn index_or_insert_mapping<'v, I>(index: &I, mut v: &'v mut Value) -> &'v mut Value
87 where
88     I: ?Sized + mapping::Index + ToOwned + Debug,
89     Value: From<I::Owned>,
90 {
91     if let Value::Null = *v {
92         *v = Value::Mapping(Mapping::new());
93         return match v {
94             Value::Mapping(map) => match map.entry(index.to_owned().into()) {
95                 Entry::Vacant(entry) => entry.insert(Value::Null),
96                 Entry::Occupied(_) => unreachable!(),
97             },
98             _ => unreachable!(),
99         };
100     }
101     loop {
102         match v {
103             Value::Mapping(map) => {
104                 return map.entry(index.to_owned().into()).or_insert(Value::Null);
105             }
106             Value::Tagged(tagged) => v = &mut tagged.value,
107             _ => panic!("cannot access key {:?} in YAML {}", index, Type(v)),
108         }
109     }
110 }
111 
112 impl Index for Value {
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>113     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
114         index_into_mapping(self, v)
115     }
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>116     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
117         index_into_mut_mapping(self, v)
118     }
index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value119     fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
120         index_or_insert_mapping(self, v)
121     }
122 }
123 
124 impl Index for str {
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>125     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
126         index_into_mapping(self, v)
127     }
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>128     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
129         index_into_mut_mapping(self, v)
130     }
index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value131     fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
132         index_or_insert_mapping(self, v)
133     }
134 }
135 
136 impl Index for String {
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>137     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
138         self.as_str().index_into(v)
139     }
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>140     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
141         self.as_str().index_into_mut(v)
142     }
index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value143     fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
144         self.as_str().index_or_insert(v)
145     }
146 }
147 
148 impl<'a, T> Index for &'a T
149 where
150     T: ?Sized + Index,
151 {
index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>152     fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
153         (**self).index_into(v)
154     }
index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>155     fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
156         (**self).index_into_mut(v)
157     }
index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value158     fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
159         (**self).index_or_insert(v)
160     }
161 }
162 
163 /// Used in panic messages.
164 struct Type<'a>(&'a Value);
165 
166 impl<'a> fmt::Display for Type<'a> {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result167     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
168         match self.0 {
169             Value::Null => formatter.write_str("null"),
170             Value::Bool(_) => formatter.write_str("boolean"),
171             Value::Number(_) => formatter.write_str("number"),
172             Value::String(_) => formatter.write_str("string"),
173             Value::Sequence(_) => formatter.write_str("sequence"),
174             Value::Mapping(_) => formatter.write_str("mapping"),
175             Value::Tagged(_) => unreachable!(),
176         }
177     }
178 }
179 
180 // The usual semantics of Index is to panic on invalid indexing.
181 //
182 // That said, the usual semantics are for things like `Vec` and `BTreeMap` which
183 // have different use cases than Value. If you are working with a Vec, you know
184 // that you are working with a Vec and you can get the len of the Vec and make
185 // sure your indices are within bounds. The Value use cases are more
186 // loosey-goosey. You got some YAML from an endpoint and you want to pull values
187 // out of it. Outside of this Index impl, you already have the option of using
188 // `value.as_sequence()` and working with the Vec directly, or matching on
189 // `Value::Sequence` and getting the Vec directly. The Index impl means you can
190 // skip that and index directly into the thing using a concise syntax. You don't
191 // have to check the type, you don't have to check the len, it is all about what
192 // you expect the Value to look like.
193 //
194 // Basically the use cases that would be well served by panicking here are
195 // better served by using one of the other approaches: `get` and `get_mut`,
196 // `as_sequence`, or match. The value of this impl is that it adds a way of
197 // working with Value that is not well served by the existing approaches:
198 // concise and careless and sometimes that is exactly what you want.
199 impl<I> ops::Index<I> for Value
200 where
201     I: Index,
202 {
203     type Output = Value;
204 
205     /// Index into a `serde_yaml::Value` using the syntax `value[0]` or
206     /// `value["k"]`.
207     ///
208     /// Returns `Value::Null` if the type of `self` does not match the type of
209     /// the index, for example if the index is a string and `self` is a sequence
210     /// or a number. Also returns `Value::Null` if the given key does not exist
211     /// in the map or the given index is not within the bounds of the sequence.
212     ///
213     /// For retrieving deeply nested values, you should have a look at the
214     /// `Value::pointer` method.
215     ///
216     /// # Examples
217     ///
218     /// ```
219     /// # use serde_yaml::Value;
220     /// #
221     /// # fn main() -> serde_yaml::Result<()> {
222     /// let data: serde_yaml::Value = serde_yaml::from_str(r#"{ x: { y: [z, zz] } }"#)?;
223     ///
224     /// assert_eq!(data["x"]["y"], serde_yaml::from_str::<Value>(r#"["z", "zz"]"#).unwrap());
225     /// assert_eq!(data["x"]["y"][0], serde_yaml::from_str::<Value>(r#""z""#).unwrap());
226     ///
227     /// assert_eq!(data["a"], serde_yaml::from_str::<Value>(r#"null"#).unwrap()); // returns null for undefined values
228     /// assert_eq!(data["a"]["b"], serde_yaml::from_str::<Value>(r#"null"#).unwrap()); // does not panic
229     /// # Ok(())
230     /// # }
231     /// ```
index(&self, index: I) -> &Value232     fn index(&self, index: I) -> &Value {
233         static NULL: Value = Value::Null;
234         index.index_into(self).unwrap_or(&NULL)
235     }
236 }
237 
238 impl<I> ops::IndexMut<I> for Value
239 where
240     I: Index,
241 {
242     /// Write into a `serde_yaml::Value` using the syntax `value[0] = ...` or
243     /// `value["k"] = ...`.
244     ///
245     /// If the index is a number, the value must be a sequence of length bigger
246     /// than the index. Indexing into a value that is not a sequence or a
247     /// sequence that is too small will panic.
248     ///
249     /// If the index is a string, the value must be an object or null which is
250     /// treated like an empty object. If the key is not already present in the
251     /// object, it will be inserted with a value of null. Indexing into a value
252     /// that is neither an object nor null will panic.
253     ///
254     /// # Examples
255     ///
256     /// ```
257     /// # fn main() -> serde_yaml::Result<()> {
258     /// let mut data: serde_yaml::Value = serde_yaml::from_str(r#"{x: 0}"#)?;
259     ///
260     /// // replace an existing key
261     /// data["x"] = serde_yaml::from_str(r#"1"#)?;
262     ///
263     /// // insert a new key
264     /// data["y"] = serde_yaml::from_str(r#"[false, false, false]"#)?;
265     ///
266     /// // replace a value in a sequence
267     /// data["y"][0] = serde_yaml::from_str(r#"true"#)?;
268     ///
269     /// // inserted a deeply nested key
270     /// data["a"]["b"]["c"]["d"] = serde_yaml::from_str(r#"true"#)?;
271     ///
272     /// println!("{:?}", data);
273     /// # Ok(())
274     /// # }
275     /// ```
index_mut(&mut self, index: I) -> &mut Value276     fn index_mut(&mut self, index: I) -> &mut Value {
277         index.index_or_insert(self)
278     }
279 }
280