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#[derive(Clone, PartialEq, PartialOrd)]
30pub enum Value {
31 Null,
33 Bool(bool),
35 Number(Number),
37 String(String),
39 Sequence(Sequence),
41 Mapping(Mapping),
43 Tagged(Box<TaggedValue>),
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub enum Kind {
51 Null,
53 Bool,
55 Number,
57 String,
59 Sequence,
61 Mapping,
63 Tagged,
65}
66
67impl 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 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 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
512impl 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 value: &str,
566 style: &libyaml_safer::ScalarStyle,
567 ) -> Value {
570 match style {
571 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 _ => {
593 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 value: &str,
626 style: &libyaml_safer::ScalarStyle,
627 ) -> 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 }
637 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 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 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 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 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 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, value, style,
760 )),
761 libyaml_safer::NodeData::Mapping { pairs, .. } => mapping_node_to_value(
762 self,
763 path,
764 pairs,
765 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 document,
777 errors,
778 recursion_limit.saturating_sub(1),
779 jump_limit,
780 ),
781 }?;
782 match self.tag.as_deref() {
784 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
804pub const DEFAULT_MAX_RECURSION_DEPTH: usize = 128;
808
809#[derive(Debug, Clone, Copy)]
810pub struct Builder {
811 pub max_recursion_depth: usize,
813 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 }
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 }
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 }
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 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 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}