Skip to main content

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