serde_yaml/value/
mod.rs

1//! The Value enum, a loosely typed way of representing any valid YAML value.
2
3mod de;
4mod debug;
5mod from;
6mod index;
7mod partial_eq;
8mod ser;
9pub(crate) mod tagged;
10
11use crate::error::{self, Error, ErrorImpl};
12use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer};
13use serde::Serialize;
14use std::hash::{Hash, Hasher};
15use std::mem;
16
17pub use self::index::Index;
18pub use self::ser::Serializer;
19pub use self::tagged::{Tag, TaggedValue};
20#[doc(inline)]
21pub use crate::mapping::Mapping;
22pub use crate::number::Number;
23
24/// Represents any valid YAML value.
25#[derive(Clone, PartialEq, PartialOrd)]
26pub enum Value {
27    /// Represents a YAML null value.
28    Null,
29    /// Represents a YAML boolean.
30    Bool(bool),
31    /// Represents a YAML numerical value, whether integer or floating point.
32    Number(Number),
33    /// Represents a YAML string.
34    String(String),
35    /// Represents a YAML sequence in which the elements are
36    /// `serde_yaml::Value`.
37    Sequence(Sequence),
38    /// Represents a YAML mapping in which the keys and values are both
39    /// `serde_yaml::Value`.
40    Mapping(Mapping),
41    /// A representation of YAML's `!Tag` syntax, used for enums.
42    Tagged(Box<TaggedValue>),
43}
44
45/// The default value is `Value::Null`.
46///
47/// This is useful for handling omitted `Value` fields when deserializing.
48///
49/// # Examples
50///
51/// ```
52/// # use serde_derive::Deserialize;
53/// use serde::Deserialize;
54/// use serde_yaml::Value;
55///
56/// #[derive(Deserialize)]
57/// struct Settings {
58///     level: i32,
59///     #[serde(default)]
60///     extras: Value,
61/// }
62///
63/// # fn try_main() -> Result<(), serde_yaml::Error> {
64/// let data = r#" { "level": 42 } "#;
65/// let s: Settings = serde_yaml::from_str(data)?;
66///
67/// assert_eq!(s.level, 42);
68/// assert_eq!(s.extras, Value::Null);
69/// #
70/// #     Ok(())
71/// # }
72/// #
73/// # try_main().unwrap()
74/// ```
75impl Default for Value {
76    fn default() -> Value {
77        Value::Null
78    }
79}
80
81/// A YAML sequence in which the elements are `serde_yaml::Value`.
82pub type Sequence = Vec<Value>;
83
84/// Convert a `T` into `serde_yaml::Value` which is an enum that can represent
85/// any valid YAML data.
86///
87/// This conversion can fail if `T`'s implementation of `Serialize` decides to
88/// return an error.
89///
90/// ```
91/// # use serde_yaml::Value;
92/// let val = serde_yaml::to_value("s").unwrap();
93/// assert_eq!(val, Value::String("s".to_owned()));
94/// ```
95pub fn to_value<T>(value: T) -> Result<Value, Error>
96where
97    T: Serialize,
98{
99    value.serialize(Serializer)
100}
101
102/// Interpret a `serde_yaml::Value` as an instance of type `T`.
103///
104/// This conversion can fail if the structure of the Value does not match the
105/// structure expected by `T`, for example if `T` is a struct type but the Value
106/// contains something other than a YAML map. It can also fail if the structure
107/// is correct but `T`'s implementation of `Deserialize` decides that something
108/// is wrong with the data, for example required struct fields are missing from
109/// the YAML map or some number is too big to fit in the expected primitive
110/// type.
111///
112/// ```
113/// # use serde_yaml::Value;
114/// let val = Value::String("foo".to_owned());
115/// let s: String = serde_yaml::from_value(val).unwrap();
116/// assert_eq!("foo", s);
117/// ```
118pub fn from_value<T>(value: Value) -> Result<T, Error>
119where
120    T: DeserializeOwned,
121{
122    Deserialize::deserialize(value)
123}
124
125impl Value {
126    /// Index into a YAML sequence or map. A string index can be used to access
127    /// a value in a map, and a usize index can be used to access an element of
128    /// an sequence.
129    ///
130    /// Returns `None` if the type of `self` does not match the type of the
131    /// index, for example if the index is a string and `self` is a sequence or
132    /// a number. Also returns `None` if the given key does not exist in the map
133    /// or the given index is not within the bounds of the sequence.
134    ///
135    /// ```
136    /// # fn main() -> serde_yaml::Result<()> {
137    /// use serde_yaml::Value;
138    ///
139    /// let object: Value = serde_yaml::from_str(r#"{ A: 65, B: 66, C: 67 }"#)?;
140    /// let x = object.get("A").unwrap();
141    /// assert_eq!(x, 65);
142    ///
143    /// let sequence: Value = serde_yaml::from_str(r#"[ "A", "B", "C" ]"#)?;
144    /// let x = sequence.get(2).unwrap();
145    /// assert_eq!(x, &Value::String("C".into()));
146    ///
147    /// assert_eq!(sequence.get("A"), None);
148    /// # Ok(())
149    /// # }
150    /// ```
151    ///
152    /// Square brackets can also be used to index into a value in a more concise
153    /// way. This returns `Value::Null` in cases where `get` would have returned
154    /// `None`.
155    ///
156    /// ```
157    /// # use serde_yaml::Value;
158    /// #
159    /// # fn main() -> serde_yaml::Result<()> {
160    /// let object: Value = serde_yaml::from_str(r#"
161    /// A: [a, á, à]
162    /// B: [b, b́]
163    /// C: [c, ć, ć̣, ḉ]
164    /// 42: true
165    /// "#)?;
166    /// assert_eq!(object["B"][0], Value::String("b".into()));
167    ///
168    /// assert_eq!(object[Value::String("D".into())], Value::Null);
169    /// assert_eq!(object["D"], Value::Null);
170    /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null);
171    ///
172    /// assert_eq!(object[42], Value::Bool(true));
173    /// # Ok(())
174    /// # }
175    /// ```
176    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
177        index.index_into(self)
178    }
179
180    /// Index into a YAML sequence or map. A string index can be used to access
181    /// a value in a map, and a usize index can be used to access an element of
182    /// an sequence.
183    ///
184    /// Returns `None` if the type of `self` does not match the type of the
185    /// index, for example if the index is a string and `self` is a sequence or
186    /// a number. Also returns `None` if the given key does not exist in the map
187    /// or the given index is not within the bounds of the sequence.
188    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> {
189        index.index_into_mut(self)
190    }
191
192    /// Returns true if the `Value` is a Null. Returns false otherwise.
193    ///
194    /// For any Value on which `is_null` returns true, `as_null` is guaranteed
195    /// to return `Some(())`.
196    ///
197    /// ```
198    /// # use serde_yaml::Value;
199    /// let v: Value = serde_yaml::from_str("null").unwrap();
200    /// assert!(v.is_null());
201    /// ```
202    ///
203    /// ```
204    /// # use serde_yaml::Value;
205    /// let v: Value = serde_yaml::from_str("false").unwrap();
206    /// assert!(!v.is_null());
207    /// ```
208    pub fn is_null(&self) -> bool {
209        if let Value::Null = self.untag_ref() {
210            true
211        } else {
212            false
213        }
214    }
215
216    /// If the `Value` is a Null, returns (). Returns None otherwise.
217    ///
218    /// ```
219    /// # use serde_yaml::Value;
220    /// let v: Value = serde_yaml::from_str("null").unwrap();
221    /// assert_eq!(v.as_null(), Some(()));
222    /// ```
223    ///
224    /// ```
225    /// # use serde_yaml::Value;
226    /// let v: Value = serde_yaml::from_str("false").unwrap();
227    /// assert_eq!(v.as_null(), None);
228    /// ```
229    pub fn as_null(&self) -> Option<()> {
230        match self.untag_ref() {
231            Value::Null => Some(()),
232            _ => None,
233        }
234    }
235
236    /// Returns true if the `Value` is a Boolean. Returns false otherwise.
237    ///
238    /// For any Value on which `is_boolean` returns true, `as_bool` is
239    /// guaranteed to return the boolean value.
240    ///
241    /// ```
242    /// # use serde_yaml::Value;
243    /// let v: Value = serde_yaml::from_str("true").unwrap();
244    /// assert!(v.is_bool());
245    /// ```
246    ///
247    /// ```
248    /// # use serde_yaml::Value;
249    /// let v: Value = serde_yaml::from_str("42").unwrap();
250    /// assert!(!v.is_bool());
251    /// ```
252    pub fn is_bool(&self) -> bool {
253        self.as_bool().is_some()
254    }
255
256    /// If the `Value` is a Boolean, returns the associated bool. Returns None
257    /// otherwise.
258    ///
259    /// ```
260    /// # use serde_yaml::Value;
261    /// let v: Value = serde_yaml::from_str("true").unwrap();
262    /// assert_eq!(v.as_bool(), Some(true));
263    /// ```
264    ///
265    /// ```
266    /// # use serde_yaml::Value;
267    /// let v: Value = serde_yaml::from_str("42").unwrap();
268    /// assert_eq!(v.as_bool(), None);
269    /// ```
270    pub fn as_bool(&self) -> Option<bool> {
271        match self.untag_ref() {
272            Value::Bool(b) => Some(*b),
273            _ => None,
274        }
275    }
276
277    /// Returns true if the `Value` is a Number. Returns false otherwise.
278    ///
279    /// ```
280    /// # use serde_yaml::Value;
281    /// let v: Value = serde_yaml::from_str("5").unwrap();
282    /// assert!(v.is_number());
283    /// ```
284    ///
285    /// ```
286    /// # use serde_yaml::Value;
287    /// let v: Value = serde_yaml::from_str("true").unwrap();
288    /// assert!(!v.is_number());
289    /// ```
290    pub fn is_number(&self) -> bool {
291        match self.untag_ref() {
292            Value::Number(_) => true,
293            _ => false,
294        }
295    }
296
297    /// Returns true if the `Value` is an integer between `i64::MIN` and
298    /// `i64::MAX`.
299    ///
300    /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to
301    /// return the integer value.
302    ///
303    /// ```
304    /// # use serde_yaml::Value;
305    /// let v: Value = serde_yaml::from_str("1337").unwrap();
306    /// assert!(v.is_i64());
307    /// ```
308    ///
309    /// ```
310    /// # use serde_yaml::Value;
311    /// let v: Value = serde_yaml::from_str("null").unwrap();
312    /// assert!(!v.is_i64());
313    /// ```
314    pub fn is_i64(&self) -> bool {
315        self.as_i64().is_some()
316    }
317
318    /// If the `Value` is an integer, represent it as i64 if possible. Returns
319    /// None otherwise.
320    ///
321    /// ```
322    /// # use serde_yaml::Value;
323    /// let v: Value = serde_yaml::from_str("1337").unwrap();
324    /// assert_eq!(v.as_i64(), Some(1337));
325    /// ```
326    ///
327    /// ```
328    /// # use serde_yaml::Value;
329    /// let v: Value = serde_yaml::from_str("false").unwrap();
330    /// assert_eq!(v.as_i64(), None);
331    /// ```
332    pub fn as_i64(&self) -> Option<i64> {
333        match self.untag_ref() {
334            Value::Number(n) => n.as_i64(),
335            _ => None,
336        }
337    }
338
339    /// Returns true if the `Value` is an integer between `u64::MIN` and
340    /// `u64::MAX`.
341    ///
342    /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to
343    /// return the integer value.
344    ///
345    /// ```
346    /// # use serde_yaml::Value;
347    /// let v: Value = serde_yaml::from_str("1337").unwrap();
348    /// assert!(v.is_u64());
349    /// ```
350    ///
351    /// ```
352    /// # use serde_yaml::Value;
353    /// let v: Value = serde_yaml::from_str("null").unwrap();
354    /// assert!(!v.is_u64());
355    /// ```
356    pub fn is_u64(&self) -> bool {
357        self.as_u64().is_some()
358    }
359
360    /// If the `Value` is an integer, represent it as u64 if possible. Returns
361    /// None otherwise.
362    ///
363    /// ```
364    /// # use serde_yaml::Value;
365    /// let v: Value = serde_yaml::from_str("1337").unwrap();
366    /// assert_eq!(v.as_u64(), Some(1337));
367    /// ```
368    ///
369    /// ```
370    /// # use serde_yaml::Value;
371    /// let v: Value = serde_yaml::from_str("false").unwrap();
372    /// assert_eq!(v.as_u64(), None);
373    /// ```
374    pub fn as_u64(&self) -> Option<u64> {
375        match self.untag_ref() {
376            Value::Number(n) => n.as_u64(),
377            _ => None,
378        }
379    }
380
381    /// Returns true if the `Value` is a number that can be represented by f64.
382    ///
383    /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to
384    /// return the floating point value.
385    ///
386    /// Currently this function returns true if and only if both `is_i64` and
387    /// `is_u64` return false but this is not a guarantee in the future.
388    ///
389    /// ```
390    /// # use serde_yaml::Value;
391    /// let v: Value = serde_yaml::from_str("256.01").unwrap();
392    /// assert!(v.is_f64());
393    /// ```
394    ///
395    /// ```
396    /// # use serde_yaml::Value;
397    /// let v: Value = serde_yaml::from_str("true").unwrap();
398    /// assert!(!v.is_f64());
399    /// ```
400    pub fn is_f64(&self) -> bool {
401        match self.untag_ref() {
402            Value::Number(n) => n.is_f64(),
403            _ => false,
404        }
405    }
406
407    /// If the `Value` is a number, represent it as f64 if possible. Returns
408    /// None otherwise.
409    ///
410    /// ```
411    /// # use serde_yaml::Value;
412    /// let v: Value = serde_yaml::from_str("13.37").unwrap();
413    /// assert_eq!(v.as_f64(), Some(13.37));
414    /// ```
415    ///
416    /// ```
417    /// # use serde_yaml::Value;
418    /// let v: Value = serde_yaml::from_str("false").unwrap();
419    /// assert_eq!(v.as_f64(), None);
420    /// ```
421    pub fn as_f64(&self) -> Option<f64> {
422        match self.untag_ref() {
423            Value::Number(i) => i.as_f64(),
424            _ => None,
425        }
426    }
427
428    /// Returns true if the `Value` is a String. Returns false otherwise.
429    ///
430    /// For any Value on which `is_string` returns true, `as_str` is guaranteed
431    /// to return the string slice.
432    ///
433    /// ```
434    /// # use serde_yaml::Value;
435    /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap();
436    /// assert!(v.is_string());
437    /// ```
438    ///
439    /// ```
440    /// # use serde_yaml::Value;
441    /// let v: Value = serde_yaml::from_str("42").unwrap();
442    /// assert!(!v.is_string());
443    /// ```
444    pub fn is_string(&self) -> bool {
445        self.as_str().is_some()
446    }
447
448    /// If the `Value` is a String, returns the associated str. Returns None
449    /// otherwise.
450    ///
451    /// ```
452    /// # use serde_yaml::Value;
453    /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap();
454    /// assert_eq!(v.as_str(), Some("lorem ipsum"));
455    /// ```
456    ///
457    /// ```
458    /// # use serde_yaml::Value;
459    /// let v: Value = serde_yaml::from_str("false").unwrap();
460    /// assert_eq!(v.as_str(), None);
461    /// ```
462    pub fn as_str(&self) -> Option<&str> {
463        match self.untag_ref() {
464            Value::String(s) => Some(s),
465            _ => None,
466        }
467    }
468
469    /// Returns true if the `Value` is a sequence. Returns false otherwise.
470    ///
471    /// ```
472    /// # use serde_yaml::Value;
473    /// let v: Value = serde_yaml::from_str("[1, 2, 3]").unwrap();
474    /// assert!(v.is_sequence());
475    /// ```
476    ///
477    /// ```
478    /// # use serde_yaml::Value;
479    /// let v: Value = serde_yaml::from_str("true").unwrap();
480    /// assert!(!v.is_sequence());
481    /// ```
482    pub fn is_sequence(&self) -> bool {
483        self.as_sequence().is_some()
484    }
485
486    /// If the `Value` is a sequence, return a reference to it if possible.
487    /// Returns None otherwise.
488    ///
489    /// ```
490    /// # use serde_yaml::{Value, Number};
491    /// let v: Value = serde_yaml::from_str("[1, 2]").unwrap();
492    /// assert_eq!(v.as_sequence(), Some(&vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]));
493    /// ```
494    ///
495    /// ```
496    /// # use serde_yaml::Value;
497    /// let v: Value = serde_yaml::from_str("false").unwrap();
498    /// assert_eq!(v.as_sequence(), None);
499    /// ```
500    pub fn as_sequence(&self) -> Option<&Sequence> {
501        match self.untag_ref() {
502            Value::Sequence(seq) => Some(seq),
503            _ => None,
504        }
505    }
506
507    /// If the `Value` is a sequence, return a mutable reference to it if
508    /// possible. Returns None otherwise.
509    ///
510    /// ```
511    /// # use serde_yaml::{Value, Number};
512    /// let mut v: Value = serde_yaml::from_str("[1]").unwrap();
513    /// let s = v.as_sequence_mut().unwrap();
514    /// s.push(Value::Number(Number::from(2)));
515    /// assert_eq!(s, &vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]);
516    /// ```
517    ///
518    /// ```
519    /// # use serde_yaml::Value;
520    /// let mut v: Value = serde_yaml::from_str("false").unwrap();
521    /// assert_eq!(v.as_sequence_mut(), None);
522    /// ```
523    pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
524        match self.untag_mut() {
525            Value::Sequence(seq) => Some(seq),
526            _ => None,
527        }
528    }
529
530    /// Returns true if the `Value` is a mapping. Returns false otherwise.
531    ///
532    /// ```
533    /// # use serde_yaml::Value;
534    /// let v: Value = serde_yaml::from_str("a: 42").unwrap();
535    /// assert!(v.is_mapping());
536    /// ```
537    ///
538    /// ```
539    /// # use serde_yaml::Value;
540    /// let v: Value = serde_yaml::from_str("true").unwrap();
541    /// assert!(!v.is_mapping());
542    /// ```
543    pub fn is_mapping(&self) -> bool {
544        self.as_mapping().is_some()
545    }
546
547    /// If the `Value` is a mapping, return a reference to it if possible.
548    /// Returns None otherwise.
549    ///
550    /// ```
551    /// # use serde_yaml::{Value, Mapping, Number};
552    /// let v: Value = serde_yaml::from_str("a: 42").unwrap();
553    ///
554    /// let mut expected = Mapping::new();
555    /// expected.insert(Value::String("a".into()),Value::Number(Number::from(42)));
556    ///
557    /// assert_eq!(v.as_mapping(), Some(&expected));
558    /// ```
559    ///
560    /// ```
561    /// # use serde_yaml::Value;
562    /// let v: Value = serde_yaml::from_str("false").unwrap();
563    /// assert_eq!(v.as_mapping(), None);
564    /// ```
565    pub fn as_mapping(&self) -> Option<&Mapping> {
566        match self.untag_ref() {
567            Value::Mapping(map) => Some(map),
568            _ => None,
569        }
570    }
571
572    /// If the `Value` is a mapping, return a reference to it if possible.
573    /// Returns None otherwise.
574    ///
575    /// ```
576    /// # use serde_yaml::{Value, Mapping, Number};
577    /// let mut v: Value = serde_yaml::from_str("a: 42").unwrap();
578    /// let m = v.as_mapping_mut().unwrap();
579    /// m.insert(Value::String("b".into()), Value::Number(Number::from(21)));
580    ///
581    /// let mut expected = Mapping::new();
582    /// expected.insert(Value::String("a".into()), Value::Number(Number::from(42)));
583    /// expected.insert(Value::String("b".into()), Value::Number(Number::from(21)));
584    ///
585    /// assert_eq!(m, &expected);
586    /// ```
587    ///
588    /// ```
589    /// # use serde_yaml::{Value, Mapping};
590    /// let mut v: Value = serde_yaml::from_str("false").unwrap();
591    /// assert_eq!(v.as_mapping_mut(), None);
592    /// ```
593    pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
594        match self.untag_mut() {
595            Value::Mapping(map) => Some(map),
596            _ => None,
597        }
598    }
599
600    /// Performs merging of `<<` keys into the surrounding mapping.
601    ///
602    /// The intended use of this in YAML is described in
603    /// <https://yaml.org/type/merge.html>.
604    ///
605    /// ```
606    /// use serde_yaml::Value;
607    ///
608    /// let config = "\
609    /// tasks:
610    ///   build: &webpack_shared
611    ///     command: webpack
612    ///     args: build
613    ///     inputs:
614    ///       - 'src/**/*'
615    ///   start:
616    ///     <<: *webpack_shared
617    ///     args: start
618    /// ";
619    ///
620    /// let mut value: Value = serde_yaml::from_str(config).unwrap();
621    /// value.apply_merge().unwrap();
622    ///
623    /// assert_eq!(value["tasks"]["start"]["command"], "webpack");
624    /// assert_eq!(value["tasks"]["start"]["args"], "start");
625    /// ```
626    pub fn apply_merge(&mut self) -> Result<(), Error> {
627        let mut stack = Vec::new();
628        stack.push(self);
629        while let Some(node) = stack.pop() {
630            match node {
631                Value::Mapping(mapping) => {
632                    match mapping.remove("<<") {
633                        Some(Value::Mapping(merge)) => {
634                            for (k, v) in merge {
635                                mapping.entry(k).or_insert(v);
636                            }
637                        }
638                        Some(Value::Sequence(sequence)) => {
639                            for value in sequence {
640                                match value {
641                                    Value::Mapping(merge) => {
642                                        for (k, v) in merge {
643                                            mapping.entry(k).or_insert(v);
644                                        }
645                                    }
646                                    Value::Sequence(_) => {
647                                        return Err(error::new(ErrorImpl::SequenceInMergeElement));
648                                    }
649                                    Value::Tagged(_) => {
650                                        return Err(error::new(ErrorImpl::TaggedInMerge));
651                                    }
652                                    _unexpected => {
653                                        return Err(error::new(ErrorImpl::ScalarInMergeElement));
654                                    }
655                                }
656                            }
657                        }
658                        None => {}
659                        Some(Value::Tagged(_)) => return Err(error::new(ErrorImpl::TaggedInMerge)),
660                        Some(_unexpected) => return Err(error::new(ErrorImpl::ScalarInMerge)),
661                    }
662                    stack.extend(mapping.values_mut());
663                }
664                Value::Sequence(sequence) => stack.extend(sequence),
665                Value::Tagged(tagged) => stack.push(&mut tagged.value),
666                _ => {}
667            }
668        }
669        Ok(())
670    }
671}
672
673impl Eq for Value {}
674
675// NOTE: This impl must be kept consistent with HashLikeValue's Hash impl in
676// mapping.rs in order for value[str] indexing to work.
677impl Hash for Value {
678    fn hash<H: Hasher>(&self, state: &mut H) {
679        mem::discriminant(self).hash(state);
680        match self {
681            Value::Null => {}
682            Value::Bool(v) => v.hash(state),
683            Value::Number(v) => v.hash(state),
684            Value::String(v) => v.hash(state),
685            Value::Sequence(v) => v.hash(state),
686            Value::Mapping(v) => v.hash(state),
687            Value::Tagged(v) => v.hash(state),
688        }
689    }
690}
691
692impl<'de> IntoDeserializer<'de, Error> for Value {
693    type Deserializer = Self;
694
695    fn into_deserializer(self) -> Self::Deserializer {
696        self
697    }
698}