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}