serde_yaml/value/index.rs
1use crate::mapping::Entry;
2use crate::{mapping, private, Mapping, Value};
3use std::fmt::{self, Debug};
4use 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`.
11pub trait Index: private::Sealed {
12 /// Return None if the key is not already in the sequence or object.
13 #[doc(hidden)]
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)]
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)]
25 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
26}
27
28impl Index for usize {
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 }
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 }
43 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
66fn index_into_mapping<'v, I>(index: &I, v: &'v Value) -> Option<&'v Value>
67where
68 I: ?Sized + mapping::Index,
69{
70 match v.untag_ref() {
71 Value::Mapping(map) => map.get(index),
72 _ => None,
73 }
74}
75
76fn index_into_mut_mapping<'v, I>(index: &I, v: &'v mut Value) -> Option<&'v mut Value>
77where
78 I: ?Sized + mapping::Index,
79{
80 match v.untag_mut() {
81 Value::Mapping(map) => map.get_mut(index),
82 _ => None,
83 }
84}
85
86fn index_or_insert_mapping<'v, I>(index: &I, mut v: &'v mut Value) -> &'v mut Value
87where
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
112impl Index for Value {
113 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
114 index_into_mapping(self, v)
115 }
116 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
117 index_into_mut_mapping(self, v)
118 }
119 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
120 index_or_insert_mapping(self, v)
121 }
122}
123
124impl Index for str {
125 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
126 index_into_mapping(self, v)
127 }
128 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
129 index_into_mut_mapping(self, v)
130 }
131 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
132 index_or_insert_mapping(self, v)
133 }
134}
135
136impl Index for String {
137 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
138 self.as_str().index_into(v)
139 }
140 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
141 self.as_str().index_into_mut(v)
142 }
143 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
144 self.as_str().index_or_insert(v)
145 }
146}
147
148impl<'a, T> Index for &'a T
149where
150 T: ?Sized + Index,
151{
152 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
153 (**self).index_into(v)
154 }
155 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
156 (**self).index_into_mut(v)
157 }
158 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.
164struct Type<'a>(&'a Value);
165
166impl<'a> fmt::Display for Type<'a> {
167 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.
199impl<I> ops::Index<I> for Value
200where
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 /// ```
232 fn index(&self, index: I) -> &Value {
233 static NULL: Value = Value::Null;
234 index.index_into(self).unwrap_or(&NULL)
235 }
236}
237
238impl<I> ops::IndexMut<I> for Value
239where
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 /// ```
276 fn index_mut(&mut self, index: I) -> &mut Value {
277 index.index_or_insert(self)
278 }
279}