Skip to main content

yaml_spanned/
value.rs

1use crate::error::{DuplicateKeyError, ErrorSpan, LimitExceeded, ParseError};
2use crate::mapping::Mapping;
3use crate::number::Number;
4use crate::spanned::{Span, Spanned};
5use crate::tag::{Tag, TaggedValue};
6use indexmap::IndexMap;
7use itertools::Itertools;
8
9#[inline]
10fn parse_null(scalar: &[u8]) -> Option<()> {
11    match scalar {
12        b"null" | b"Null" | b"NULL" | b"~" | b"" => Some(()),
13        _ => None,
14    }
15}
16
17#[inline]
18fn parse_bool(scalar: &str) -> Option<bool> {
19    match scalar {
20        "true" | "True" | "TRUE" => Some(true),
21        "false" | "False" | "FALSE" => Some(false),
22        _ => None,
23    }
24}
25
26pub type Sequence = Vec<Spanned<Value>>;
27
28/// Represents any valid YAML value.
29#[derive(Clone, PartialEq, PartialOrd)]
30pub enum Value {
31    /// Represents a YAML null value.
32    Null,
33    /// Represents a YAML boolean.
34    Bool(bool),
35    /// Represents a YAML numerical value, whether integer or floating point.
36    Number(Number),
37    /// Represents a YAML string.
38    String(String),
39    /// Represents a YAML sequence in which the elements are `yaml_spanned::SpannedValue`.
40    Sequence(Sequence),
41    /// Represents a YAML mapping in which the keys and values are both `yaml_spanned::SpannedValue`.
42    Mapping(Mapping),
43    /// A representation of YAML's `!Tag` syntax, used for enums.
44    Tagged(Box<TaggedValue>),
45}
46
47/// Represents any valid YAML value kind.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub enum Kind {
51    /// Represents a YAML null value.
52    Null,
53    /// Represents a YAML boolean.
54    Bool,
55    /// Represents a YAML numerical value, whether integer or floating point.
56    Number,
57    /// Represents a YAML string.
58    String,
59    /// Represents a YAML sequence in which the elements are `yaml_spanned::SpannedValue`.
60    Sequence,
61    /// Represents a YAML mapping in which the keys and values are both `yaml_spanned::SpannedValue`.
62    Mapping,
63    /// A representation of YAML's `!Tag` syntax, used for enums.
64    Tagged,
65}
66
67/// The default value is `Value::Null`.
68///
69/// This is useful for handling omitted `Value` fields when deserializing.
70///
71/// # Examples
72///
73/// ```
74/// use serde::Deserialize;
75/// use yaml_spanned::{Value, SpannedValue};
76///
77/// #[derive(serde::Deserialize)]
78/// struct Settings {
79///     level: i32,
80///     #[serde(default)]
81///     extras: Value,
82/// }
83///
84/// # fn main() -> Result<(), yaml_spanned::Error> {
85/// let yaml = r#" { "level": 42 } "#;
86/// let value: SpannedValue = yaml_spanned::from_str(&yaml)?;
87/// let settings: Settings = yaml_spanned::from_value(&value)?;
88///
89/// assert_eq!(settings.level, 42);
90/// assert_eq!(settings.extras, yaml_spanned::Value::Null);
91/// #
92/// #     Ok(())
93/// # }
94/// ```
95impl Default for Value {
96    fn default() -> Value {
97        Value::Null
98    }
99}
100
101impl Value {
102    #[must_use]
103    pub fn kind(&self) -> Kind {
104        match self {
105            Self::Null => Kind::Null,
106            Self::Number(_) => Kind::Number,
107            Self::String(_) => Kind::String,
108            Self::Sequence(_) => Kind::Sequence,
109            Self::Mapping(_) => Kind::Mapping,
110            Self::Tagged(_) => Kind::Tagged,
111            Self::Bool(_) => Kind::Bool,
112        }
113    }
114
115    #[must_use]
116    pub fn cleared_spans(mut self) -> Self {
117        self.clear_spans();
118        self
119    }
120
121    pub fn clear_spans(&mut self) {
122        match self {
123            Value::Tagged(v) => v.value.clear_spans(),
124            Value::Mapping(mapping) => {
125                let old_mapping: Mapping = std::mem::take(mapping);
126                *mapping = Mapping::from_iter(
127                    old_mapping
128                        .into_iter()
129                        .map(|(k, v)| (k.into_inner().into(), v.into_inner().into())),
130                );
131            }
132            Value::Sequence(seq) => {
133                for v in seq.iter_mut() {
134                    v.clear_spans();
135                }
136            }
137            Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
138        }
139    }
140}
141
142impl Spanned<Value> {
143    #[must_use]
144    pub fn cleared_spans(mut self) -> Self {
145        self.clear_spans();
146        self
147    }
148
149    pub fn clear_spans(&mut self) {
150        self.span.start = None;
151        self.span.end = None;
152        self.inner.clear_spans();
153    }
154}
155impl Value {
156    #[inline]
157    #[must_use]
158    pub fn is_null(&self) -> bool {
159        matches!(self, Self::Null)
160    }
161
162    #[inline]
163    #[must_use]
164    pub fn is_sequence(&self) -> bool {
165        self.as_sequence().is_some()
166    }
167
168    #[inline]
169    pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> {
170        match self {
171            Self::Sequence(sequence) => Some(sequence),
172            _ => None,
173        }
174    }
175
176    #[inline]
177    #[must_use]
178    pub fn as_sequence(&self) -> Option<&Sequence> {
179        match self {
180            Self::Sequence(sequence) => Some(sequence),
181            _ => None,
182        }
183    }
184
185    #[inline]
186    #[must_use]
187    pub fn is_mapping(&self) -> bool {
188        self.as_mapping().is_some()
189    }
190
191    #[inline]
192    pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> {
193        match self {
194            Self::Mapping(mapping) => Some(mapping),
195            _ => None,
196        }
197    }
198
199    #[inline]
200    #[must_use]
201    pub fn as_mapping(&self) -> Option<&Mapping> {
202        match self {
203            Self::Mapping(mapping) => Some(mapping),
204            _ => None,
205        }
206    }
207
208    #[inline]
209    pub fn get_or_null<I: crate::mapping::Index>(&self, index: I) -> &Spanned<Value> {
210        static NULL: Spanned<Value> = Spanned::dummy(Value::Null);
211        self.as_mapping()
212            .and_then(|map| map.get(index))
213            .unwrap_or(&NULL)
214    }
215
216    #[inline]
217    pub fn get<I: crate::mapping::Index>(&self, index: I) -> Option<&Spanned<Value>> {
218        self.as_mapping().and_then(|map| map.get(index))
219    }
220
221    #[inline]
222    pub fn get_mut<I: crate::mapping::Index>(&mut self, index: I) -> Option<&mut Spanned<Value>> {
223        self.as_mapping_mut().and_then(|map| map.get_mut(index))
224    }
225
226    #[inline]
227    #[must_use]
228    pub fn is_bool(&self) -> bool {
229        self.as_bool().is_some()
230    }
231
232    #[inline]
233    pub fn as_bool_mut(&mut self) -> Option<&mut bool> {
234        match self {
235            Self::Bool(boolean) => Some(boolean),
236            _ => None,
237        }
238    }
239
240    #[inline]
241    #[must_use]
242    pub fn as_bool(&self) -> Option<bool> {
243        match self {
244            Self::Bool(boolean) => Some(*boolean),
245            _ => None,
246        }
247    }
248
249    #[inline]
250    #[must_use]
251    pub fn is_u64(&self) -> bool {
252        self.as_u64().is_some()
253    }
254
255    #[inline]
256    pub fn as_u64_mut(&mut self) -> Option<&mut u64> {
257        match self {
258            Self::Number(number) => number.as_u64_mut(),
259            _ => None,
260        }
261    }
262
263    #[inline]
264    #[must_use]
265    pub fn as_u64(&self) -> Option<u64> {
266        match self {
267            Self::Number(number) => number.as_u64(),
268            _ => None,
269        }
270    }
271
272    #[inline]
273    #[must_use]
274    pub fn is_i64(&self) -> bool {
275        self.as_i64().is_some()
276    }
277
278    #[inline]
279    pub fn as_i64_mut(&mut self) -> Option<&mut i64> {
280        match self {
281            Self::Number(number) => number.as_i64_mut(),
282            _ => None,
283        }
284    }
285
286    #[inline]
287    #[must_use]
288    pub fn as_i64(&self) -> Option<i64> {
289        match self {
290            Self::Number(number) => number.as_i64(),
291            _ => None,
292        }
293    }
294
295    #[inline]
296    #[must_use]
297    pub fn is_f64(&self) -> bool {
298        // NOTE: cannot use `as_f64().is_some()`, as_f64 will cast integers to floating points numbers
299        match self {
300            Self::Number(number) => number.is_f64(),
301            _ => false,
302        }
303    }
304
305    #[inline]
306    pub fn as_f64_mut(&mut self) -> Option<&mut f64> {
307        match self {
308            Self::Number(number) => number.as_f64_mut(),
309            _ => None,
310        }
311    }
312
313    #[inline]
314    #[must_use]
315    pub fn as_f64(&self) -> Option<f64> {
316        match self {
317            Self::Number(number) => number.as_f64(),
318            _ => None,
319        }
320    }
321
322    #[inline]
323    #[must_use]
324    pub fn is_str(&self) -> bool {
325        self.as_str().is_some()
326    }
327
328    #[inline]
329    pub fn as_str_mut(&mut self) -> Option<&mut str> {
330        match self {
331            Self::String(scalar) => Some(scalar.as_mut_str()),
332            _ => None,
333        }
334    }
335
336    #[inline]
337    #[must_use]
338    pub fn as_str(&self) -> Option<&str> {
339        match self {
340            Self::String(scalar) => Some(scalar.as_str()),
341            _ => None,
342        }
343    }
344
345    #[inline]
346    #[must_use]
347    pub fn is_string(&self) -> bool {
348        self.as_string().is_some()
349    }
350
351    #[inline]
352    pub fn as_string_mut(&mut self) -> Option<&mut String> {
353        match self {
354            Self::String(scalar) => Some(scalar),
355            _ => None,
356        }
357    }
358
359    #[inline]
360    #[must_use]
361    pub fn as_string(&self) -> Option<&String> {
362        match self {
363            Self::String(scalar) => Some(scalar),
364            _ => None,
365        }
366    }
367
368    /// Performs merging of `<<` keys into the surrounding mapping.
369    ///
370    /// The intended use of this in YAML is described in
371    /// <https://yaml.org/type/merge.html>.
372    ///
373    /// ```
374    /// use yaml_spanned::SpannedValue;
375    ///
376    /// let config = "\
377    /// tasks:
378    ///   build: &webpack_shared
379    ///     command: webpack
380    ///     args: build
381    ///     inputs:
382    ///       - 'src/**/*'
383    ///   start:
384    ///     <<: *webpack_shared
385    ///     args: start
386    /// ";
387    ///
388    /// let mut value: SpannedValue = yaml_spanned::from_str(config).unwrap();
389    /// value.apply_merge().unwrap();
390    ///
391    /// assert_eq!(value["tasks"]["start"]["command"], "webpack");
392    /// assert_eq!(value["tasks"]["start"]["args"], "start");
393    /// ```
394    pub fn apply_merge(&mut self) -> Result<(), crate::error::MergeError> {
395        let mut stack = Vec::new();
396        stack.push(self);
397        while let Some(node) = stack.pop() {
398            match node {
399                Value::Mapping(mapping) => {
400                    match mapping.remove("<<").map(Spanned::into_inner) {
401                        Some(Value::Mapping(merge)) => {
402                            for (k, v) in merge {
403                                _ = mapping.entry(k).or_insert(v);
404                            }
405                        }
406                        Some(Value::Sequence(sequence)) => {
407                            for value in sequence {
408                                match value.into_inner() {
409                                    Value::Mapping(merge) => {
410                                        for (k, v) in merge {
411                                            _ = mapping.entry(k).or_insert(v);
412                                        }
413                                    }
414                                    Value::Sequence(_) => {
415                                        return Err(
416                                            crate::error::MergeError::SequenceInMergeElement,
417                                        );
418                                    }
419                                    Value::Tagged(_) => {
420                                        return Err(crate::error::MergeError::TaggedInMerge);
421                                    }
422                                    _unexpected => {
423                                        return Err(crate::error::MergeError::ScalarInMergeElement);
424                                    }
425                                }
426                            }
427                        }
428                        None => {}
429                        Some(Value::Tagged(_)) => {
430                            return Err(crate::error::MergeError::TaggedInMerge);
431                        }
432                        Some(_unexpected) => {
433                            return Err(crate::error::MergeError::ScalarInMergeElement);
434                        }
435                    }
436                    stack.extend(mapping.values_mut().map(Spanned::as_mut));
437                }
438                Value::Sequence(sequence) => stack.extend(sequence.iter_mut().map(Spanned::as_mut)),
439                Value::Tagged(tagged) => stack.push(&mut tagged.value),
440                _ => {}
441            }
442        }
443        Ok(())
444    }
445}
446
447impl std::fmt::Debug for Value {
448    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
449        match self {
450            Self::Null => write!(f, "NULL"),
451            Self::Bool(boolean) => write!(f, "Bool({boolean})"),
452            Self::String(value) => write!(f, "String({value:?})"),
453            Self::Number(number) => write!(f, "Number({number:?})"),
454            Self::Sequence(sequence) => f.debug_list().entries(sequence).finish(),
455            Self::Mapping(mapping) => std::fmt::Debug::fmt(mapping, f),
456            Self::Tagged(tagged) => std::fmt::Debug::fmt(tagged, f),
457        }
458    }
459}
460
461impl std::fmt::Display for Value {
462    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
463        match self {
464            Self::Null => write!(f, "NULL"),
465            Self::Bool(boolean) => write!(f, "Bool({boolean})"),
466            Self::String(value) => write!(f, "String({value})"),
467            Self::Number(number) => write!(f, "Number({number})"),
468            Self::Sequence(sequence) => f
469                .debug_list()
470                .entries(sequence.iter().map(crate::fmt::Display))
471                .finish(),
472            Self::Mapping(mapping) => std::fmt::Display::fmt(mapping, f),
473            Self::Tagged(tagged) => std::fmt::Display::fmt(tagged, f),
474        }
475    }
476}
477
478pub struct StringValueRepr<'a>(&'a Value);
479
480impl std::fmt::Debug for StringValueRepr<'_> {
481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
482        std::fmt::Display::fmt(&self, f)
483    }
484}
485
486impl std::fmt::Display for StringValueRepr<'_> {
487    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
488        match self.0 {
489            Value::Null => write!(f, "NULL"),
490            Value::Bool(boolean) => write!(f, "{boolean}"),
491            Value::String(value) => write!(f, "{value}"),
492            Value::Number(number) => write!(f, "{number}"),
493            Value::Sequence(sequence) => f
494                .debug_list()
495                .entries(sequence.iter().map(|item| item.string_value_repr()))
496                .finish(),
497            Value::Mapping(mapping) => write!(f, "{}", mapping.string_value_repr()),
498            Value::Tagged(tagged) => write!(f, "{}", tagged.value.string_value_repr()),
499        }
500    }
501}
502
503impl Value {
504    #[must_use]
505    pub fn string_value_repr(&self) -> StringValueRepr<'_> {
506        StringValueRepr(self)
507    }
508}
509
510impl Eq for Value {}
511
512// NOTE: This impl must be kept consistent with HashLikeValue's Hash impl in
513// mapping.rs in order for value[str] indexing to work.
514impl std::hash::Hash for Value {
515    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
516        std::mem::discriminant(self).hash(state);
517        match self {
518            Value::Null => {}
519            Value::Bool(v) => v.hash(state),
520            Value::Number(v) => v.hash(state),
521            Value::String(v) => v.hash(state),
522            Value::Sequence(v) => v.hash(state),
523            Value::Mapping(v) => v.hash(state),
524            Value::Tagged(v) => v.hash(state),
525        }
526    }
527}
528
529impl TryFrom<libyaml_safer::Mark> for crate::spanned::Marker {
530    type Error = std::num::TryFromIntError;
531    fn try_from(value: libyaml_safer::Mark) -> Result<Self, Self::Error> {
532        Ok(Self {
533            byte_index: value.index.try_into()?,
534            line: value.line.try_into()?,
535            column: value.column.try_into()?,
536        })
537    }
538}
539
540impl TryFrom<(libyaml_safer::Mark, libyaml_safer::Mark)> for crate::spanned::Span {
541    type Error = std::num::TryFromIntError;
542    fn try_from(value: (libyaml_safer::Mark, libyaml_safer::Mark)) -> Result<Self, Self::Error> {
543        Ok(Self {
544            start: Some(value.0.try_into()?),
545            end: Some(value.1.try_into()?),
546        })
547    }
548}
549
550trait ToValue {
551    fn to_value(
552        &self,
553        path: &str,
554        document: &libyaml_safer::Document,
555        errors: &mut Vec<ParseError>,
556        recursion_limit: usize,
557        jump_limit: &mut usize,
558    ) -> Result<Spanned<Value>, LimitExceeded>;
559}
560
561#[inline]
562fn scalar_node_to_value_guess_type(
563    // node: &libyaml_safer::Node,
564    // path: &str,
565    value: &str,
566    style: &libyaml_safer::ScalarStyle,
567    // document: &libyaml_safer::Document,
568    // errors: &mut Vec<ParseError>,
569) -> Value {
570    match style {
571        // ':'  => ScalarStyle::Plain,
572        // '\'' => ScalarStyle::SingleQuoted,
573        // '"'  => ScalarStyle::DoubleQuoted,
574        // '|'  => ScalarStyle::Literal,
575        // '>'  => ScalarStyle::Folded,
576        libyaml_safer::ScalarStyle::Plain | libyaml_safer::ScalarStyle::Any => {
577            if parse_null(value.as_bytes()).is_some() {
578                return Value::Null;
579            }
580            if let Some(boolean) = parse_bool(value) {
581                return Value::Bool(boolean);
582            }
583            if let Some(number) = crate::number::parse_number(value) {
584                return Value::Number(number);
585            }
586            Value::String(value.to_string())
587        }
588        // libyaml_safer::ScalarStyle::Literal
589        // | libyaml_safer::ScalarStyle::Folded
590        // | libyaml_safer::ScalarStyle::SingleQuoted
591        // | libyaml_safer::ScalarStyle::SingleQuoted
592        _ => {
593            // is string
594            Value::String(value.to_string())
595        }
596    }
597}
598
599trait SpannedNode {
600    fn span(&self) -> Span;
601}
602
603impl SpannedNode for &libyaml_safer::Node {
604    fn span(&self) -> Span {
605        Span {
606            start: self.start_mark.try_into().ok(),
607            end: self.end_mark.try_into().ok(),
608        }
609    }
610}
611
612impl SpannedNode for &libyaml_safer::Document {
613    fn span(&self) -> Span {
614        Span {
615            start: self.start_mark.try_into().ok(),
616            end: self.end_mark.try_into().ok(),
617        }
618    }
619}
620
621#[inline]
622fn scalar_node_to_value(
623    node: &libyaml_safer::Node,
624    // path: &str,
625    value: &str,
626    style: &libyaml_safer::ScalarStyle,
627    // document: &libyaml_safer::Document,
628    // errors: &mut Vec<ParseError>,
629) -> Spanned<Value> {
630    if let Some("tag:yaml.org,2002:int") = node.tag.as_deref() {
631        if let Some(number) = crate::number::parse_number(value) {
632            return Spanned::new(node.span(), Value::Number(number));
633        }
634    } else {
635        // autodetect
636    }
637    // let value = scalar_node_to_value_guess_type(node, path, value, style, document, errors);
638    let value = scalar_node_to_value_guess_type(value, style);
639    Spanned::new(node.span(), value)
640}
641
642#[inline]
643fn mapping_node_to_value(
644    node: &libyaml_safer::Node,
645    path: &str,
646    pairs: &[libyaml_safer::NodePair],
647    // style: &libyaml_safer::MappingStyle,
648    document: &libyaml_safer::Document,
649    errors: &mut Vec<ParseError>,
650    recursion_limit: usize,
651    jump_limit: &mut usize,
652) -> Result<Spanned<Value>, LimitExceeded> {
653    let entries: Vec<_> = pairs
654        .iter()
655        .map(|pair| {
656            // *jump_count += 1;
657            if *jump_limit == 0 {
658                return Err(LimitExceeded::RepetitionLimitExceeded);
659            }
660            *jump_limit = jump_limit.saturating_sub(1);
661            let key = document.get_node(pair.key).unwrap().to_value(
662                path,
663                document,
664                errors,
665                recursion_limit.saturating_sub(1),
666                jump_limit,
667            )?;
668
669            // *jump_count += 1;
670            if *jump_limit == 0 {
671                return Err(LimitExceeded::RepetitionLimitExceeded);
672            }
673            *jump_limit = jump_limit.saturating_sub(1);
674
675            let value = document.get_node(pair.value).unwrap().to_value(
676                &format!("{path}.{}", key.as_str().unwrap_or_default()),
677                document,
678                errors,
679                recursion_limit.saturating_sub(1),
680                jump_limit,
681            )?;
682            Ok::<_, LimitExceeded>((key, value))
683        })
684        .collect::<Result<Vec<_>, _>>()?;
685
686    let duplicate_keys = entries.iter().map(|(key, _)| key.as_ref()).duplicates();
687    // .take(1); // only take the first entry?
688
689    for duplicate_key in duplicate_keys {
690        let occurrences = entries
691            .iter()
692            .filter(|(key, _)| key == duplicate_key)
693            .map(|(key, _)| key.span().into())
694            .collect::<Vec<ErrorSpan>>();
695        errors.push(
696            DuplicateKeyError {
697                key: duplicate_key.string_value_repr().to_string(),
698                path: path.to_string(),
699                occurrences,
700            }
701            .into(),
702        );
703    }
704    Ok(Spanned::new(
705        node.span(),
706        Value::Mapping(Mapping(IndexMap::from_iter(entries))),
707    ))
708}
709
710#[inline]
711fn sequence_node_to_value(
712    node: &libyaml_safer::Node,
713    path: &str,
714    items: &[i32],
715    // style: &libyaml_safer::SequenceStyle,
716    document: &libyaml_safer::Document,
717    errors: &mut Vec<ParseError>,
718    recursion_limit: usize,
719    jump_limit: &mut usize,
720) -> Result<Spanned<Value>, LimitExceeded> {
721    let sequence = items
722        .iter()
723        .enumerate()
724        .map(|(idx, node_idx)| {
725            if *jump_limit == 0 {
726                return Err(LimitExceeded::RepetitionLimitExceeded);
727            }
728            *jump_limit = jump_limit.saturating_sub(1);
729
730            document.get_node(*node_idx).unwrap().to_value(
731                &format!("{path}[{idx}]"),
732                document,
733                errors,
734                recursion_limit.saturating_sub(1),
735                jump_limit,
736            )
737        })
738        .collect::<Result<Vec<_>, _>>()?;
739    Ok(Spanned::new(node.span(), Value::Sequence(sequence)))
740}
741
742impl ToValue for libyaml_safer::Node {
743    fn to_value(
744        &self,
745        path: &str,
746        document: &libyaml_safer::Document,
747        errors: &mut Vec<ParseError>,
748        recursion_limit: usize,
749        jump_limit: &mut usize,
750    ) -> Result<Spanned<Value>, LimitExceeded> {
751        if recursion_limit == 0 {
752            return Err(LimitExceeded::RecursionLimitExceeded);
753        }
754
755        let value = match &self.data {
756            libyaml_safer::NodeData::NoNode => Ok(Spanned::new(self.span(), Value::Null)),
757            libyaml_safer::NodeData::Scalar { value, style } => Ok(scalar_node_to_value(
758                // self, path, value, style, document, errors,
759                self, value, style,
760            )),
761            libyaml_safer::NodeData::Mapping { pairs, .. } => mapping_node_to_value(
762                self,
763                path,
764                pairs,
765                // style,
766                document,
767                errors,
768                recursion_limit.saturating_sub(1),
769                jump_limit,
770            ),
771            libyaml_safer::NodeData::Sequence { items, .. } => sequence_node_to_value(
772                self,
773                path,
774                items,
775                // style,
776                document,
777                errors,
778                recursion_limit.saturating_sub(1),
779                jump_limit,
780            ),
781        }?;
782        // check if value is tagged using a non-YAML tag
783        match self.tag.as_deref() {
784            // None
785            // | Some(
786            //     "tag:yaml.org,2002:seq"
787            //     | "tag:yaml.org,2002:map"
788            //     | "tag:yaml.org,2002:str"
789            //     | "tag:yaml.org,2002:int",
790            // ) => value,
791            None => Ok(value),
792            Some(tag) if tag.starts_with("tag:yaml.org,2002:") => Ok(value),
793            Some(tag) => Ok(Spanned::new(
794                self.span(),
795                Value::Tagged(Box::new(TaggedValue {
796                    tag: Tag::new(tag.to_string()),
797                    value,
798                })),
799            )),
800        }
801    }
802}
803
804/// Default maximum recursion depth during parsing.
805///
806/// The default value of 128 is adopted from `serde_yaml`.
807pub const DEFAULT_MAX_RECURSION_DEPTH: usize = 128;
808
809#[derive(Debug, Clone, Copy)]
810pub struct Builder {
811    /// Maximum recursion depth during parsing.
812    pub max_recursion_depth: usize,
813    /// Maximum jump count during parsing.
814    pub jump_limit: Option<usize>,
815}
816
817impl Default for Builder {
818    fn default() -> Self {
819        Self {
820            max_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH,
821            jump_limit: None,
822        }
823    }
824}
825
826impl Builder {
827    pub fn from_document(
828        &self,
829        document: &mut libyaml_safer::Document,
830        errors: &mut Vec<ParseError>,
831    ) -> Result<Spanned<Value>, LimitExceeded> {
832        let Some(root_node) = document.nodes.first() else {
833            return Ok(Spanned::new((&*document).span(), Value::Null));
834        };
835
836        let mut jump_limit = self.jump_limit.unwrap_or(document.nodes.len() * 100);
837        let value = root_node.to_value(
838            "",
839            &*document,
840            errors,
841            self.max_recursion_depth,
842            &mut jump_limit,
843        )?;
844        Ok(value)
845    }
846}
847
848#[cfg(feature = "serde")]
849impl serde::de::IntoDeserializer<'_, crate::error::SerdeError> for Value {
850    type Deserializer = Self;
851
852    fn into_deserializer(self) -> Self::Deserializer {
853        self
854    }
855}
856
857#[cfg(test)]
858mod tests {
859    use crate::{Mapping, Sequence, TaggedValue, Value};
860    use color_eyre::eyre;
861    use indoc::indoc;
862    use similar_asserts::assert_eq as sim_assert_eq;
863
864    #[test]
865    fn test_empty_string() -> eyre::Result<()> {
866        crate::tests::init();
867
868        let yaml = indoc! {"
869            empty:
870            tilde: ~
871        "};
872
873        let value = crate::from_str(yaml)?;
874        sim_assert_eq!(
875            value.clone().cleared_spans().into_inner(),
876            Value::from(Mapping::from_iter([
877                ("empty".into(), Value::Null.into()),
878                ("tilde".into(), Value::Null.into()),
879            ]))
880        );
881
882        #[cfg(feature = "serde")]
883        {
884            #[derive(serde::Deserialize, PartialEq, Debug)]
885            struct Struct {
886                empty: String,
887                tilde: String,
888            }
889
890            let _expected = Struct {
891                empty: String::new(),
892                tilde: "~".to_owned(),
893            };
894            // TODO: cannot deserialize to empty string from NULL
895            // similar_asserts::assert_eq!(crate::from_value::<Struct>(value)?, expected);
896        }
897        Ok(())
898    }
899
900    #[test]
901    fn test_enum_representations() -> eyre::Result<()> {
902        crate::tests::init();
903
904        let yaml = indoc! {"
905            - Unit
906            - 'Unit'
907            - !Unit
908            - !Unit ~
909            - !Unit null
910            - !Tuple [0, 0]
911            - !Tuple
912              - 0
913              - 0
914            - !Struct {x: 0, y: 0}
915            - !Struct
916              x: 0
917              y: 0
918            - !String '...'
919            - !String ...
920            - !Number 0
921        "};
922
923        let value = crate::from_str(yaml)?;
924        similar_asserts::assert_eq!(
925            value.clone().cleared_spans().into_inner(),
926            Value::from(Sequence::from_iter([
927                "Unit".into(),
928                "Unit".into(),
929                TaggedValue::new("Unit", Value::Null).into(),
930                TaggedValue::new("Unit", Value::Null).into(),
931                TaggedValue::new("Unit", Value::Null).into(),
932                TaggedValue::new("Tuple", Sequence::from_iter([0.into(), 0.into()])).into(),
933                TaggedValue::new("Tuple", Sequence::from_iter([0.into(), 0.into()])).into(),
934                TaggedValue::new(
935                    "Struct",
936                    Mapping::from_iter([("x".into(), 0.into()), ("y".into(), 0.into())])
937                )
938                .into(),
939                TaggedValue::new(
940                    "Struct",
941                    Mapping::from_iter([("x".into(), 0.into()), ("y".into(), 0.into())])
942                )
943                .into(),
944                TaggedValue::new("String", "...").into(),
945                TaggedValue::new("String", "...").into(),
946                TaggedValue::new("Number", 0).into(),
947            ]))
948        );
949
950        #[cfg(feature = "serde")]
951        #[derive(serde::Deserialize, PartialEq, Debug)]
952        enum Enum {
953            Unit,
954            Tuple(i32, i32),
955            Struct { x: i32, y: i32 },
956            String(String),
957            Number(f64),
958        }
959
960        #[cfg(feature = "serde")]
961        {
962            let expected = vec![
963                Enum::Unit,
964                Enum::Unit,
965                Enum::Unit,
966                Enum::Unit,
967                Enum::Unit,
968                Enum::Tuple(0, 0),
969                Enum::Tuple(0, 0),
970                Enum::Struct { x: 0, y: 0 },
971                Enum::Struct { x: 0, y: 0 },
972                Enum::String("...".to_owned()),
973                Enum::String("...".to_owned()),
974                Enum::Number(0.0),
975            ];
976
977            sim_assert_eq!(crate::from_value::<Vec<Enum>>(&value)?, expected);
978        }
979
980        let yaml = indoc! {"
981            - !String
982        "};
983
984        let value = crate::from_str(yaml)?;
985        sim_assert_eq!(
986            value.clone().cleared_spans().into_inner(),
987            Value::from(Sequence::from_iter([TaggedValue::new(
988                "String",
989                Value::Null
990            )
991            .into()]))
992        );
993
994        #[cfg(feature = "serde")]
995        {
996            let _expected = [Enum::String(String::new())];
997            // TODO: allow parsing empty string from Value::Null
998            // sim_assert_eq!(crate::from_value::<Vec<Enum>>(value)?, expected);
999        }
1000
1001        Ok(())
1002    }
1003
1004    #[test]
1005    fn test_enum_alias() -> eyre::Result<()> {
1006        crate::tests::init();
1007
1008        let yaml = indoc! {"
1009            aref:
1010              &aref
1011              A
1012            bref:
1013              &bref
1014              !B
1015                - 1
1016                - 2
1017
1018            a: *aref
1019            b: *bref
1020        "};
1021
1022        let value = crate::from_str(yaml)?;
1023        let expected: Value = Mapping::from_iter([
1024            ("aref".into(), "A".into()),
1025            (
1026                "bref".into(),
1027                TaggedValue::new("B", Sequence::from_iter([1.into(), 2.into()])).into(),
1028            ),
1029            ("a".into(), "A".into()),
1030            (
1031                "b".into(),
1032                TaggedValue::new("B", Sequence::from_iter([1.into(), 2.into()])).into(),
1033            ),
1034        ])
1035        .into();
1036        sim_assert_eq!(value.clone().cleared_spans().into_inner(), expected);
1037
1038        #[cfg(feature = "serde")]
1039        {
1040            #[derive(serde::Deserialize, PartialEq, Debug)]
1041            enum E {
1042                A,
1043                B(u8, u8),
1044            }
1045            #[derive(serde::Deserialize, PartialEq, Debug)]
1046            struct Data {
1047                a: E,
1048                b: E,
1049            }
1050
1051            let expected = Data {
1052                a: E::A,
1053                b: E::B(1, 2),
1054            };
1055            sim_assert_eq!(crate::from_value::<Data>(&value)?, expected);
1056        }
1057
1058        Ok(())
1059    }
1060
1061    #[test]
1062    fn test_option_alias() -> eyre::Result<()> {
1063        crate::tests::init();
1064
1065        let yaml = indoc! {"
1066            none_f:
1067              &none_f
1068              ~
1069            none_s:
1070              &none_s
1071              ~
1072            none_b:
1073              &none_b
1074              ~
1075
1076            some_f:
1077              &some_f
1078              1.0
1079            some_s:
1080              &some_s
1081              x
1082            some_b:
1083              &some_b
1084              true
1085
1086            a: *none_f
1087            b: *none_s
1088            c: *none_b
1089            d: *some_f
1090            e: *some_s
1091            f: *some_b
1092        "};
1093
1094        let value = crate::from_str(yaml)?;
1095        let expected: Value = Mapping::from_iter([
1096            ("none_f".into(), Value::Null.into()),
1097            ("none_s".into(), Value::Null.into()),
1098            ("none_b".into(), Value::Null.into()),
1099            ("some_f".into(), 1.0.into()),
1100            ("some_s".into(), "x".into()),
1101            ("some_b".into(), true.into()),
1102            ("a".into(), Value::Null.into()),
1103            ("b".into(), Value::Null.into()),
1104            ("c".into(), Value::Null.into()),
1105            ("d".into(), 1.0.into()),
1106            ("e".into(), "x".into()),
1107            ("f".into(), true.into()),
1108        ])
1109        .into();
1110        sim_assert_eq!(value.clone().cleared_spans().into_inner(), expected);
1111
1112        #[cfg(feature = "serde")]
1113        {
1114            #[derive(serde::Deserialize, PartialEq, Debug)]
1115            struct Data {
1116                a: Option<f64>,
1117                b: Option<String>,
1118                c: Option<bool>,
1119                d: Option<f64>,
1120                e: Option<String>,
1121                f: Option<bool>,
1122            }
1123            let expected = Data {
1124                a: None,
1125                b: None,
1126                c: None,
1127                d: Some(1.0),
1128                e: Some("x".to_owned()),
1129                f: Some(true),
1130            };
1131            sim_assert_eq!(crate::from_value::<Data>(&value)?, expected);
1132        }
1133
1134        Ok(())
1135    }
1136
1137    #[test]
1138    fn test_option() -> eyre::Result<()> {
1139        crate::tests::init();
1140
1141        let yaml = indoc! {"
1142            b:
1143            c: true
1144        "};
1145
1146        let value = crate::from_str(yaml)?;
1147        let expected: Value =
1148            Mapping::from_iter([("b".into(), Value::Null.into()), ("c".into(), true.into())])
1149                .into();
1150        sim_assert_eq!(value.clone().cleared_spans().into_inner(), expected);
1151
1152        #[cfg(feature = "serde")]
1153        {
1154            #[derive(serde::Deserialize, PartialEq, Debug)]
1155            struct Data {
1156                a: Option<f64>,
1157                b: Option<String>,
1158                c: Option<bool>,
1159            }
1160            let expected = Data {
1161                a: None,
1162                b: None,
1163                c: Some(true),
1164            };
1165            sim_assert_eq!(crate::from_value::<Data>(&value)?, expected);
1166        }
1167        Ok(())
1168    }
1169
1170    #[test]
1171    fn test_alias() -> eyre::Result<()> {
1172        crate::tests::init();
1173
1174        let yaml = indoc! {"
1175            first:
1176              &alias
1177              1
1178            second:
1179              *alias
1180            third: 3
1181        "};
1182
1183        let value = crate::from_str(yaml)?;
1184        let expected: Value = Mapping::from_iter([
1185            ("first".into(), 1.into()),
1186            ("second".into(), 1.into()),
1187            ("third".into(), 3.into()),
1188        ])
1189        .into();
1190        sim_assert_eq!(value.clone().cleared_spans().into_inner(), expected);
1191
1192        #[cfg(feature = "serde")]
1193        {
1194            use std::collections::BTreeMap;
1195
1196            let mut expected = BTreeMap::new();
1197            expected.insert("first".to_owned(), 1);
1198            expected.insert("second".to_owned(), 1);
1199            expected.insert("third".to_owned(), 3);
1200
1201            sim_assert_eq!(crate::from_value::<BTreeMap<_, _>>(&value)?, expected);
1202        }
1203
1204        Ok(())
1205    }
1206
1207    #[test]
1208    fn test_borrowed() -> eyre::Result<()> {
1209        crate::tests::init();
1210
1211        let yaml = indoc! {"
1212            - plain nonàscii
1213            - 'single quoted'
1214            - \"double quoted\"
1215        "};
1216
1217        let value = crate::from_str(yaml)?;
1218        let expected: Value = Sequence::from_iter([
1219            "plain nonàscii".into(),
1220            "single quoted".into(),
1221            "double quoted".into(),
1222        ])
1223        .into();
1224        sim_assert_eq!(value.clone().cleared_spans().into_inner(), expected);
1225
1226        #[cfg(feature = "serde")]
1227        {
1228            let _expected = ["plain nonàscii", "single quoted", "double quoted"];
1229            // TODO: cannot deserialize borrowed as we first allocate value
1230            // sim_assert_eq!(crate::from_value::<Vec<&str>>(value)?, expected);
1231        }
1232
1233        Ok(())
1234    }
1235
1236    #[cfg(feature = "serde")]
1237    #[test]
1238    fn test_into_deserializer() -> eyre::Result<()> {
1239        crate::tests::init();
1240
1241        use serde::{Deserialize, de::IntoDeserializer};
1242
1243        #[derive(Debug, serde::Deserialize, PartialEq)]
1244        struct Test {
1245            first: String,
1246            second: u32,
1247        }
1248
1249        let value = crate::from_str("xyz")?;
1250        dbg!(&value);
1251        let s = String::deserialize(value.into_deserializer())?;
1252        sim_assert_eq!(s, "xyz");
1253
1254        let yaml = "- first\n- second\n- third";
1255        dbg!(&yaml);
1256        let value = crate::from_str(yaml)?;
1257        dbg!(&value);
1258        let arr = Vec::<String>::deserialize(value.into_deserializer())?;
1259        sim_assert_eq!(arr, &["first", "second", "third"]);
1260
1261        let value = crate::from_str("first: abc\nsecond: 99")?;
1262        let test = Test::deserialize(value.into_deserializer())?;
1263
1264        sim_assert_eq!(
1265            test,
1266            Test {
1267                first: "abc".to_string(),
1268                second: 99
1269            }
1270        );
1271        Ok(())
1272    }
1273
1274    #[test]
1275    fn test_merge() -> eyre::Result<()> {
1276        crate::tests::init();
1277
1278        // From https://yaml.org/type/merge.html.
1279        let yaml = indoc! {"
1280            ---
1281            - &CENTER { x: 1, y: 2 }
1282            - &LEFT { x: 0, y: 2 }
1283            - &BIG { r: 10 }
1284            - &SMALL { r: 1 }
1285
1286            # All the following maps are equal:
1287
1288            - # Explicit keys
1289              x: 1
1290              y: 2
1291              r: 10
1292              label: center/big
1293
1294            - # Merge one map
1295              << : *CENTER
1296              r: 10
1297              label: center/big
1298
1299            - # Merge multiple maps
1300              << : [ *CENTER, *BIG ]
1301              label: center/big
1302
1303            - # Override
1304              << : [ *BIG, *LEFT, *SMALL ]
1305              x: 1
1306              label: center/big
1307        "};
1308
1309        let mut value = crate::from_str(yaml)?;
1310        value.apply_merge()?;
1311        for i in 5..=7 {
1312            sim_assert_eq!(value[4], value[i]);
1313        }
1314        Ok(())
1315    }
1316
1317    #[test]
1318    fn test_display() -> eyre::Result<()> {
1319        crate::tests::init();
1320
1321        let yaml = indoc! {"
1322            'Null': ~
1323            Bool: true
1324            Number: 1
1325            String: ...
1326            Sequence:
1327              - true
1328            EmptySequence: []
1329            EmptyMapping: {}
1330            Tagged: !tag true
1331        "};
1332
1333        let value = crate::from_str(yaml)?;
1334        let display = format!("{value}");
1335        println!("{display}");
1336
1337        let _expected = indoc! {r#"
1338            Mapping {
1339                "Null": Null,
1340                "Bool": Bool(true),
1341                "Number": Number(1),
1342                "String": String("..."),
1343                "Sequence": Sequence [
1344                    Bool(true),
1345                ],
1346                "EmptySequence": Sequence [],
1347                "EmptyMapping": Mapping {},
1348                "Tagged": TaggedValue {
1349                    tag: !tag,
1350                    value: Bool(true),
1351                },
1352            }"#
1353        };
1354        let expected = r#"{"Null": NULL, "Bool": Bool(true), "Number": Number(1), "String": String(...), "Sequence": [Bool(true)], "EmptySequence": [], "EmptyMapping": {}, "Tagged": Bool(true)}"#;
1355        sim_assert_eq!(display, expected);
1356        Ok(())
1357    }
1358
1359    #[test]
1360    fn test_debug() -> eyre::Result<()> {
1361        crate::tests::init();
1362
1363        let yaml = indoc! {"
1364            'Null': ~
1365            Bool: true
1366            Number: 1
1367            String: ...
1368            Sequence:
1369              - true
1370            EmptySequence: []
1371            EmptyMapping: {}
1372            Tagged: !tag true
1373        "};
1374
1375        let value = crate::from_str(yaml)?;
1376        let debug = format!("{value:#?}");
1377        println!("{debug}");
1378
1379        let expected = indoc! {r#"
1380            Spanned {
1381                span: L0:0 - L9:0,
1382                inner: Mapping(
1383                    {
1384                        Spanned {
1385                            span: L0:0 - L0:6,
1386                            inner: String("Null"),
1387                        }: Spanned {
1388                            span: L0:8 - L0:9,
1389                            inner: NULL,
1390                        },
1391                        Spanned {
1392                            span: L1:0 - L1:4,
1393                            inner: String("Bool"),
1394                        }: Spanned {
1395                            span: L1:6 - L1:10,
1396                            inner: Bool(true),
1397                        },
1398                        Spanned {
1399                            span: L2:0 - L2:6,
1400                            inner: String("Number"),
1401                        }: Spanned {
1402                            span: L2:8 - L2:9,
1403                            inner: Number(UnsignedInt(1)),
1404                        },
1405                        Spanned {
1406                            span: L3:0 - L3:6,
1407                            inner: String("String"),
1408                        }: Spanned {
1409                            span: L3:8 - L3:11,
1410                            inner: String("..."),
1411                        },
1412                        Spanned {
1413                            span: L4:0 - L4:8,
1414                            inner: String("Sequence"),
1415                        }: Spanned {
1416                            span: L5:2 - L6:0,
1417                            inner: [
1418                                Spanned {
1419                                    span: L5:4 - L5:8,
1420                                    inner: Bool(true),
1421                                },
1422                            ],
1423                        },
1424                        Spanned {
1425                            span: L6:0 - L6:13,
1426                            inner: String("EmptySequence"),
1427                        }: Spanned {
1428                            span: L6:15 - L6:17,
1429                            inner: [],
1430                        },
1431                        Spanned {
1432                            span: L7:0 - L7:12,
1433                            inner: String("EmptyMapping"),
1434                        }: Spanned {
1435                            span: L7:14 - L7:16,
1436                            inner: Mapping(
1437                                {},
1438                            ),
1439                        },
1440                        Spanned {
1441                            span: L8:0 - L8:6,
1442                            inner: String("Tagged"),
1443                        }: Spanned {
1444                            span: L8:8 - L8:17,
1445                            inner: TaggedValue {
1446                                tag: !tag,
1447                                value: Spanned {
1448                                    span: L8:8 - L8:17,
1449                                    inner: Bool(true),
1450                                },
1451                            },
1452                        },
1453                    },
1454                ),
1455            }"#
1456        };
1457        sim_assert_eq!(debug, expected);
1458        Ok(())
1459    }
1460
1461    #[ignore = "serialization of struct to value not supported"]
1462    #[test]
1463    fn test_tagged() -> eyre::Result<()> {
1464        crate::tests::init();
1465
1466        // #[derive(serde::Serialize)]
1467        // enum Enum {
1468        //     Variant(usize),
1469        // }
1470        //
1471        // let value = crate::to_value(&Enum::Variant(0))?;
1472        //
1473        // let deserialized: Value = serde_yaml::from_value(value.clone())?;
1474        // sim_assert_eq!(value, deserialized);
1475        //
1476        // let serialized = crate::to_value(&value)?;
1477        // sim_assert_eq!(value, serialized);
1478        Ok(())
1479    }
1480
1481    #[test]
1482    fn test_two_documents() -> eyre::Result<()> {
1483        crate::tests::init();
1484
1485        let yaml = indoc! {"
1486            ---
1487            0
1488            ---
1489            1
1490        "};
1491
1492        let values: Vec<Value> = crate::from_str_all(yaml)?
1493            .into_iter()
1494            .map(|doc| doc.cleared_spans().into_inner())
1495            .collect();
1496        let expected: Vec<Value> = vec![0.into(), 1.into()];
1497        sim_assert_eq!(values, expected);
1498        Ok(())
1499    }
1500}