serde_yaml/value/
index.rs

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