1use crate::{
8 error::{ErrorKind, ScanError},
9 input::{str::StrInput, BorrowedInput},
10 scanner::{Marker, QueuedToken, QueuedTokenType, ScalarStyle, Scanner, Span},
11 BufferedInput, FallibleBufferedInput, Options,
12};
13
14#[cfg(feature = "comments")]
15use crate::scanner::Placement;
16#[cfg(feature = "comments")]
17use alloc::collections::VecDeque;
18use alloc::{
19 borrow::Cow,
20 collections::{BTreeMap, BTreeSet},
21 string::String,
22 vec::Vec,
23};
24use core::{
25 convert::Infallible,
26 fmt::{self, Display},
27};
28
29#[derive(Clone, Copy, PartialEq, Debug, Eq)]
30enum State {
31 StreamStart,
32 ImplicitDocumentStart,
33 DocumentStart,
34 DocumentContent,
35 DocumentEnd,
36 BlockNode,
37 BlockNodeOrIndentlessSequence,
38 FlowNode,
39 BlockSequenceFirstEntry,
40 BlockSequenceEntry,
41 IndentlessSequenceEntry,
42 IndentlessSequenceEntryNode,
43 BlockMappingFirstKey,
44 BlockMappingKey,
45 #[cfg(feature = "comments")]
46 BlockMappingKeyNode,
47 BlockMappingValue,
48 #[cfg(feature = "comments")]
49 BlockMappingValueNode,
50 FlowSequenceFirstEntry,
51 FlowSequenceEntry,
52 FlowSequenceEntryMappingKey,
53 FlowSequenceEntryMappingValue,
54 #[cfg(feature = "comments")]
55 FlowSequenceEntryMappingValueNode,
56 FlowSequenceEntryMappingEnd,
57 FlowMappingFirstKey,
58 FlowMappingKey,
59 #[cfg(feature = "comments")]
60 FlowMappingKeyNode,
61 FlowMappingValue,
62 #[cfg(feature = "comments")]
63 FlowMappingValueNode,
64 FlowMappingEmptyValue,
65 #[cfg(feature = "comments")]
66 BlockSequenceEntryNode,
67 End,
68}
69
70#[derive(Copy, Clone, PartialEq, Debug, Eq, Hash)]
72pub struct YamlVersion {
73 pub major: u32,
75 pub minor: u32,
77}
78
79impl YamlVersion {
80 #[must_use]
82 pub const fn new(major: u32, minor: u32) -> Self {
83 Self { major, minor }
84 }
85}
86
87#[non_exhaustive]
92#[derive(Clone, PartialEq, Debug, Eq)]
93pub enum Event<'input> {
94 StreamStart,
96 StreamEnd,
98 DocumentStart(
101 bool,
105 Option<YamlVersion>,
107 ),
108 DocumentEnd,
113 Alias(
119 usize,
121 ),
122 Anchor(
139 usize,
141 Cow<'input, str>,
143 ),
144 UnresolvedAlias(
150 Cow<'input, str>,
152 ),
153 #[cfg(feature = "comments")]
160 Comment(
161 Cow<'input, str>,
163 Placement,
165 ),
166 Scalar(
168 Cow<'input, str>,
170 ScalarStyle,
172 usize,
174 Option<Cow<'input, Tag>>,
176 ),
177 SequenceStart(
179 StructureStyle,
181 usize,
183 Option<Cow<'input, Tag>>,
185 ),
186 SequenceEnd,
188 MappingStart(
190 StructureStyle,
192 usize,
194 Option<Cow<'input, Tag>>,
196 ),
197 MappingEnd,
199}
200
201#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
221pub enum StructureStyle {
222 Block,
224 Flow,
226}
227
228#[derive(Clone, PartialEq, Debug, Eq, Ord, PartialOrd, Hash)]
230pub struct Tag {
231 handle: Cow<'static, str>,
235 suffix: Cow<'static, str>,
237 original_handle: Cow<'static, str>,
243}
244
245const YAML_CORE_SCHEMA_PREFIX: &str = "tag:yaml.org,2002:";
246
247const YAML_CORE_SCHEMA_SUFFIXES: [&str; 7] = ["bool", "float", "int", "map", "null", "seq", "str"];
254
255fn known_yaml_core_schema_suffix(suffix: &str) -> Option<&str> {
256 YAML_CORE_SCHEMA_SUFFIXES
257 .contains(&suffix)
258 .then_some(suffix)
259}
260
261fn known_yaml_core_schema_suffix_from_split(
262 handle_tail: &str,
263 suffix: &str,
264) -> Option<&'static str> {
265 YAML_CORE_SCHEMA_SUFFIXES.iter().copied().find(|candidate| {
266 candidate
267 .strip_prefix(handle_tail)
268 .is_some_and(|candidate_tail| candidate_tail == suffix)
269 })
270}
271
272fn own_tag_component(component: Cow<'_, str>) -> Cow<'static, str> {
274 let known = match component.as_ref() {
275 "" => "",
276 "!" => "!",
277 "!!" => "!!",
278 "tag:yaml.org,2002:" => YAML_CORE_SCHEMA_PREFIX,
279 "bool" => "bool",
280 "float" => "float",
281 "int" => "int",
282 "map" => "map",
283 "null" => "null",
284 "seq" => "seq",
285 "str" => "str",
286 _ => return Cow::Owned(component.into_owned()),
287 };
288 Cow::Borrowed(known)
289}
290
291impl Tag {
292 #[must_use]
297 pub fn new(handle: impl Into<String>, suffix: impl Into<String>) -> Self {
298 let handle = handle.into();
299 Self {
300 original_handle: Cow::Owned(handle.clone()),
301 handle: Cow::Owned(handle),
302 suffix: Cow::Owned(suffix.into()),
303 }
304 }
305
306 #[must_use]
308 pub fn with_original_handle(
309 handle: impl Into<String>,
310 suffix: impl Into<String>,
311 original_handle: impl Into<String>,
312 ) -> Self {
313 Self {
314 handle: Cow::Owned(handle.into()),
315 suffix: Cow::Owned(suffix.into()),
316 original_handle: Cow::Owned(original_handle.into()),
317 }
318 }
319
320 #[must_use]
322 pub fn handle(&self) -> &str {
323 &self.handle
324 }
325
326 #[must_use]
328 pub fn suffix(&self) -> &str {
329 &self.suffix
330 }
331
332 #[must_use]
334 pub fn original_handle(&self) -> &str {
335 &self.original_handle
336 }
337
338 #[must_use]
347 pub fn core_suffix(&self) -> Option<&str> {
348 if let Some(remaining_prefix) = YAML_CORE_SCHEMA_PREFIX.strip_prefix(self.handle.as_ref()) {
351 let suffix = self.suffix.strip_prefix(remaining_prefix)?;
352 return known_yaml_core_schema_suffix(suffix);
353 }
354
355 let handle_tail = self.handle.strip_prefix(YAML_CORE_SCHEMA_PREFIX)?;
359 known_yaml_core_schema_suffix_from_split(handle_tail, &self.suffix)
360 }
361
362 #[must_use]
371 pub fn suffix_in_namespace(&self, prefix: &str) -> Option<Cow<'_, str>> {
372 if let Some(handle_tail) = self.handle.strip_prefix(prefix) {
373 return Some(if handle_tail.is_empty() {
376 Cow::Borrowed(self.suffix.as_ref())
377 } else {
378 let mut name = String::with_capacity(handle_tail.len() + self.suffix.len());
379 name.push_str(handle_tail);
380 name.push_str(&self.suffix);
381 Cow::Owned(name)
382 });
383 }
384
385 prefix
388 .strip_prefix(self.handle.as_ref())
389 .and_then(|prefix_tail| self.suffix.strip_prefix(prefix_tail))
390 .map(Cow::Borrowed)
391 }
392
393 #[must_use]
403 pub fn is_yaml_core_schema(&self) -> bool {
404 self.core_suffix().is_some()
405 }
406
407 #[must_use]
412 pub fn is_yaml_core_schema_tag(&self, suffix: &str) -> bool {
413 self.core_suffix()
414 .is_some_and(|core_suffix| core_suffix == suffix)
415 }
416
417 #[must_use]
423 pub fn is_custom(&self) -> bool {
424 !self.is_yaml_core_schema()
425 }
426
427 #[must_use]
429 pub fn parts(&self) -> (&str, &str) {
430 (&self.handle, &self.suffix)
431 }
432
433 #[must_use]
438 pub fn original_parts(&self) -> (&str, &str) {
439 (&self.original_handle, &self.suffix)
440 }
441
442 #[must_use]
448 pub fn original(&self) -> String {
449 if self.original_handle.is_empty() && self.suffix != "!" {
450 let mut tag = String::with_capacity(self.suffix.len() + 3);
451 tag.push_str("!<");
452 tag.push_str(&self.suffix);
453 tag.push('>');
454 return tag;
455 }
456
457 let mut tag = String::with_capacity(self.original_handle.len() + self.suffix.len());
458 tag.push_str(&self.original_handle);
459 tag.push_str(&self.suffix);
460 tag
461 }
462}
463
464impl Display for Tag {
465 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
466 if self.handle == "!" {
467 write!(f, "!{}", self.suffix)
468 } else {
469 write!(f, "{}{}", self.handle, self.suffix)
470 }
471 }
472}
473
474impl<'input> Event<'input> {
475 #[must_use]
485 pub fn anchor_id(&self) -> Option<usize> {
486 match self {
487 Self::Scalar(_, _, anchor_id, _)
488 | Self::SequenceStart(_, anchor_id, _)
489 | Self::MappingStart(_, anchor_id, _)
490 | Self::Anchor(anchor_id, _)
491 if *anchor_id != 0 =>
492 {
493 Some(*anchor_id)
494 }
495 _ => None,
496 }
497 }
498
499 #[must_use]
504 pub fn alias_id(&self) -> Option<usize> {
505 match self {
506 Self::Alias(anchor_id) => Some(*anchor_id),
507 _ => None,
508 }
509 }
510
511 #[must_use]
513 pub fn is_alias(&self) -> bool {
514 matches!(self, Self::Alias(_) | Self::UnresolvedAlias(_))
515 }
516
517 #[must_use]
519 pub fn tag(&self) -> Option<&Tag> {
520 match self {
521 Self::Scalar(_, _, _, tag)
522 | Self::SequenceStart(_, _, tag)
523 | Self::MappingStart(_, _, tag) => tag.as_deref(),
524 _ => None,
525 }
526 }
527
528 #[must_use]
530 pub fn scalar(&self) -> Option<(&str, ScalarStyle)> {
531 match self {
532 Self::Scalar(value, style, _, _) => Some((value.as_ref(), *style)),
533 _ => None,
534 }
535 }
536
537 #[must_use]
543 pub fn is_node(&self) -> bool {
544 matches!(
545 self,
546 Self::Alias(_)
547 | Self::UnresolvedAlias(_)
548 | Self::Scalar(..)
549 | Self::SequenceStart(..)
550 | Self::MappingStart(..)
551 )
552 }
553
554 fn empty_scalar() -> Self {
556 Event::Scalar("~".into(), ScalarStyle::Plain, 0, None)
558 }
559
560 fn empty_scalar_with_anchor(anchor: usize, tag: Option<Cow<'input, Tag>>) -> Self {
562 let value = if tag.is_some() {
563 Cow::default()
564 } else {
565 "~".into()
566 };
567
568 Event::Scalar(value, ScalarStyle::Plain, anchor, tag)
569 }
570}
571
572#[derive(Debug)]
574struct PendingAnchor<'input> {
575 id: usize,
576 name: Cow<'input, str>,
577 span: Span,
578 node_emitted: bool,
579}
580
581#[derive(Debug)]
583#[allow(clippy::struct_excessive_bools)] pub struct Parser<'input, T: BorrowedInput<'input>> {
585 scanner: Scanner<'input, T>,
587 emit_unresolved_aliases: bool,
589 emit_anchor_events: bool,
591 pending_anchor: Option<PendingAnchor<'input>>,
593 #[cfg(feature = "comments")]
595 max_buffered_comment_events: usize,
596 block_nesting_limit: usize,
598 block_level: usize,
600 states: Vec<State>,
605 state: State,
607 token: Option<QueuedToken<'input>>,
609 current: Option<(Event<'input>, Span)>,
611 current_error: Option<ScanError>,
613 #[cfg(feature = "comments")]
619 deferred_error: Option<ScanError>,
620 #[cfg(feature = "comments")]
622 queued_events: VecDeque<(Event<'input>, Span)>,
623 #[cfg(feature = "comments")]
625 comment_scratch: Vec<(Event<'input>, Span)>,
626
627 pending_key_indent: Option<usize>,
633 #[cfg(feature = "comments")]
636 pending_node_anchor_id: Option<usize>,
637 #[cfg(feature = "comments")]
639 pending_node_tag: Option<Cow<'input, Tag>>,
640 #[cfg(feature = "comments")]
642 pending_node_tag_span: Option<(Marker, u32)>,
643 #[cfg(feature = "comments")]
645 pending_node_property_end: Option<Marker>,
646 pending_empty_scalar_span: Option<Span>,
648 last_non_comment_event_end: Option<Marker>,
652 #[cfg(feature = "comments")]
654 pending_document_version: Option<YamlVersion>,
655 #[cfg(feature = "comments")]
657 pending_document_directives: bool,
658 #[cfg(feature = "comments")]
660 pending_document_tag_handles: BTreeSet<Cow<'input, str>>,
661 anchors: BTreeMap<Cow<'input, str>, usize>,
663 anchor_id_count: usize,
668 tags: BTreeMap<Cow<'input, str>, Cow<'input, str>>,
672 stream_end_emitted: bool,
679 failed: bool,
681 at_document_end: bool,
683 keep_tags: bool,
685}
686
687pub trait EventReceiver<'input> {
770 fn on_event(&mut self, ev: Event<'input>);
772}
773
774pub trait SpannedEventReceiver<'input> {
779 fn on_event(&mut self, ev: Event<'input>, span: Span);
781}
782
783impl<'input, R: EventReceiver<'input>> SpannedEventReceiver<'input> for R {
784 fn on_event(&mut self, ev: Event<'input>, _span: Span) {
785 self.on_event(ev);
786 }
787}
788
789pub trait TryEventReceiver<'input> {
794 type Error;
796
797 fn on_event(&mut self, ev: Event<'input>) -> Result<(), Self::Error>;
804}
805
806pub trait TrySpannedEventReceiver<'input> {
812 type Error;
814
815 fn on_event(&mut self, ev: Event<'input>, span: Span) -> Result<(), Self::Error>;
822}
823
824impl<'input, R: TryEventReceiver<'input>> TrySpannedEventReceiver<'input> for R {
825 type Error = R::Error;
826
827 fn on_event(&mut self, ev: Event<'input>, _span: Span) -> Result<(), Self::Error> {
828 TryEventReceiver::on_event(self, ev)
829 }
830}
831
832#[derive(Clone, PartialEq, Debug, Eq)]
834pub enum TryLoadError<E> {
835 Scan(
837 ScanError,
839 ),
840 Receiver(
842 E,
844 ),
845}
846
847impl<E> TryLoadError<E> {
848 #[cold]
849 fn scan(error: ScanError) -> Self {
850 Self::Scan(error)
851 }
852
853 #[cold]
854 fn receiver(error: E) -> Self {
855 Self::Receiver(error)
856 }
857}
858
859impl<E> From<ScanError> for TryLoadError<E> {
860 #[cold]
861 fn from(error: ScanError) -> Self {
862 Self::scan(error)
863 }
864}
865
866impl<E: Display> Display for TryLoadError<E> {
867 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
868 match self {
869 Self::Scan(error) => write!(f, "parser error: {error}"),
870 Self::Receiver(error) => write!(f, "receiver error: {error}"),
871 }
872 }
873}
874
875impl<E> core::error::Error for TryLoadError<E>
876where
877 E: core::error::Error + 'static,
878{
879 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
880 match self {
881 Self::Scan(error) => Some(error),
882 Self::Receiver(error) => Some(error),
883 }
884 }
885}
886
887fn try_emit<'input, R>(
888 recv: &mut R,
889 ev: Event<'input>,
890 span: Span,
891) -> Result<(), TryLoadError<R::Error>>
892where
893 R: TrySpannedEventReceiver<'input>,
894{
895 recv.on_event(ev, span).map_err(TryLoadError::receiver)
896}
897
898struct InfallibleSpannedReceiver<'receiver, R>(&'receiver mut R);
899
900impl<'input, R: SpannedEventReceiver<'input>> TrySpannedEventReceiver<'input>
901 for InfallibleSpannedReceiver<'_, R>
902{
903 type Error = Infallible;
904
905 fn on_event(&mut self, ev: Event<'input>, span: Span) -> Result<(), Self::Error> {
906 self.0.on_event(ev, span);
907 Ok(())
908 }
909}
910
911fn into_scan_result(result: Result<(), TryLoadError<Infallible>>) -> Result<(), ScanError> {
912 match result {
913 Ok(()) => Ok(()),
914 Err(TryLoadError::Scan(error)) => error.into_result(),
915 Err(TryLoadError::Receiver(error)) => match error {},
916 }
917}
918
919pub type ParseResult<'input> = Result<(Event<'input>, Span), ScanError>;
921
922pub trait ParserTrait<'input> {
924 fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>>;
926
927 fn next_event(&mut self) -> Option<ParseResult<'input>>;
929
930 fn load<R: SpannedEventReceiver<'input>>(
944 &mut self,
945 recv: &mut R,
946 multi: bool,
947 ) -> Result<(), ScanError>;
948
949 fn try_load<R: TrySpannedEventReceiver<'input>>(
965 &mut self,
966 recv: &mut R,
967 multi: bool,
968 ) -> Result<(), TryLoadError<R::Error>> {
969 while let Some(res) = self.next_event() {
970 let (ev, span) = res?;
971 let is_doc_end = matches!(ev, Event::DocumentEnd);
972 let is_stream_end = matches!(ev, Event::StreamEnd);
973
974 try_emit(recv, ev, span)?;
975
976 if is_stream_end {
977 break;
978 }
979 if !multi && is_doc_end {
980 break;
981 }
982 }
983
984 Ok(())
985 }
986}
987
988impl<'input> Parser<'input, StrInput<'input>> {
989 #[must_use]
1001 pub fn new_from_str(value: &'input str) -> Self {
1002 Self::new_from_str_with_options(value, Options::default())
1003 }
1004
1005 #[must_use]
1010 pub fn new_from_str_with_options(value: &'input str, options: Options) -> Self {
1011 Parser::with_options(StrInput::new(value), options)
1012 }
1013}
1014
1015impl<T> Parser<'static, BufferedInput<T>>
1016where
1017 T: Iterator<Item = char>,
1018{
1019 #[must_use]
1021 pub fn new_from_iter(iter: T) -> Self {
1022 Self::new_from_iter_with_options(iter, Options::default())
1023 }
1024
1025 #[must_use]
1028 pub fn new_from_iter_with_options(iter: T, options: Options) -> Self {
1029 Parser::with_options(BufferedInput::new(iter), options)
1030 }
1031}
1032
1033impl<T> Parser<'static, FallibleBufferedInput<T>>
1034where
1035 T: Iterator<Item = Result<char, ErrorKind>>,
1036{
1037 #[must_use]
1043 pub fn new_from_fallible_iter(iter: T) -> Self {
1044 Self::new_from_fallible_iter_with_options(iter, Options::default())
1045 }
1046
1047 #[must_use]
1054 pub fn new_from_fallible_iter_with_options(iter: T, options: Options) -> Self {
1055 Parser::with_options(FallibleBufferedInput::new(iter), options)
1056 }
1057}
1058
1059impl<'input, T: BorrowedInput<'input>> Parser<'input, T> {
1060 #[must_use]
1062 pub fn anchor_offset(&self) -> usize {
1063 self.anchor_id_count
1064 }
1065
1066 pub fn set_anchor_offset(&mut self, offset: usize) {
1068 self.anchor_id_count = offset;
1069 }
1070
1071 #[must_use]
1073 pub fn new(src: T) -> Self {
1074 Self::with_options(src, Options::default())
1075 }
1076
1077 #[must_use]
1084 pub fn with_options(src: T, options: Options) -> Self {
1085 #[cfg(feature = "comments")]
1086 let max_buffered_comment_events = options.max_buffered_comment_events;
1087 let block_nesting_limit = options.block_nesting_limit;
1088 let emit_unresolved_aliases = options.emit_unresolved_aliases;
1089 let emit_anchor_events = options.emit_anchor_events;
1090 let scanner = Scanner::with_options(src, options);
1091
1092 Parser {
1093 scanner,
1094 emit_unresolved_aliases,
1095 emit_anchor_events,
1096 pending_anchor: None,
1097 #[cfg(feature = "comments")]
1098 max_buffered_comment_events,
1099 block_nesting_limit,
1100 block_level: 0,
1101 states: Vec::new(),
1102 state: State::StreamStart,
1103 token: None,
1104 current: None,
1105 current_error: None,
1106 #[cfg(feature = "comments")]
1107 deferred_error: None,
1108 #[cfg(feature = "comments")]
1109 queued_events: VecDeque::new(),
1110 #[cfg(feature = "comments")]
1111 comment_scratch: Vec::new(),
1112
1113 pending_key_indent: None,
1114 #[cfg(feature = "comments")]
1115 pending_node_anchor_id: None,
1116 #[cfg(feature = "comments")]
1117 pending_node_tag: None,
1118 #[cfg(feature = "comments")]
1119 pending_node_tag_span: None,
1120 #[cfg(feature = "comments")]
1121 pending_node_property_end: None,
1122 pending_empty_scalar_span: None,
1123 last_non_comment_event_end: None,
1124 #[cfg(feature = "comments")]
1125 pending_document_version: None,
1126 #[cfg(feature = "comments")]
1127 pending_document_directives: false,
1128 #[cfg(feature = "comments")]
1129 pending_document_tag_handles: BTreeSet::new(),
1130
1131 anchors: BTreeMap::new(),
1132 anchor_id_count: 1,
1134 tags: BTreeMap::new(),
1135 stream_end_emitted: false,
1136 failed: false,
1137 at_document_end: false,
1138 keep_tags: false,
1139 }
1140 }
1141
1142 #[must_use]
1165 pub fn keep_tags(mut self, value: bool) -> Self {
1166 self.keep_tags = value;
1167 self
1168 }
1169
1170 pub fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>> {
1180 ParserTrait::peek(self)
1181 }
1182
1183 pub fn next_event(&mut self) -> Option<ParseResult<'input>> {
1191 ParserTrait::next_event(self)
1192 }
1193
1194 pub fn proceed_next_document(&mut self) -> Result<bool, ScanError> {
1254 if self.stream_end_emitted && !self.failed {
1256 return Ok(false);
1257 }
1258
1259 self.skip_document()?;
1260 let result = self.next_document_exists();
1261 match result {
1262 Ok(false) => {
1263 self.at_document_end = true;
1266 }
1267 Err(_) => {
1268 self.current = None;
1269 self.current_error = None;
1270 #[cfg(feature = "comments")]
1271 {
1272 self.queued_events.clear();
1273 self.comment_scratch.clear();
1274 self.deferred_error = None;
1275 }
1276 self.failed = true;
1277 self.stream_end_emitted = true;
1278 }
1279 Ok(true) => {}
1280 }
1281 result
1282 }
1283
1284 fn skip_document(&mut self) -> Result<(), ScanError> {
1285 loop {
1286 if !self.failed {
1287 if self.at_document_end {
1288 if matches!(self.current, Some((Event::DocumentEnd, _))) {
1291 self.current = None;
1292 }
1293 self.at_document_end = false;
1294 return Ok(());
1295 }
1296 loop {
1299 match self.next_event_impl() {
1300 Ok((Event::DocumentEnd, _)) => {
1301 self.at_document_end = false;
1302 return Ok(());
1303 }
1304 Ok(event @ (Event::StreamEnd, _)) => {
1305 self.current = Some(event);
1307 return Ok(());
1308 }
1309 Ok(_) => {}
1310 Err(_) => break,
1311 }
1312 }
1313 }
1314
1315 let failed_header = matches!(
1318 self.state,
1319 State::ImplicitDocumentStart | State::DocumentStart
1320 ) && self.scanner.in_directive_prefix();
1321 self.recover_document()?;
1324 if !failed_header || !matches!(self.peek_token()?.1, QueuedTokenType::DocumentStart) {
1325 return Ok(());
1326 }
1327 }
1329 }
1330
1331 fn next_document_exists(&mut self) -> Result<bool, ScanError> {
1333 if matches!(self.current, Some((Event::StreamEnd, _))) {
1334 return Ok(false);
1335 }
1336
1337 #[cfg(feature = "comments")]
1338 if self.has_pending_document_directives() {
1339 self.scanner.check_source_error()?;
1342 return Ok(true);
1343 }
1344
1345 loop {
1346 let token = match self.peek_token() {
1347 Ok(token) => token,
1348 Err(error) => {
1349 self.scanner.check_source_error()?;
1352 #[cfg(feature = "comments")]
1353 {
1354 self.deferred_error = Some(error);
1355 }
1356 #[cfg(not(feature = "comments"))]
1357 {
1358 self.current_error = Some(error);
1359 self.failed = true;
1360 }
1361 return Ok(true);
1362 }
1363 };
1364 match token.1 {
1365 QueuedTokenType::StreamEnd => return Ok(false),
1366 QueuedTokenType::DocumentEnd => self.skip(),
1367 #[cfg(feature = "comments")]
1368 QueuedTokenType::Comment(_) => {
1369 let mark = token.0.start;
1370 if self.queued_events.len() >= self.max_buffered_comment_events {
1371 return Err(ScanError::from_kind(mark, ErrorKind::TooManyComments));
1372 }
1373 let comment = self
1374 .next_comment_event()?
1375 .expect("comment token disappeared after peek");
1376 self.queued_events.push_back(comment);
1377 }
1378 _ => return Ok(true),
1379 }
1380 }
1381 }
1382
1383 fn recover_document(&mut self) -> Result<(), ScanError> {
1384 let result = self.scanner.proceed_next_document(self.token.take());
1385 self.current = None;
1386 self.current_error = None;
1387 self.pending_anchor = None;
1388 if let Err(error) = result {
1389 self.stream_end_emitted = true;
1390 return Err(error);
1391 }
1392
1393 self.states.clear();
1394 self.state = State::ImplicitDocumentStart;
1395 self.block_level = 0;
1396 self.pending_key_indent = None;
1397 self.pending_empty_scalar_span = None;
1398 self.last_non_comment_event_end = None;
1399 #[cfg(feature = "comments")]
1400 {
1401 self.deferred_error = None;
1402 self.queued_events.clear();
1403 self.comment_scratch.clear();
1404 self.pending_node_anchor_id = None;
1405 self.pending_node_tag = None;
1406 self.pending_node_tag_span = None;
1407 self.pending_node_property_end = None;
1408 self.pending_document_version = None;
1409 self.pending_document_directives = false;
1410 self.pending_document_tag_handles.clear();
1411 }
1412 self.anchors.clear();
1413 self.clear_document_tags();
1414 self.failed = false;
1415 self.at_document_end = false;
1416 self.stream_end_emitted = false;
1417 Ok(())
1418 }
1419
1420 fn next_event_impl<'a>(&mut self) -> ParseResult<'a>
1426 where
1427 'input: 'a,
1428 {
1429 let result = self.next_event_inner();
1430 if result.is_err() {
1431 self.failed = true;
1432 }
1433 result
1434 }
1435
1436 fn next_event_inner<'a>(&mut self) -> ParseResult<'a>
1437 where
1438 'input: 'a,
1439 {
1440 let event = match self.current.take() {
1441 None if self
1442 .pending_anchor
1443 .as_ref()
1444 .is_some_and(|anchor| anchor.node_emitted) =>
1445 {
1446 let anchor = self
1447 .pending_anchor
1448 .take()
1449 .expect("anchor metadata is ready");
1450 Ok((Event::Anchor(anchor.id, anchor.name), anchor.span))
1451 }
1452 None => {
1453 #[cfg(feature = "comments")]
1454 {
1455 if let Some(event) = self.queued_events.pop_front() {
1456 Ok(self.apply_pending_key_indent(event))
1457 } else if let Some(error) = self.deferred_error.take() {
1458 return Err(error);
1459 } else if self.state == State::End {
1460 self.parse()
1461 } else if let Some(comment) = self.maybe_next_comment_event()? {
1462 Ok(comment)
1463 } else {
1464 self.parse()
1465 }
1466 }
1467 #[cfg(not(feature = "comments"))]
1468 {
1469 self.parse()
1470 }
1471 }
1472 Some(v) => Ok(v),
1473 }?;
1474
1475 if let Some(anchor) = &mut self.pending_anchor {
1478 anchor.node_emitted |= matches!(
1479 &event.0,
1480 Event::Scalar(_, _, id, _)
1481 | Event::SequenceStart(_, id, _)
1482 | Event::MappingStart(_, id, _)
1483 if *id == anchor.id
1484 );
1485 }
1486
1487 Ok(self.remember_non_comment_event_end(event))
1488 }
1489
1490 fn next_event_for_load<'a>(&mut self) -> ParseResult<'a>
1496 where
1497 'input: 'a,
1498 {
1499 let result = self.next_event_impl();
1500 if result.is_err() {
1501 self.stream_end_emitted = true;
1502 }
1503 result
1504 }
1505
1506 fn apply_pending_key_indent<'a>(&mut self, (ev, span): (Event<'a>, Span)) -> (Event<'a>, Span) {
1507 if ev.is_node() {
1508 if let Some(indent) = self.pending_key_indent.take() {
1509 return (ev, span.with_indent(Some(indent)));
1510 }
1511 }
1512
1513 (ev, span)
1514 }
1515
1516 fn remember_non_comment_event_end<'a>(
1517 &mut self,
1518 (event, span): (Event<'a>, Span),
1519 ) -> (Event<'a>, Span) {
1520 if matches!(event, Event::Anchor(..)) {
1521 return (event, span);
1522 }
1523 #[cfg(feature = "comments")]
1524 if matches!(event, Event::Comment(..)) {
1525 return (event, span);
1526 }
1527 self.last_non_comment_event_end = Some(span.end);
1528 if matches!(event, Event::DocumentStart(..) | Event::DocumentEnd) {
1529 self.at_document_end = matches!(event, Event::DocumentEnd);
1530 }
1531 (event, span)
1532 }
1533
1534 fn peek_token(&mut self) -> Result<&QueuedToken<'_>, ScanError> {
1536 #[cfg(feature = "comments")]
1537 if let Some(error) = &self.deferred_error {
1538 return Err(error.clone());
1539 }
1540
1541 match self.token {
1542 None => {
1543 self.token = Some(self.scan_next_token()?);
1544 Ok(self.token.as_ref().unwrap())
1545 }
1546 Some(ref tok) => Ok(tok),
1547 }
1548 }
1549
1550 fn scan_next_token(&mut self) -> Result<QueuedToken<'input>, ScanError> {
1554 match self.scanner.next_queued_token()? {
1555 None => unreachable!("scanner ended before the parser consumed its stream-end token"),
1556 Some(tok) => Ok(tok),
1557 }
1558 }
1559
1560 #[cfg(feature = "comments")]
1561 #[inline]
1562 fn maybe_next_comment_event<'a>(&mut self) -> Result<Option<(Event<'a>, Span)>, ScanError>
1563 where
1564 'input: 'a,
1565 {
1566 if self.scanner.comments_possible() {
1567 self.next_comment_event()
1568 } else {
1569 Ok(None)
1570 }
1571 }
1572
1573 #[cfg(feature = "comments")]
1574 fn next_comment_event<'a>(&mut self) -> Result<Option<(Event<'a>, Span)>, ScanError>
1575 where
1576 'input: 'a,
1577 {
1578 let is_comment = {
1579 let token = self.peek_token()?;
1580 matches!(token.1, QueuedTokenType::Comment(_))
1581 };
1582
1583 if !is_comment {
1584 return Ok(None);
1585 }
1586
1587 let QueuedToken(span, token) = self.fetch_token();
1588 match token {
1589 QueuedTokenType::Comment(comment) => {
1590 let placement = self.refined_comment_placement(span, comment.placement());
1591 Ok(Some((Event::Comment(comment.into_text(), placement), span)))
1592 }
1593 _ => unreachable!("comment token disappeared after peek"),
1594 }
1595 }
1596
1597 #[cfg(feature = "comments")]
1598 #[inline]
1599 fn next_comment_events(&mut self) -> Result<Vec<(Event<'input>, Span)>, ScanError> {
1600 if !self.scanner.comments_possible() {
1601 return Ok(Vec::new());
1602 }
1603
1604 debug_assert_eq!(self.comment_scratch.len(), 0);
1605 loop {
1606 match self
1607 .peek_token()
1608 .map(|token| matches!(token.1, QueuedTokenType::Comment(_)))
1609 {
1610 Ok(true) => {}
1611 Err(error) if self.comment_scratch.is_empty() => return Err(error),
1612 Err(error) => {
1613 debug_assert!(self.deferred_error.is_none());
1614 self.deferred_error = Some(error);
1615 return Ok(core::mem::take(&mut self.comment_scratch));
1616 }
1617 Ok(_) => {
1618 return Ok(if self.comment_scratch.is_empty() {
1620 Vec::new()
1621 } else {
1622 core::mem::take(&mut self.comment_scratch)
1623 });
1624 }
1625 }
1626
1627 if self.comment_scratch.len() >= self.max_buffered_comment_events {
1628 self.comment_scratch.clear();
1629 return Err(ScanError::from_kind(
1630 self.peek_token()?.0.start,
1631 ErrorKind::TooManyComments,
1632 ));
1633 }
1634
1635 let comment = match self.next_comment_event() {
1636 Ok(comment) => comment.expect("comment token disappeared after peek"),
1637 Err(error) => {
1638 self.comment_scratch.clear();
1639 return Err(error);
1640 }
1641 };
1642 self.comment_scratch.push(comment);
1643 if self.deferred_error.is_some() {
1644 return Ok(core::mem::take(&mut self.comment_scratch));
1645 }
1646 }
1647 }
1648
1649 #[cfg(feature = "comments")]
1650 fn queue_tail_and_return_first(
1651 &mut self,
1652 mut events: Vec<(Event<'input>, Span)>,
1653 ) -> (Event<'input>, Span) {
1654 let first = {
1655 let mut drained = events.drain(..);
1656 let first = drained
1657 .next()
1658 .expect("event queue must contain at least one event");
1659 self.queued_events.extend(drained);
1660 first
1661 };
1662 self.comment_scratch = events;
1663 first
1664 }
1665
1666 #[cfg(feature = "comments")]
1667 fn queue_event_by_span(
1668 &mut self,
1669 mut comments: Vec<(Event<'input>, Span)>,
1670 event: (Event<'input>, Span),
1671 ) -> (Event<'input>, Span) {
1672 let insert_at = comments
1673 .iter()
1674 .position(|(_, comment_span)| {
1675 comment_span.start.index() >= event.1.start.index()
1676 && comment_span.end.index() >= event.1.end.index()
1677 })
1678 .unwrap_or(comments.len());
1679 comments.insert(insert_at, event);
1680 self.queue_tail_and_return_first(comments)
1681 }
1682
1683 #[cfg(feature = "comments")]
1684 fn queue_two_events_by_span(
1685 &mut self,
1686 mut comments: Vec<(Event<'input>, Span)>,
1687 first: (Event<'input>, Span),
1688 second: (Event<'input>, Span),
1689 ) -> (Event<'input>, Span) {
1690 let insert_at = comments
1691 .iter()
1692 .position(|(_, comment_span)| {
1693 comment_span.start.index() >= first.1.start.index()
1694 && comment_span.end.index() >= first.1.end.index()
1695 })
1696 .unwrap_or(comments.len());
1697 comments.reserve(2);
1698 comments.insert(insert_at, first);
1699 comments.insert(insert_at + 1, second);
1700 self.queue_tail_and_return_first(comments)
1701 }
1702
1703 #[cfg(feature = "comments")]
1704 fn refined_comment_placement(&mut self, span: Span, placement: Placement) -> Placement {
1705 if placement == Placement::Right {
1706 return Placement::Right;
1707 }
1708
1709 let next = match self.peek_token() {
1710 Ok(next) => next,
1711 Err(error) => {
1712 debug_assert!(self.deferred_error.is_none());
1713 self.deferred_error = Some(error);
1714 return placement;
1715 }
1716 };
1717 if matches!(next.1, QueuedTokenType::StreamEnd) {
1718 return Placement::Last;
1719 }
1720
1721 if next.0.start.line() == span.end.line() + 1 {
1722 Placement::Above
1723 } else {
1724 Placement::Free
1725 }
1726 }
1727
1728 #[track_caller]
1733 fn fetch_token<'a>(&mut self) -> QueuedToken<'a>
1734 where
1735 'input: 'a,
1736 {
1737 self.token
1738 .take()
1739 .expect("fetch_token needs to be preceded by peek_token")
1740 }
1741
1742 fn skip(&mut self) {
1744 self.token = None;
1745 }
1746 #[track_caller]
1751 fn pop_state(&mut self) {
1752 self.state = self.states.pop().unwrap();
1753 }
1754 fn push_state(&mut self, state: State) {
1756 self.states.push(state);
1757 }
1758
1759 fn start_block_collection(&mut self, mark: Marker) -> Result<(), ScanError> {
1760 if self.block_level >= self.block_nesting_limit {
1761 return Err(ScanError::from_kind(
1762 mark,
1763 ErrorKind::RecursionLimitExceeded,
1764 ));
1765 }
1766 self.block_level += 1;
1767 Ok(())
1768 }
1769
1770 fn end_block_collection(&mut self) {
1771 debug_assert!(self.block_level > 0);
1772 self.block_level -= 1;
1773 }
1774
1775 fn defer_parse_node<'a>(
1776 &mut self,
1777 node_state: State,
1778 return_state: State,
1779 block: bool,
1780 indentless_sequence: bool,
1781 ) -> ParseResult<'a>
1782 where
1783 'input: 'a,
1784 {
1785 self.push_state(return_state);
1786 self.state = node_state;
1787 #[cfg(feature = "comments")]
1788 if let Some(comment) = self.maybe_next_comment_event()? {
1789 return Ok(comment);
1790 }
1791 self.parse_node(block, indentless_sequence)
1792 }
1793
1794 fn parse<'a>(&mut self) -> ParseResult<'a>
1795 where
1796 'input: 'a,
1797 {
1798 if self.state == State::End {
1799 return Ok((Event::StreamEnd, Span::empty(self.scanner.mark())));
1800 }
1801 let event = self.state_machine()?;
1802 Ok(self.apply_pending_key_indent(event))
1803 }
1804
1805 pub fn load<R: SpannedEventReceiver<'input>>(
1855 &mut self,
1856 recv: &mut R,
1857 multi: bool,
1858 ) -> Result<(), ScanError> {
1859 ParserTrait::load(self, recv, multi)
1860 }
1861
1862 pub fn try_load<R: TrySpannedEventReceiver<'input>>(
1911 &mut self,
1912 recv: &mut R,
1913 multi: bool,
1914 ) -> Result<(), TryLoadError<R::Error>> {
1915 ParserTrait::try_load(self, recv, multi)
1916 }
1917
1918 fn state_machine<'a>(&mut self) -> ParseResult<'a>
1919 where
1920 'input: 'a,
1921 {
1922 debug_print!("\n\x1B[;33mParser state: {:?} \x1B[;0m", self.state);
1923
1924 match self.state {
1925 State::StreamStart => self.stream_start(),
1926
1927 State::ImplicitDocumentStart => self.document_start(true),
1928 State::DocumentStart => self.document_start(false),
1929 State::DocumentContent => self.document_content(),
1930 State::DocumentEnd => self.document_end(),
1931
1932 State::BlockNode => self.parse_node(true, false),
1933 State::BlockNodeOrIndentlessSequence => self.parse_node(true, true),
1934 State::FlowNode => self.parse_node(false, false),
1935 State::BlockMappingFirstKey => self.block_mapping_key(true),
1936 State::BlockMappingKey => self.block_mapping_key(false),
1937 #[cfg(feature = "comments")]
1938 State::BlockMappingKeyNode => self.block_mapping_key_node(),
1939 State::BlockMappingValue => self.block_mapping_value(),
1940 #[cfg(feature = "comments")]
1941 State::BlockMappingValueNode => self.block_mapping_value_node(),
1942
1943 State::BlockSequenceFirstEntry => self.block_sequence_entry(true),
1944 State::BlockSequenceEntry => self.block_sequence_entry(false),
1945 #[cfg(feature = "comments")]
1946 State::BlockSequenceEntryNode => self.block_sequence_entry_node(),
1947
1948 State::FlowSequenceFirstEntry => self.flow_sequence_entry(true),
1949 State::FlowSequenceEntry => self.flow_sequence_entry(false),
1950
1951 State::FlowMappingFirstKey => self.flow_mapping_key(true),
1952 State::FlowMappingKey => self.flow_mapping_key(false),
1953 #[cfg(feature = "comments")]
1954 State::FlowMappingKeyNode => self.flow_mapping_key_node(),
1955 State::FlowMappingValue => self.flow_mapping_value(false),
1956 #[cfg(feature = "comments")]
1957 State::FlowMappingValueNode => self.flow_mapping_value_node(),
1958
1959 State::IndentlessSequenceEntry => self.indentless_sequence_entry(),
1960 State::IndentlessSequenceEntryNode => self.indentless_sequence_entry_node(),
1961
1962 State::FlowSequenceEntryMappingKey => self.flow_sequence_entry_mapping_key(),
1963 State::FlowSequenceEntryMappingValue => self.flow_sequence_entry_mapping_value(),
1964 #[cfg(feature = "comments")]
1965 State::FlowSequenceEntryMappingValueNode => {
1966 self.flow_sequence_entry_mapping_value_node()
1967 }
1968 State::FlowSequenceEntryMappingEnd => self.flow_sequence_entry_mapping_end(),
1969 State::FlowMappingEmptyValue => self.flow_mapping_value(true),
1970
1971 State::End => unreachable!("end state is handled before state-machine dispatch"),
1972 }
1973 }
1974
1975 fn stream_start<'a>(&mut self) -> ParseResult<'a>
1976 where
1977 'input: 'a,
1978 {
1979 match *self.peek_token()? {
1980 QueuedToken(span, QueuedTokenType::StreamStart) => {
1981 self.state = State::ImplicitDocumentStart;
1982 self.skip();
1983 Ok((Event::StreamStart, span))
1984 }
1985 QueuedToken(span, _) => Err(ScanError::from_kind(
1986 span.start,
1987 ErrorKind::ExpectedStreamStart,
1988 )),
1989 }
1990 }
1991
1992 #[cfg(feature = "comments")]
1993 fn has_pending_document_directives(&self) -> bool {
1994 self.pending_document_directives
1995 || self.pending_document_version.is_some()
1996 || !self.pending_document_tag_handles.is_empty()
1997 }
1998
1999 fn document_start<'a>(&mut self, implicit: bool) -> ParseResult<'a>
2000 where
2001 'input: 'a,
2002 {
2003 #[cfg(feature = "comments")]
2007 if self.has_pending_document_directives() {
2008 return self.explicit_document_start();
2009 }
2010
2011 while let QueuedTokenType::DocumentEnd = self.peek_token()?.1 {
2012 self.skip();
2013 }
2014
2015 self.anchors.clear();
2017
2018 #[cfg(feature = "comments")]
2022 if let Some(comment) = self.maybe_next_comment_event()? {
2023 return Ok(comment);
2024 }
2025
2026 match *self.peek_token()? {
2027 QueuedToken(span, QueuedTokenType::StreamEnd) => {
2028 self.state = State::End;
2029 self.skip();
2030 Ok((Event::StreamEnd, span))
2031 }
2032 QueuedToken(
2033 _,
2034 QueuedTokenType::VersionDirective(..)
2035 | QueuedTokenType::TagDirective(..)
2036 | QueuedTokenType::ReservedDirective(..)
2037 | QueuedTokenType::DocumentStart,
2038 ) => {
2039 self.explicit_document_start()
2041 }
2042 QueuedToken(span, _) if implicit => {
2043 self.parser_process_directives(None, false, BTreeSet::new())?;
2044 self.push_state(State::DocumentEnd);
2045 self.state = State::BlockNode;
2046 Ok((Event::DocumentStart(false, None), span))
2047 }
2048 _ => {
2049 self.explicit_document_start()
2051 }
2052 }
2053 }
2054
2055 fn parser_process_directives(
2056 &mut self,
2057 mut version: Option<YamlVersion>,
2058 continuing: bool,
2059 mut document_tag_handles: BTreeSet<Cow<'input, str>>,
2060 ) -> Result<(Option<YamlVersion>, BTreeSet<Cow<'input, str>>), ScanError> {
2061 if !continuing && !self.keep_tags {
2064 self.tags.clear();
2065 }
2066
2067 loop {
2068 let is_directive = matches!(
2069 self.peek_token()?.1,
2070 QueuedTokenType::VersionDirective(..)
2071 | QueuedTokenType::TagDirective(..)
2072 | QueuedTokenType::ReservedDirective(..)
2073 );
2074 if !is_directive {
2075 break;
2076 }
2077
2078 let QueuedToken(span, token) = self.fetch_token();
2079 match token {
2080 QueuedTokenType::VersionDirective(major, minor) => {
2081 if version.is_some() {
2082 return Err(ScanError::from_kind(
2083 span.start,
2084 ErrorKind::DuplicateVersionDirective,
2085 ));
2086 }
2087 if major != 1 {
2088 return Err(ScanError::from_kind(
2089 span.start,
2090 ErrorKind::UnsupportedYamlMajorVersion,
2091 ));
2092 }
2093 version = Some(YamlVersion::new(major, minor));
2094 }
2095 QueuedTokenType::TagDirective(handle, prefix) => {
2096 if !document_tag_handles.insert(handle.clone()) {
2097 return Err(ScanError::from_kind(
2098 span.start,
2099 ErrorKind::DuplicateTagDirective,
2100 ));
2101 }
2102 self.tags.insert(handle, prefix);
2103 }
2104 QueuedTokenType::ReservedDirective(_, _) => {
2105 }
2107 _ => unreachable!("non-directive token passed the directive guard"),
2108 }
2109 }
2110
2111 Ok((version, document_tag_handles))
2112 }
2113
2114 fn explicit_document_start<'a>(&mut self) -> ParseResult<'a>
2115 where
2116 'input: 'a,
2117 {
2118 #[cfg(feature = "comments")]
2119 let version = {
2120 let pending_version = self.pending_document_version.take();
2121 let continuing_directives = core::mem::take(&mut self.pending_document_directives);
2122 let pending_tag_handles = core::mem::take(&mut self.pending_document_tag_handles);
2123 let (version, document_tag_handles) = self.parser_process_directives(
2124 pending_version,
2125 continuing_directives,
2126 pending_tag_handles,
2127 )?;
2128 if let Some(comment) = self.maybe_next_comment_event()? {
2129 self.pending_document_version = version;
2130 self.pending_document_directives = true;
2131 self.pending_document_tag_handles = document_tag_handles;
2132 return Ok(comment);
2133 }
2134 version
2135 };
2136 #[cfg(not(feature = "comments"))]
2137 let (version, _) = self.parser_process_directives(None, false, BTreeSet::new())?;
2138 match *self.peek_token()? {
2139 QueuedToken(mark, QueuedTokenType::DocumentStart) => {
2140 self.push_state(State::DocumentEnd);
2141 self.state = State::DocumentContent;
2142 self.skip();
2143 Ok((Event::DocumentStart(true, version), mark))
2144 }
2145 QueuedToken(span, _) => Err(ScanError::from_kind(
2146 span.start,
2147 ErrorKind::ExpectedDocumentStart,
2148 )),
2149 }
2150 }
2151
2152 fn document_content<'a>(&mut self) -> ParseResult<'a>
2153 where
2154 'input: 'a,
2155 {
2156 if let QueuedToken(
2157 mark,
2158 QueuedTokenType::VersionDirective(..)
2159 | QueuedTokenType::TagDirective(..)
2160 | QueuedTokenType::ReservedDirective(..)
2161 | QueuedTokenType::DocumentStart
2162 | QueuedTokenType::DocumentEnd
2163 | QueuedTokenType::StreamEnd,
2164 ) = *self.peek_token()?
2165 {
2166 self.pop_state();
2167 let span = self
2168 .last_non_comment_event_end
2169 .map_or_else(|| Span::empty(mark.start), Span::empty);
2170 Ok((Event::empty_scalar(), span))
2171 } else {
2172 self.state = State::BlockNode;
2173 self.parse_node(true, false)
2174 }
2175 }
2176
2177 fn document_end<'a>(&mut self) -> ParseResult<'a>
2178 where
2179 'input: 'a,
2180 {
2181 let mut explicit_end = false;
2182 let span: Span = match *self.peek_token()? {
2183 QueuedToken(span, QueuedTokenType::DocumentEnd) => {
2184 explicit_end = true;
2185 self.skip();
2186 span
2187 }
2188 QueuedToken(span, _) => self
2189 .last_non_comment_event_end
2190 .map_or_else(|| Span::empty(span.start), Span::empty),
2191 };
2192
2193 self.clear_document_tags();
2194 if explicit_end {
2195 self.state = State::ImplicitDocumentStart;
2196 } else {
2197 if let QueuedToken(
2198 span,
2199 QueuedTokenType::VersionDirective(..)
2200 | QueuedTokenType::TagDirective(..)
2201 | QueuedTokenType::ReservedDirective(..),
2202 ) = *self.peek_token()?
2203 {
2204 return Err(ScanError::from_kind(
2205 span.start,
2206 ErrorKind::MissingDocumentEndBeforeDirective,
2207 ));
2208 }
2209 self.state = State::DocumentStart;
2210 }
2211
2212 Ok((Event::DocumentEnd, span))
2213 }
2214
2215 fn clear_document_tags(&mut self) {
2216 if self.keep_tags {
2217 self.tags.remove("!!");
2219 self.tags.remove("!");
2220 } else {
2221 self.tags.clear();
2222 }
2223 }
2224
2225 fn register_anchor(&mut self, name: Cow<'input, str>, mark: &Span) -> Result<usize, ScanError> {
2226 let new_id = self.anchor_id_count;
2228 self.anchor_id_count = self
2229 .anchor_id_count
2230 .checked_add(1)
2231 .ok_or_else(|| ScanError::from_kind(mark.start, ErrorKind::AnchorCountOverflow))?;
2232 if self.emit_anchor_events {
2233 debug_assert!(self.pending_anchor.is_none());
2234 self.pending_anchor = Some(PendingAnchor {
2235 id: new_id,
2236 name: name.clone(),
2237 span: *mark,
2238 node_emitted: false,
2239 });
2240 }
2241 self.anchors.insert(name, new_id);
2242 Ok(new_id)
2243 }
2244
2245 #[cfg(feature = "comments")]
2246 fn save_pending_node_properties(
2247 &mut self,
2248 anchor_id: Option<usize>,
2249 tag: Option<Cow<'input, Tag>>,
2250 tag_span: Option<(Marker, u32)>,
2251 property_end: Option<Marker>,
2252 ) {
2253 self.pending_node_anchor_id = anchor_id;
2254 self.pending_node_tag = tag;
2255 self.pending_node_tag_span = tag_span;
2256 self.pending_node_property_end = property_end;
2257 }
2258
2259 fn attach_tag_span(
2260 event: Event<'_>,
2261 span: Span,
2262 tag_span: Option<(Marker, u32)>,
2263 ) -> (Event<'_>, Span) {
2264 (event, span.with_tag_span(tag_span))
2265 }
2266
2267 #[allow(clippy::too_many_lines)]
2268 fn parse_node<'a>(&mut self, block: bool, indentless_sequence: bool) -> ParseResult<'a>
2269 where
2270 'input: 'a,
2271 {
2272 #[cfg(feature = "comments")]
2273 if let Some(comment) = self.maybe_next_comment_event()? {
2274 return Ok(comment);
2275 }
2276
2277 #[cfg(feature = "comments")]
2278 let (mut anchor_id, mut tag, mut tag_span, mut property_end) = (
2279 self.pending_node_anchor_id.take(),
2280 self.pending_node_tag.take(),
2281 self.pending_node_tag_span.take(),
2282 self.pending_node_property_end.take(),
2283 );
2284 #[cfg(not(feature = "comments"))]
2285 let (mut anchor_id, mut tag, mut tag_span, mut property_end) = (None, None, None, None);
2286 match *self.peek_token()? {
2287 QueuedToken(_, QueuedTokenType::Alias(_)) if anchor_id.is_none() && tag.is_none() => {
2288 self.pop_state();
2289 let QueuedToken(span, QueuedTokenType::Alias(name)) = self.fetch_token() else {
2290 unreachable!("alias token disappeared after peek")
2291 };
2292 return match self.anchors.get(&*name) {
2293 None if self.emit_unresolved_aliases => {
2294 Ok((Event::UnresolvedAlias(name), span))
2295 }
2296 None => Err(ScanError::from_kind(span.start, ErrorKind::UnknownAnchor)),
2297 Some(id) => Ok((Event::Alias(*id), span)),
2298 };
2299 }
2300 QueuedToken(_, QueuedTokenType::Anchor(_)) if anchor_id.is_none() => {
2301 let QueuedToken(span, QueuedTokenType::Anchor(name)) = self.fetch_token() else {
2302 unreachable!("anchor token disappeared after peek")
2303 };
2304 anchor_id = Some(self.register_anchor(name, &span)?);
2305 property_end = Some(span.end);
2306 if tag.is_none() && matches!(self.peek_token()?.1, QueuedTokenType::Tag(..)) {
2307 let QueuedToken(tag_mark, QueuedTokenType::Tag(handle, suffix)) =
2308 self.fetch_token()
2309 else {
2310 unreachable!("tag token disappeared after peek")
2311 };
2312 tag_span = Some((tag_mark.start, u32::try_from(tag_mark.len()).unwrap_or(0)));
2313 tag = Some(self.resolve_tag(tag_mark, handle, suffix)?);
2314 property_end = Some(tag_mark.end);
2315 }
2316 #[cfg(feature = "comments")]
2317 if let Some(comment) = self.maybe_next_comment_event()? {
2318 self.save_pending_node_properties(anchor_id, tag, tag_span, property_end);
2319 return Ok(comment);
2320 }
2321 }
2322 QueuedToken(mark, QueuedTokenType::Tag(..)) if tag.is_none() => {
2323 let QueuedTokenType::Tag(handle, suffix) = self.fetch_token().1 else {
2324 unreachable!("tag token disappeared after peek")
2325 };
2326 tag_span = Some((mark.start, u32::try_from(mark.len()).unwrap_or(0)));
2327 property_end = Some(mark.end);
2328 tag = Some(self.resolve_tag(mark, handle, suffix)?);
2329 if anchor_id.is_none() {
2330 if let QueuedTokenType::Anchor(_) = &self.peek_token()?.1 {
2331 let QueuedToken(mark, QueuedTokenType::Anchor(name)) = self.fetch_token()
2332 else {
2333 unreachable!("anchor token disappeared after peek")
2334 };
2335 anchor_id = Some(self.register_anchor(name, &mark)?);
2336 property_end = Some(mark.end);
2337 }
2338 }
2339 #[cfg(feature = "comments")]
2340 if let Some(comment) = self.maybe_next_comment_event()? {
2341 self.save_pending_node_properties(anchor_id, tag, tag_span, property_end);
2342 return Ok(comment);
2343 }
2344 }
2345 _ => {}
2346 }
2347 let has_anchor = anchor_id.is_some();
2348 let anchor_id = anchor_id.unwrap_or(0);
2349 match *self.peek_token()? {
2350 QueuedToken(mark, QueuedTokenType::BlockEntry) if indentless_sequence => {
2351 self.start_block_collection(mark.start)?;
2352 self.skip();
2353 let start = (
2354 Event::SequenceStart(StructureStyle::Block, anchor_id, tag),
2355 mark.with_tag_span(tag_span),
2356 );
2357 #[cfg(feature = "comments")]
2358 {
2359 let comments = match self.next_comment_events() {
2360 Ok(comments) => comments,
2361 Err(error) if !matches!(error.kind(), ErrorKind::TooManyComments) => {
2362 debug_assert!(self.deferred_error.is_none());
2367 self.deferred_error = Some(error);
2368 self.pending_empty_scalar_span = Some(mark);
2369 self.state = State::IndentlessSequenceEntryNode;
2370 return Ok(start);
2371 }
2372 Err(error) => return Err(error),
2373 };
2374 if comments.is_empty() {
2375 self.pending_empty_scalar_span = Some(mark);
2376 self.state = State::IndentlessSequenceEntryNode;
2377 Ok(start)
2378 } else if let Ok(QueuedToken(
2379 _,
2380 QueuedTokenType::BlockEntry
2381 | QueuedTokenType::Key
2382 | QueuedTokenType::Value
2383 | QueuedTokenType::BlockEnd,
2384 )) = self.peek_token()
2385 {
2386 self.state = State::IndentlessSequenceEntry;
2387 Ok(self.queue_two_events_by_span(
2388 comments,
2389 start,
2390 (Event::empty_scalar(), mark),
2391 ))
2392 } else {
2393 self.pending_empty_scalar_span = Some(mark);
2394 self.state = State::IndentlessSequenceEntryNode;
2395 Ok(self.queue_event_by_span(comments, start))
2396 }
2397 }
2398 #[cfg(not(feature = "comments"))]
2399 {
2400 self.pending_empty_scalar_span = Some(mark);
2401 self.state = State::IndentlessSequenceEntryNode;
2402 Ok(start)
2403 }
2404 }
2405 QueuedToken(_, QueuedTokenType::Scalar(..)) => {
2406 self.pop_state();
2407 let QueuedToken(mark, QueuedTokenType::Scalar(style, v)) = self.fetch_token()
2408 else {
2409 unreachable!("scalar token disappeared after peek")
2410 };
2411 Ok(Self::attach_tag_span(
2412 Event::Scalar(v, style, anchor_id, tag),
2413 mark,
2414 tag_span,
2415 ))
2416 }
2417 QueuedToken(mark, QueuedTokenType::FlowSequenceStart) => {
2418 self.state = State::FlowSequenceFirstEntry;
2419 self.skip();
2420 Ok(Self::attach_tag_span(
2421 Event::SequenceStart(StructureStyle::Flow, anchor_id, tag),
2422 mark,
2423 tag_span,
2424 ))
2425 }
2426 QueuedToken(mark, QueuedTokenType::FlowMappingStart) => {
2427 self.state = State::FlowMappingFirstKey;
2428 self.skip();
2429 Ok(Self::attach_tag_span(
2430 Event::MappingStart(StructureStyle::Flow, anchor_id, tag),
2431 mark,
2432 tag_span,
2433 ))
2434 }
2435 QueuedToken(mark, QueuedTokenType::BlockSequenceStart) if block => {
2436 self.start_block_collection(mark.start)?;
2437 self.state = State::BlockSequenceFirstEntry;
2438 self.skip();
2439 Ok(Self::attach_tag_span(
2440 Event::SequenceStart(StructureStyle::Block, anchor_id, tag),
2441 mark,
2442 tag_span,
2443 ))
2444 }
2445 QueuedToken(mark, QueuedTokenType::BlockMappingStart) if block => {
2446 self.start_block_collection(mark.start)?;
2447 self.state = State::BlockMappingFirstKey;
2448 self.skip();
2449 Ok(Self::attach_tag_span(
2450 Event::MappingStart(StructureStyle::Block, anchor_id, tag),
2451 mark,
2452 tag_span,
2453 ))
2454 }
2455 QueuedToken(mark, _) if tag.is_some() || has_anchor => {
2457 self.pop_state();
2458 let span = property_end.map_or_else(|| Span::empty(mark.start), Span::empty);
2459 Ok(Self::attach_tag_span(
2460 Event::empty_scalar_with_anchor(anchor_id, tag),
2461 span,
2462 tag_span,
2463 ))
2464 }
2465 QueuedToken(span, _) => {
2466 let kind = match self.state {
2467 State::FlowSequenceFirstEntry | State::FlowSequenceEntry => {
2468 ErrorKind::UnexpectedEofFlowSequence
2469 }
2470 State::FlowMappingFirstKey
2471 | State::FlowMappingKey
2472 | State::FlowMappingValue
2473 | State::FlowMappingEmptyValue => ErrorKind::UnexpectedEofFlowMapping,
2474 State::FlowSequenceEntryMappingKey
2475 | State::FlowSequenceEntryMappingValue
2476 | State::FlowSequenceEntryMappingEnd
2477 | State::FlowNode => ErrorKind::UnexpectedEofImplicitFlowMapping,
2478 State::BlockSequenceFirstEntry
2479 | State::BlockSequenceEntry
2480 | State::BlockNode => ErrorKind::UnexpectedEofBlockSequence,
2481 State::BlockMappingFirstKey
2482 | State::BlockMappingKey
2483 | State::BlockMappingValue
2484 | State::BlockNodeOrIndentlessSequence => ErrorKind::UnexpectedEofBlockMapping,
2485 _ => ErrorKind::ExpectedNodeContent,
2486 };
2487 Err(ScanError::from_kind(span.start, kind))
2488 }
2489 }
2490 }
2491
2492 fn block_mapping_key<'a>(&mut self, _first: bool) -> ParseResult<'a>
2493 where
2494 'input: 'a,
2495 {
2496 match *self.peek_token()? {
2497 QueuedToken(_, QueuedTokenType::Key) => {
2498 if let QueuedToken(key_span, QueuedTokenType::Key) = *self.peek_token()? {
2500 self.pending_key_indent = Some(key_span.start.col());
2501 }
2502 self.skip();
2503 #[cfg(feature = "comments")]
2504 if let Some(comment) = self.maybe_next_comment_event()? {
2505 self.state = State::BlockMappingKeyNode;
2506 return Ok(comment);
2507 }
2508 self.block_mapping_key_node()
2509 }
2510 QueuedToken(mark, QueuedTokenType::Value) => {
2512 self.state = State::BlockMappingValue;
2513 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2514 }
2515 QueuedToken(mark, QueuedTokenType::BlockEnd) => {
2516 self.end_block_collection();
2517 self.pop_state();
2518 self.skip();
2519 Ok((Event::MappingEnd, mark))
2520 }
2521 QueuedToken(span, _) => Err(ScanError::from_kind(
2522 span.start,
2523 ErrorKind::ExpectedBlockMappingKey,
2524 )),
2525 }
2526 }
2527
2528 fn block_mapping_key_node<'a>(&mut self) -> ParseResult<'a>
2529 where
2530 'input: 'a,
2531 {
2532 if let QueuedToken(
2533 mark,
2534 QueuedTokenType::Key | QueuedTokenType::Value | QueuedTokenType::BlockEnd,
2535 ) = *self.peek_token()?
2536 {
2537 self.state = State::BlockMappingValue;
2538 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2539 } else {
2540 self.defer_parse_node(
2541 State::BlockNodeOrIndentlessSequence,
2542 State::BlockMappingValue,
2543 true,
2544 true,
2545 )
2546 }
2547 }
2548
2549 fn block_mapping_value<'a>(&mut self) -> ParseResult<'a>
2550 where
2551 'input: 'a,
2552 {
2553 match *self.peek_token()? {
2554 QueuedToken(mark, QueuedTokenType::Value) => {
2555 self.skip();
2556 #[cfg(feature = "comments")]
2557 {
2558 let comments = self.next_comment_events()?;
2559 if !comments.is_empty() {
2560 if let Ok(QueuedToken(
2561 _,
2562 QueuedTokenType::Key
2563 | QueuedTokenType::Value
2564 | QueuedTokenType::BlockEnd,
2565 )) = self.peek_token()
2566 {
2567 self.state = State::BlockMappingKey;
2568 return Ok(
2569 self.queue_event_by_span(comments, (Event::empty_scalar(), mark))
2570 );
2571 }
2572 self.pending_empty_scalar_span = Some(mark);
2573 self.state = State::BlockMappingValueNode;
2574 return Ok(self.queue_tail_and_return_first(comments));
2575 }
2576 }
2577 self.block_mapping_value_node_with_empty_span(mark)
2578 }
2579 QueuedToken(mark, _) => {
2580 self.state = State::BlockMappingKey;
2581 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2582 }
2583 }
2584 }
2585
2586 #[cfg(feature = "comments")]
2587 fn block_mapping_value_node<'a>(&mut self) -> ParseResult<'a>
2588 where
2589 'input: 'a,
2590 {
2591 self.peek_token()?;
2593 let Some(mark) = self.pending_empty_scalar_span.take() else {
2594 unreachable!(
2595 "block mapping value-node state entered without a pending empty-scalar span"
2596 )
2597 };
2598 self.block_mapping_value_node_with_empty_span(mark)
2599 }
2600
2601 fn block_mapping_value_node_with_empty_span<'a>(&mut self, mark: Span) -> ParseResult<'a>
2602 where
2603 'input: 'a,
2604 {
2605 if let QueuedToken(
2606 _,
2607 QueuedTokenType::Key | QueuedTokenType::Value | QueuedTokenType::BlockEnd,
2608 ) = *self.peek_token()?
2609 {
2610 self.state = State::BlockMappingKey;
2611 Ok((Event::empty_scalar(), mark))
2612 } else {
2613 self.defer_parse_node(
2614 State::BlockNodeOrIndentlessSequence,
2615 State::BlockMappingKey,
2616 true,
2617 true,
2618 )
2619 }
2620 }
2621
2622 fn flow_mapping_key<'a>(&mut self, first: bool) -> ParseResult<'a>
2623 where
2624 'input: 'a,
2625 {
2626 let span: Span =
2627 if let QueuedToken(mark, QueuedTokenType::FlowMappingEnd) = *self.peek_token()? {
2628 mark
2629 } else {
2630 if !first {
2631 match *self.peek_token()? {
2632 QueuedToken(_, QueuedTokenType::FlowEntry) => {
2633 self.skip();
2634 #[cfg(feature = "comments")]
2635 if let Some(comment) = self.maybe_next_comment_event()? {
2636 self.state = State::FlowMappingFirstKey;
2637 return Ok(comment);
2638 }
2639 }
2640 QueuedToken(span, _) => {
2641 return Err(ScanError::from_kind(
2642 span.start,
2643 ErrorKind::ExpectedFlowMappingSeparator,
2644 ))
2645 }
2646 }
2647 }
2648
2649 match *self.peek_token()? {
2650 QueuedToken(_, QueuedTokenType::Key) => {
2651 self.skip();
2652 #[cfg(feature = "comments")]
2653 if let Some(comment) = self.maybe_next_comment_event()? {
2654 self.state = State::FlowMappingKeyNode;
2655 return Ok(comment);
2656 }
2657 return self.flow_mapping_key_node();
2658 }
2659 QueuedToken(marker, QueuedTokenType::Value) => {
2660 self.state = State::FlowMappingValue;
2661 return Ok((Event::empty_scalar(), Span::empty(marker.start)));
2662 }
2663 QueuedToken(_, QueuedTokenType::FlowMappingEnd) => (),
2664 _ => {
2665 return self.defer_parse_node(
2666 State::FlowNode,
2667 State::FlowMappingEmptyValue,
2668 false,
2669 false,
2670 );
2671 }
2672 }
2673
2674 self.peek_token()?.0
2675 };
2676
2677 self.pop_state();
2678 self.skip();
2679 Ok((Event::MappingEnd, span))
2680 }
2681
2682 fn flow_mapping_key_node<'a>(&mut self) -> ParseResult<'a>
2683 where
2684 'input: 'a,
2685 {
2686 if let QueuedToken(
2687 mark,
2688 QueuedTokenType::Value | QueuedTokenType::FlowEntry | QueuedTokenType::FlowMappingEnd,
2689 ) = *self.peek_token()?
2690 {
2691 self.state = State::FlowMappingValue;
2692 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2693 } else {
2694 self.defer_parse_node(State::FlowNode, State::FlowMappingValue, false, false)
2695 }
2696 }
2697
2698 fn flow_mapping_value<'a>(&mut self, empty: bool) -> ParseResult<'a>
2699 where
2700 'input: 'a,
2701 {
2702 let span: Span = {
2703 if empty {
2704 let QueuedToken(mark, _) = *self.peek_token()?;
2705 self.state = State::FlowMappingKey;
2706 return Ok((Event::empty_scalar(), Span::empty(mark.start)));
2707 }
2708 match *self.peek_token()? {
2709 QueuedToken(span, QueuedTokenType::Value) => {
2710 self.skip();
2711 #[cfg(feature = "comments")]
2712 {
2713 let comments = self.next_comment_events()?;
2714 if comments.is_empty() {
2715 return self.flow_mapping_value_node_with_empty_span(span);
2716 }
2717 if let Ok(QueuedToken(
2718 _,
2719 QueuedTokenType::FlowEntry | QueuedTokenType::FlowMappingEnd,
2720 )) = self.peek_token()
2721 {
2722 self.state = State::FlowMappingKey;
2723 return Ok(
2724 self.queue_event_by_span(comments, (Event::empty_scalar(), span))
2725 );
2726 }
2727
2728 self.pending_empty_scalar_span = Some(span);
2729 self.state = State::FlowMappingValueNode;
2730 return Ok(self.queue_tail_and_return_first(comments));
2731 }
2732 #[cfg(not(feature = "comments"))]
2733 return self.flow_mapping_value_node_with_empty_span(span);
2734 }
2735 QueuedToken(marker, _) => Span::empty(marker.start),
2736 }
2737 };
2738
2739 self.state = State::FlowMappingKey;
2740 Ok((Event::empty_scalar(), span))
2741 }
2742
2743 #[cfg(feature = "comments")]
2744 fn flow_mapping_value_node<'a>(&mut self) -> ParseResult<'a>
2745 where
2746 'input: 'a,
2747 {
2748 self.peek_token()?;
2750 let Some(mark) = self.pending_empty_scalar_span.take() else {
2751 unreachable!(
2752 "flow mapping value-node state entered without a pending empty-scalar span"
2753 )
2754 };
2755 self.flow_mapping_value_node_with_empty_span(mark)
2756 }
2757
2758 fn flow_mapping_value_node_with_empty_span<'a>(&mut self, mark: Span) -> ParseResult<'a>
2759 where
2760 'input: 'a,
2761 {
2762 match self.peek_token()?.1 {
2763 QueuedTokenType::FlowEntry | QueuedTokenType::FlowMappingEnd => {
2764 self.state = State::FlowMappingKey;
2765 Ok((Event::empty_scalar(), mark))
2766 }
2767 _ => self.defer_parse_node(State::FlowNode, State::FlowMappingKey, false, false),
2768 }
2769 }
2770
2771 fn flow_sequence_entry<'a>(&mut self, first: bool) -> ParseResult<'a>
2772 where
2773 'input: 'a,
2774 {
2775 match *self.peek_token()? {
2776 QueuedToken(mark, QueuedTokenType::FlowSequenceEnd) => {
2777 self.pop_state();
2778 self.skip();
2779 return Ok((Event::SequenceEnd, mark));
2780 }
2781 QueuedToken(_, QueuedTokenType::FlowEntry) if !first => {
2782 self.skip();
2783 #[cfg(feature = "comments")]
2784 if let Some(comment) = self.maybe_next_comment_event()? {
2785 self.state = State::FlowSequenceFirstEntry;
2786 return Ok(comment);
2787 }
2788 }
2789 QueuedToken(span, _) if !first => {
2790 return Err(ScanError::from_kind(
2791 span.start,
2792 ErrorKind::ExpectedFlowSequenceSeparator,
2793 ));
2794 }
2795 _ => { }
2796 }
2797 match *self.peek_token()? {
2798 QueuedToken(mark, QueuedTokenType::FlowSequenceEnd) => {
2799 self.pop_state();
2800 self.skip();
2801 Ok((Event::SequenceEnd, mark))
2802 }
2803 QueuedToken(mark, QueuedTokenType::Key) => {
2804 self.state = State::FlowSequenceEntryMappingKey;
2805 self.skip();
2806 Ok((Event::MappingStart(StructureStyle::Flow, 0, None), mark))
2807 }
2808 _ => self.defer_parse_node(State::FlowNode, State::FlowSequenceEntry, false, false),
2809 }
2810 }
2811
2812 fn indentless_sequence_entry<'a>(&mut self) -> ParseResult<'a>
2813 where
2814 'input: 'a,
2815 {
2816 match *self.peek_token()? {
2817 QueuedToken(mark, QueuedTokenType::BlockEntry) => {
2818 self.skip();
2819 #[cfg(feature = "comments")]
2820 {
2821 let comments = self.next_comment_events()?;
2822 if !comments.is_empty() {
2823 if let Ok(QueuedToken(
2824 _,
2825 QueuedTokenType::BlockEntry
2826 | QueuedTokenType::Key
2827 | QueuedTokenType::Value
2828 | QueuedTokenType::BlockEnd,
2829 )) = self.peek_token()
2830 {
2831 self.state = State::IndentlessSequenceEntry;
2832 return Ok(
2833 self.queue_event_by_span(comments, (Event::empty_scalar(), mark))
2834 );
2835 }
2836 self.pending_empty_scalar_span = Some(mark);
2837 self.state = State::IndentlessSequenceEntryNode;
2838 return Ok(self.queue_tail_and_return_first(comments));
2839 }
2840 }
2841 self.indentless_sequence_entry_node_with_empty_span(mark)
2842 }
2843 QueuedToken(mark, _) => {
2844 self.end_block_collection();
2845 self.pop_state();
2846 Ok((Event::SequenceEnd, Span::empty(mark.start)))
2849 }
2850 }
2851 }
2852
2853 fn indentless_sequence_entry_node<'a>(&mut self) -> ParseResult<'a>
2854 where
2855 'input: 'a,
2856 {
2857 self.peek_token()?;
2859 let Some(mark) = self.pending_empty_scalar_span.take() else {
2860 unreachable!(
2861 "indentless sequence entry-node state entered without a pending empty-scalar span"
2862 )
2863 };
2864 self.indentless_sequence_entry_node_with_empty_span(mark)
2865 }
2866
2867 fn indentless_sequence_entry_node_with_empty_span<'a>(&mut self, mark: Span) -> ParseResult<'a>
2868 where
2869 'input: 'a,
2870 {
2871 if let QueuedToken(
2872 _,
2873 QueuedTokenType::BlockEntry
2874 | QueuedTokenType::Key
2875 | QueuedTokenType::Value
2876 | QueuedTokenType::BlockEnd,
2877 ) = *self.peek_token()?
2878 {
2879 self.state = State::IndentlessSequenceEntry;
2880 Ok((Event::empty_scalar(), mark))
2881 } else {
2882 self.defer_parse_node(
2883 State::BlockNode,
2884 State::IndentlessSequenceEntry,
2885 true,
2886 false,
2887 )
2888 }
2889 }
2890
2891 fn block_sequence_entry<'a>(&mut self, _first: bool) -> ParseResult<'a>
2892 where
2893 'input: 'a,
2894 {
2895 match *self.peek_token()? {
2896 QueuedToken(mark, QueuedTokenType::BlockEnd) => {
2897 self.end_block_collection();
2898 self.pop_state();
2899 self.skip();
2900 Ok((Event::SequenceEnd, mark))
2901 }
2902 QueuedToken(mark, QueuedTokenType::BlockEntry) => {
2903 self.skip();
2904 #[cfg(feature = "comments")]
2905 {
2906 let comments = self.next_comment_events()?;
2907 if !comments.is_empty() {
2908 if let Ok(QueuedToken(
2909 _,
2910 QueuedTokenType::BlockEntry | QueuedTokenType::BlockEnd,
2911 )) = self.peek_token()
2912 {
2913 self.state = State::BlockSequenceEntry;
2914 return Ok(
2915 self.queue_event_by_span(comments, (Event::empty_scalar(), mark))
2916 );
2917 }
2918 self.pending_empty_scalar_span = Some(mark);
2919 self.state = State::BlockSequenceEntryNode;
2920 return Ok(self.queue_tail_and_return_first(comments));
2921 }
2922 }
2923 self.block_sequence_entry_node_with_empty_span(mark)
2924 }
2925 QueuedToken(span, _) => Err(ScanError::from_kind(
2926 span.start,
2927 ErrorKind::ExpectedBlockSequenceEntry,
2928 )),
2929 }
2930 }
2931
2932 #[cfg(feature = "comments")]
2933 fn block_sequence_entry_node<'a>(&mut self) -> ParseResult<'a>
2934 where
2935 'input: 'a,
2936 {
2937 self.peek_token()?;
2939 let Some(mark) = self.pending_empty_scalar_span.take() else {
2940 unreachable!(
2941 "block sequence entry-node state entered without a pending empty-scalar span"
2942 )
2943 };
2944 self.block_sequence_entry_node_with_empty_span(mark)
2945 }
2946
2947 fn block_sequence_entry_node_with_empty_span<'a>(&mut self, mark: Span) -> ParseResult<'a>
2948 where
2949 'input: 'a,
2950 {
2951 if let QueuedToken(_, QueuedTokenType::BlockEntry | QueuedTokenType::BlockEnd) =
2952 *self.peek_token()?
2953 {
2954 self.state = State::BlockSequenceEntry;
2955 Ok((Event::empty_scalar(), mark))
2956 } else {
2957 self.defer_parse_node(State::BlockNode, State::BlockSequenceEntry, true, false)
2958 }
2959 }
2960
2961 fn flow_sequence_entry_mapping_key<'a>(&mut self) -> ParseResult<'a>
2962 where
2963 'input: 'a,
2964 {
2965 if let QueuedToken(mark, QueuedTokenType::FlowEntry | QueuedTokenType::FlowSequenceEnd) =
2966 *self.peek_token()?
2967 {
2968 self.state = State::FlowSequenceEntryMappingValue;
2969 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2970 } else {
2971 self.defer_parse_node(
2972 State::FlowNode,
2973 State::FlowSequenceEntryMappingValue,
2974 false,
2975 false,
2976 )
2977 }
2978 }
2979
2980 fn flow_sequence_entry_mapping_value<'a>(&mut self) -> ParseResult<'a>
2981 where
2982 'input: 'a,
2983 {
2984 match *self.peek_token()? {
2985 QueuedToken(_, QueuedTokenType::Value) => {
2986 self.skip();
2987 #[cfg(feature = "comments")]
2988 if let Some(comment) = self.maybe_next_comment_event()? {
2989 self.state = State::FlowSequenceEntryMappingValueNode;
2990 return Ok(comment);
2991 }
2992 self.flow_sequence_entry_mapping_value_node()
2993 }
2994 QueuedToken(mark, _) => {
2995 self.state = State::FlowSequenceEntryMappingEnd;
2996 Ok((Event::empty_scalar(), Span::empty(mark.start)))
2997 }
2998 }
2999 }
3000
3001 fn flow_sequence_entry_mapping_value_node<'a>(&mut self) -> ParseResult<'a>
3002 where
3003 'input: 'a,
3004 {
3005 let QueuedToken(span, ref tok) = *self.peek_token()?;
3006 if matches!(
3007 tok,
3008 QueuedTokenType::FlowEntry | QueuedTokenType::FlowSequenceEnd
3009 ) {
3010 self.state = State::FlowSequenceEntryMappingEnd;
3011 Ok((Event::empty_scalar(), Span::empty(span.start)))
3012 } else {
3013 self.defer_parse_node(
3014 State::FlowNode,
3015 State::FlowSequenceEntryMappingEnd,
3016 false,
3017 false,
3018 )
3019 }
3020 }
3021
3022 #[allow(clippy::unnecessary_wraps)]
3023 fn flow_sequence_entry_mapping_end<'a>(&mut self) -> ParseResult<'a>
3024 where
3025 'input: 'a,
3026 {
3027 self.state = State::FlowSequenceEntry;
3028 let QueuedToken(span, _) = *self.peek_token()?;
3029 Ok((Event::MappingEnd, Span::empty(span.start)))
3030 }
3031
3032 fn resolve_tag(
3034 &self,
3035 span: Span,
3036 handle: Cow<'input, str>,
3037 suffix: Cow<'input, str>,
3038 ) -> Result<Cow<'input, Tag>, ScanError> {
3039 let original_handle = own_tag_component(handle);
3040 let suffix = own_tag_component(suffix);
3041 let handle = if original_handle.is_empty() && suffix == "!" {
3042 Cow::Borrowed("")
3044 } else if let Some(prefix) = self.tags.get(original_handle.as_ref()) {
3045 own_tag_component(Cow::Borrowed(prefix.as_ref()))
3047 } else if original_handle == "!!" {
3048 Cow::Borrowed(YAML_CORE_SCHEMA_PREFIX)
3049 } else {
3050 if original_handle.len() >= 2
3052 && original_handle.starts_with('!')
3053 && original_handle.ends_with('!')
3054 {
3055 return Err(ScanError::from_kind(
3056 span.start,
3057 ErrorKind::UndeclaredTagHandle,
3058 ));
3059 }
3060 original_handle.clone()
3061 };
3062 Ok(Cow::Owned(Tag {
3063 handle,
3064 suffix,
3065 original_handle,
3066 }))
3067 }
3068}
3069
3070impl<'input, T: BorrowedInput<'input>> ParserTrait<'input> for Parser<'input, T> {
3071 fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>> {
3072 if let Some(ref x) = self.current {
3073 Some(Ok(x))
3074 } else if let Some(error) = &self.current_error {
3075 Some(Err(error.clone()))
3076 } else {
3077 if self.stream_end_emitted {
3078 return None;
3079 }
3080 match self.next_event_impl() {
3081 Ok(token) => self.current = Some(token),
3082 Err(error) => {
3083 self.current_error = Some(error.clone());
3084 return Some(Err(error));
3085 }
3086 }
3087 self.current.as_ref().map(Ok)
3088 }
3089 }
3090
3091 fn next_event(&mut self) -> Option<ParseResult<'input>> {
3092 if let Some(error) = self.current_error.take() {
3093 self.stream_end_emitted = true;
3094 return Some(Err(error));
3095 }
3096
3097 if self.stream_end_emitted {
3098 return None;
3099 }
3100
3101 let tok = self.next_event_impl();
3102 if matches!(tok, Ok((Event::StreamEnd, _)) | Err(_)) {
3103 self.stream_end_emitted = true;
3104 }
3105 Some(tok)
3106 }
3107
3108 fn load<R: SpannedEventReceiver<'input>>(
3109 &mut self,
3110 recv: &mut R,
3111 multi: bool,
3112 ) -> Result<(), ScanError> {
3113 let mut recv = InfallibleSpannedReceiver(recv);
3114 into_scan_result(ParserTrait::try_load(self, &mut recv, multi))
3115 }
3116
3117 fn try_load<R: TrySpannedEventReceiver<'input>>(
3118 &mut self,
3119 recv: &mut R,
3120 multi: bool,
3121 ) -> Result<(), TryLoadError<R::Error>> {
3122 let stream_start_buffered = matches!(self.current.as_ref(), Some((Event::StreamStart, _)));
3123 if !self.scanner.stream_started() || stream_start_buffered {
3124 let (ev, span) = self.next_event_for_load()?;
3125 if ev != Event::StreamStart {
3126 self.stream_end_emitted = true;
3127 return Err(TryLoadError::scan(ScanError::from_kind(
3128 span.start,
3129 ErrorKind::ExpectedStreamStart,
3130 )));
3131 }
3132 try_emit(recv, ev, span)?;
3133 }
3134
3135 let has_buffered_result = self.current.is_some() || self.current_error.is_some();
3136 #[cfg(feature = "comments")]
3137 let has_buffered_result =
3138 has_buffered_result || self.deferred_error.is_some() || !self.queued_events.is_empty();
3139 if self.state == State::End && !has_buffered_result {
3140 try_emit(recv, Event::StreamEnd, Span::empty(self.scanner.mark()))?;
3146 self.stream_end_emitted = true;
3147 return Ok(());
3148 }
3149 if self.stream_end_emitted && self.current_error.is_none() {
3150 return Ok(());
3154 }
3155
3156 loop {
3157 let (ev, span) = if let Some(error) = self.current_error.take() {
3158 self.stream_end_emitted = true;
3159 return Err(TryLoadError::scan(error));
3160 } else {
3161 self.next_event_for_load()?
3162 };
3163 let is_doc_end = matches!(ev, Event::DocumentEnd);
3164 let is_stream_end = matches!(ev, Event::StreamEnd);
3165
3166 try_emit(recv, ev, span)?;
3167
3168 if is_stream_end {
3169 self.stream_end_emitted = true;
3170 return Ok(());
3171 }
3172 if !multi && is_doc_end {
3173 return Ok(());
3174 }
3175 }
3176 }
3177}
3178
3179impl<'input, T: BorrowedInput<'input>> Iterator for Parser<'input, T> {
3180 type Item = Result<(Event<'input>, Span), ScanError>;
3181
3182 fn next(&mut self) -> Option<Self::Item> {
3183 self.next_event()
3184 }
3185}
3186
3187impl<'input, T: BorrowedInput<'input>> core::iter::FusedIterator for Parser<'input, T> {}
3188
3189#[cfg(test)]
3190mod test {
3191 #[cfg(feature = "error_messages")]
3192 use alloc::string::String;
3193 use alloc::{borrow::Cow, format, string::ToString, vec, vec::Vec};
3194 #[cfg(feature = "error_messages")]
3195 use core::{error::Error as _, fmt};
3196
3197 #[cfg(feature = "error_messages")]
3198 use crate::error::{ErrorKind, ScanError};
3199 use crate::scanner::{Marker, ScalarStyle, Span};
3200
3201 use super::{
3202 Event, EventReceiver, Parser, State, StructureStyle, Tag, TryEventReceiver, TryLoadError,
3203 TrySpannedEventReceiver, YamlVersion,
3204 };
3205
3206 #[derive(Default)]
3207 struct CollectingSink<'input> {
3208 events: Vec<Event<'input>>,
3209 }
3210
3211 impl<'input> EventReceiver<'input> for CollectingSink<'input> {
3212 fn on_event(&mut self, ev: Event<'input>) {
3213 self.events.push(ev);
3214 }
3215 }
3216
3217 #[cfg(feature = "error_messages")]
3218 fn first_error_info(input: &str) -> String {
3219 for event in Parser::new_from_str(input) {
3220 if let Err(err) = event {
3221 return err.info();
3222 }
3223 }
3224 panic!("expected parser error")
3225 }
3226
3227 fn first_tagged_scalar_tag(input: &str) -> Tag {
3228 Parser::new_from_str(input)
3229 .find_map(|event| match event.expect("input should parse").0 {
3230 Event::Scalar(_, _, _, Some(tag)) => Some(tag.into_owned()),
3231 _ => None,
3232 })
3233 .expect("expected tagged scalar")
3234 }
3235
3236 #[cfg(feature = "comments")]
3237 #[test]
3238 fn deferred_parse_node_can_emit_comment_before_flow_node() {
3239 let mut parser = Parser::new_from_str("---\n# deferred\nvalue\n");
3240 assert_eq!(parser.stream_start().unwrap().0, Event::StreamStart);
3241 assert_eq!(
3242 parser.document_start(true).unwrap().0,
3243 Event::DocumentStart(true, None)
3244 );
3245
3246 let (event, _) = parser
3247 .defer_parse_node(State::FlowNode, State::FlowMappingKey, false, false)
3248 .unwrap();
3249
3250 assert!(matches!(event, Event::Comment(text, _) if text == " deferred"));
3251 assert_eq!(parser.state, State::FlowNode);
3252 }
3253
3254 #[cfg(feature = "comments")]
3255 #[test]
3256 fn queued_node_event_gets_pending_key_indent() {
3257 let mut parser = Parser::new_from_str("");
3258 let span = Span::empty(Marker::new(0, 1, 0));
3259
3260 parser.pending_key_indent = Some(3);
3261 parser
3262 .queued_events
3263 .push_back((Event::SequenceStart(StructureStyle::Block, 0, None), span));
3264
3265 let (event, span) = parser.next_event_impl().unwrap();
3266
3267 assert!(matches!(
3268 event,
3269 Event::SequenceStart(StructureStyle::Block, 0, None)
3270 ));
3271 assert_eq!(span.indent, Some(3));
3272 assert_eq!(parser.pending_key_indent, None);
3273 }
3274
3275 #[test]
3276 fn state_machine_handles_deferred_flow_node_states() {
3277 let mut parser = Parser::new_from_str("value\n");
3278 assert_eq!(parser.stream_start().unwrap().0, Event::StreamStart);
3279 assert_eq!(
3280 parser.document_start(true).unwrap().0,
3281 Event::DocumentStart(false, None)
3282 );
3283 parser.state = State::FlowNode;
3284 parser.push_state(State::End);
3285
3286 let (event, _) = parser.state_machine().unwrap();
3287
3288 assert!(matches!(event, Event::Scalar(value, ..) if value == "value"));
3289 }
3290
3291 #[cfg(feature = "comments")]
3292 #[test]
3293 fn state_machine_handles_deferred_flow_mapping_value_node() {
3294 let mut parser = Parser::new_from_str("value\n");
3295 assert_eq!(parser.stream_start().unwrap().0, Event::StreamStart);
3296 assert_eq!(
3297 parser.document_start(true).unwrap().0,
3298 Event::DocumentStart(false, None)
3299 );
3300 parser.state = State::FlowSequenceEntryMappingValueNode;
3301
3302 let (event, _) = parser.state_machine().unwrap();
3303
3304 assert!(matches!(event, Event::Scalar(value, ..) if value == "value"));
3305 }
3306
3307 #[test]
3308 fn display_resolved_core_tag_without_extra_bang() {
3309 let tag = Tag::with_original_handle("tag:yaml.org,2002:", "str", "!!");
3310
3311 assert_eq!(tag.to_string(), "tag:yaml.org,2002:str");
3312 }
3313
3314 #[test]
3315 fn tag_helpers_distinguish_core_and_local_tags() {
3316 let core = Tag::with_original_handle("tag:yaml.org,2002:", "int", "!!");
3317 let local = Tag::new("!", "thing");
3318 let non_specific = Tag::with_original_handle("", "!", "");
3319 let verbatim = Tag::with_original_handle("", "tag:example.com,2000:thing", "");
3320 let unknown_yaml_org = Tag::with_original_handle("", "tag:yaml.org,2002:application", "");
3321
3322 assert_eq!(core.core_suffix(), Some("int"));
3323 assert!(core.is_yaml_core_schema());
3324 assert!(core.is_yaml_core_schema_tag("int"));
3325 assert!(!core.is_yaml_core_schema_tag("str"));
3326 assert!(!core.is_custom());
3327 assert_eq!(core.parts(), ("tag:yaml.org,2002:", "int"));
3328 assert_eq!(core.original_parts(), ("!!", "int"));
3329 assert_eq!(core.original(), "!!int");
3330
3331 assert_eq!(local.core_suffix(), None);
3332 assert!(!local.is_yaml_core_schema());
3333 assert!(!local.is_yaml_core_schema_tag("thing"));
3334 assert!(local.is_custom());
3335 assert_eq!(local.parts(), ("!", "thing"));
3336 assert_eq!(local.original_parts(), ("!", "thing"));
3337 assert_eq!(local.original(), "!thing");
3338 assert_eq!(local.to_string(), "!thing");
3339
3340 assert_eq!(non_specific.parts(), ("", "!"));
3341 assert_eq!(non_specific.original_parts(), ("", "!"));
3342 assert_eq!(non_specific.original(), "!");
3343
3344 assert_eq!(verbatim.parts(), ("", "tag:example.com,2000:thing"));
3345 assert_eq!(
3346 verbatim.original_parts(),
3347 ("", "tag:example.com,2000:thing")
3348 );
3349 assert_eq!(verbatim.original(), "!<tag:example.com,2000:thing>");
3350
3351 assert_eq!(unknown_yaml_org.core_suffix(), None);
3352 assert!(!unknown_yaml_org.is_yaml_core_schema());
3353 assert!(unknown_yaml_org.is_custom());
3354 }
3355
3356 #[test]
3357 fn core_suffix_uses_resolved_tag_uri_for_common_spellings() {
3358 let cases = [
3359 ("shorthand", "v: !!int 1\n", ("tag:yaml.org,2002:", "int")),
3360 (
3361 "verbatim",
3362 "v: !<tag:yaml.org,2002:int> 1\n",
3363 ("", "tag:yaml.org,2002:int"),
3364 ),
3365 (
3366 "full prefix",
3367 "%TAG !e! tag:yaml.org,2002:\n---\nv: !e!int 1\n",
3368 ("tag:yaml.org,2002:", "int"),
3369 ),
3370 (
3371 "mid-split",
3372 "%TAG !m! tag:yaml.org,2002:i\n---\nv: !m!nt 1\n",
3373 ("tag:yaml.org,2002:i", "nt"),
3374 ),
3375 ];
3376
3377 for (label, input, expected_parts) in cases {
3378 let tag = first_tagged_scalar_tag(input);
3379
3380 assert_eq!(tag.parts(), expected_parts, "{label}");
3381 assert_eq!(tag.core_suffix(), Some("int"), "{label}");
3382 assert!(tag.is_yaml_core_schema(), "{label}");
3383 assert!(tag.is_yaml_core_schema_tag("int"), "{label}");
3384 assert!(!tag.is_yaml_core_schema_tag("str"), "{label}");
3385 assert!(!tag.is_custom(), "{label}");
3386 }
3387 }
3388
3389 #[test]
3390 fn core_suffix_rejects_non_core_yaml_org_tags() {
3391 let cases = [
3392 "binary",
3393 "merge",
3394 "omap",
3395 "pairs",
3396 "set",
3397 "timestamp",
3398 "value",
3399 "yaml",
3400 ];
3401
3402 for suffix in cases {
3403 let tag = Tag::with_original_handle("tag:yaml.org,2002:", suffix, "!!");
3404
3405 assert_eq!(tag.core_suffix(), None, "{suffix}");
3406 assert!(!tag.is_yaml_core_schema(), "{suffix}");
3407 assert!(tag.is_custom(), "{suffix}");
3408 }
3409 }
3410
3411 #[test]
3412 fn core_suffix_rejects_non_core_tags() {
3413 let cases = [
3414 ("local", "v: !local 1\n"),
3415 ("verbatim custom", "v: !<tag:example.com,2000:int> 1\n"),
3416 (
3417 "custom directive",
3418 "%TAG !e! tag:example.com,2000:\n---\nv: !e!int 1\n",
3419 ),
3420 (
3421 "overridden secondary handle",
3422 "%TAG !! tag:example.com,2000:app/\n---\nv: !!int 1\n",
3423 ),
3424 ];
3425
3426 for (label, input) in cases {
3427 let tag = first_tagged_scalar_tag(input);
3428
3429 assert_eq!(tag.core_suffix(), None, "{label}");
3430 assert!(!tag.is_yaml_core_schema(), "{label}");
3431 assert!(!tag.is_yaml_core_schema_tag("int"), "{label}");
3432 assert!(tag.is_custom(), "{label}");
3433 }
3434 }
3435
3436 #[test]
3437 fn suffix_in_namespace_resolves_across_spellings() {
3438 const NS: &str = "tag:yaml.org,2002:";
3439
3440 let shorthand = Tag::with_original_handle(NS, "omap", "!!");
3445 let verbatim = Tag::with_original_handle("", "tag:yaml.org,2002:omap", "");
3446 let mid_split = Tag::with_original_handle("tag:yaml.org,2002:o", "map", "!o!");
3447 let inside_split = Tag::with_original_handle("tag:yaml.org,", "2002:omap", "!y!");
3448 for tag in [&shorthand, &verbatim, &mid_split, &inside_split] {
3449 assert_eq!(tag.suffix_in_namespace(NS).as_deref(), Some("omap"));
3450 assert_eq!(tag.core_suffix(), None);
3451 }
3452
3453 assert!(matches!(
3456 shorthand.suffix_in_namespace(NS),
3457 Some(Cow::Borrowed(_))
3458 ));
3459 assert!(matches!(
3460 verbatim.suffix_in_namespace(NS),
3461 Some(Cow::Borrowed(_))
3462 ));
3463 assert!(matches!(
3464 inside_split.suffix_in_namespace(NS),
3465 Some(Cow::Borrowed(_))
3466 ));
3467 assert!(matches!(
3468 mid_split.suffix_in_namespace(NS),
3469 Some(Cow::Owned(_))
3470 ));
3471
3472 let merge = Tag::with_original_handle(NS, "merge", "!!");
3475 assert_eq!(merge.suffix_in_namespace(NS).as_deref(), Some("merge"));
3476 assert_eq!(merge.core_suffix(), None);
3477 assert_eq!(
3478 Tag::new(NS, "int").suffix_in_namespace(NS).as_deref(),
3479 Some("int")
3480 );
3481
3482 assert_eq!(Tag::new("!", "omap").suffix_in_namespace(NS), None);
3484 assert_eq!(
3485 Tag::with_original_handle("", "tag:example.com,2000:omap", "").suffix_in_namespace(NS),
3486 None
3487 );
3488 }
3489
3490 #[test]
3491 fn attach_tag_span_preserves_node_span() {
3492 let event = Event::Scalar("value".into(), ScalarStyle::Plain, 0, None);
3493 let span = Span::new(Marker::new(6, 1, 6), Marker::new(11, 1, 11));
3494 let tag_start = Marker::new(0, 1, 0);
3495
3496 let (attached_event, attached_span) =
3497 Parser::<crate::input::str::StrInput<'_>>::attach_tag_span(
3498 event.clone(),
3499 span,
3500 Some((tag_start, 4)),
3501 );
3502
3503 assert_eq!(attached_event, event);
3504 assert_eq!(attached_span.start, span.start);
3505 assert_eq!(attached_span.end, span.end);
3506 assert_eq!(attached_span.tag_start(), Some(tag_start));
3507 assert_eq!(
3508 attached_span.tag_span(),
3509 Some(Span::new(tag_start, Marker::new(4, 1, 4)))
3510 );
3511 }
3512
3513 #[test]
3514 fn event_inspection_helpers_report_node_metadata() {
3515 let tag = Tag::new("!", "thing");
3516 let scalar = Event::Scalar(
3517 "value".into(),
3518 ScalarStyle::DoubleQuoted,
3519 7,
3520 Some(Cow::Borrowed(&tag)),
3521 );
3522 let sequence =
3523 Event::SequenceStart(StructureStyle::Block, 8, Some(Cow::Owned(tag.clone())));
3524 let mapping = Event::MappingStart(StructureStyle::Block, 9, Some(Cow::Borrowed(&tag)));
3525
3526 assert_eq!(scalar.anchor_id(), Some(7));
3527 assert_eq!(scalar.alias_id(), None);
3528 assert_eq!(scalar.tag(), Some(&tag));
3529 assert_eq!(scalar.scalar(), Some(("value", ScalarStyle::DoubleQuoted)));
3530 assert!(scalar.is_node());
3531
3532 assert_eq!(sequence.anchor_id(), Some(8));
3533 assert_eq!(sequence.alias_id(), None);
3534 assert_eq!(sequence.tag(), Some(&tag));
3535 assert_eq!(sequence.scalar(), None);
3536 assert!(sequence.is_node());
3537
3538 assert_eq!(mapping.anchor_id(), Some(9));
3539 assert_eq!(mapping.alias_id(), None);
3540 assert_eq!(mapping.tag(), Some(&tag));
3541 assert_eq!(mapping.scalar(), None);
3542 assert!(mapping.is_node());
3543
3544 let alias = Event::Alias(10);
3545 assert_eq!(alias.anchor_id(), None);
3546 assert_eq!(alias.alias_id(), Some(10));
3547 assert_eq!(alias.tag(), None);
3548 assert_eq!(alias.scalar(), None);
3549 assert!(alias.is_node());
3550
3551 let unanchored_scalar = Event::Scalar("x".into(), ScalarStyle::Plain, 0, None);
3552 assert_eq!(unanchored_scalar.anchor_id(), None);
3553 assert_eq!(unanchored_scalar.alias_id(), None);
3554
3555 let stream_start = Event::StreamStart;
3556 assert_eq!(stream_start.anchor_id(), None);
3557 assert_eq!(stream_start.alias_id(), None);
3558 assert_eq!(stream_start.tag(), None);
3559 assert_eq!(stream_start.scalar(), None);
3560 assert!(!stream_start.is_node());
3561 }
3562
3563 #[test]
3564 fn test_peek_eq_parse() {
3565 let s = "
3566a0 bb: val
3567a1: &x
3568 b1: 4
3569 b2: d
3570a2: 4
3571a3: [1, 2, 3]
3572a4:
3573 - [a1, a2]
3574 - 2
3575a5: *x
3576";
3577 let mut p = Parser::new_from_str(s);
3578 loop {
3579 let event_peek = p.peek().unwrap().unwrap().clone();
3580 let event = p.next_event().unwrap().unwrap();
3581 assert_eq!(event, event_peek);
3582 if event.0 == Event::StreamEnd {
3583 break;
3584 }
3585 }
3586 }
3587
3588 #[test]
3589 fn test_repeated_peek_returns_buffered_event() {
3590 let mut parser = Parser::new_from_str("key: value\n");
3591
3592 let first_peek = parser.peek().unwrap().unwrap().clone();
3593 let second_peek = parser.peek().unwrap().unwrap().clone();
3594 let next = parser.next_event().unwrap().unwrap();
3595
3596 assert_eq!(first_peek, second_peek);
3597 assert_eq!(first_peek, next);
3598 }
3599
3600 #[cfg(feature = "error_messages")]
3601 #[test]
3602 fn test_peek_surfaces_scan_error_without_consuming_stream_end_state() {
3603 let mut parser = Parser::new_from_str("a: [1, 2");
3604
3605 loop {
3606 match parser.peek() {
3607 Some(Ok(_)) => {
3608 parser.next_event().unwrap().unwrap();
3609 }
3610 Some(Err(error)) => {
3611 assert_eq!(error.info(), "unclosed bracket '['");
3612 break;
3613 }
3614 None => panic!("expected parse error"),
3615 }
3616 }
3617 }
3618
3619 #[test]
3620 fn test_iterator_terminates_after_scan_error() {
3621 let parser = Parser::new_from_str("foo:\n bar\ninvalid\n");
3622 let mut errors = 0usize;
3623 let mut events = 0usize;
3624
3625 for item in parser {
3626 events += 1;
3627 if item.is_err() {
3628 errors += 1;
3629 }
3630 assert!(
3631 events < 1000,
3632 "parser iterator did not terminate after a scan error"
3633 );
3634 }
3635
3636 assert_eq!(errors, 1);
3637 }
3638
3639 #[cfg(feature = "error_messages")]
3640 #[test]
3641 fn test_iterator_terminates_after_node_property_error() {
3642 let parser = Parser::new_from_str("- *nope\n- 2\n");
3643 let mut errors = 0usize;
3644 let mut saw_later_node = false;
3645 let mut events = 0usize;
3646
3647 for item in parser {
3648 events += 1;
3649 match item {
3650 Ok((Event::Scalar(value, ..), _)) if value == "2" => saw_later_node = true,
3651 Ok(_) => {}
3652 Err(error) => {
3653 assert_eq!(error.info(), "while parsing node, found unknown anchor");
3654 errors += 1;
3655 }
3656 }
3657 assert!(
3658 events < 1000,
3659 "parser iterator did not terminate after a node-property error"
3660 );
3661 }
3662
3663 assert_eq!(errors, 1);
3664 assert!(!saw_later_node, "parser resumed after the alias error");
3665 }
3666
3667 #[test]
3668 fn test_peeked_scan_error_is_returned_once_by_next_event() {
3669 let mut parser = Parser::new_from_str("a: [1, 2");
3670
3671 let first_error = loop {
3672 match parser.peek() {
3673 Some(Ok(_)) => {
3674 parser.next_event().unwrap().unwrap();
3675 }
3676 Some(Err(error)) => break error,
3677 None => panic!("expected parse error"),
3678 }
3679 };
3680 let Some(Err(second_error)) = parser.peek() else {
3681 panic!("expected cached parse error");
3682 };
3683
3684 assert_eq!(first_error, second_error);
3685 assert_eq!(parser.next_event().unwrap().unwrap_err(), first_error);
3686 assert!(parser.next_event().is_none());
3687 assert!(parser.peek().is_none());
3688 }
3689
3690 #[cfg(feature = "error_messages")]
3691 #[test]
3692 fn test_peeked_node_property_error_is_stable_and_terminal() {
3693 let mut parser = Parser::new_from_str("a: *nope\nb: 2\n");
3694
3695 for _ in 0..4 {
3696 parser.next_event().unwrap().unwrap();
3697 }
3698
3699 let Some(Err(first_error)) = parser.peek() else {
3700 panic!("expected unknown alias error");
3701 };
3702 let Some(Err(second_error)) = parser.peek() else {
3703 panic!("expected cached unknown alias error");
3704 };
3705
3706 assert_eq!(first_error, second_error);
3707 assert_eq!(
3708 first_error.info(),
3709 "while parsing node, found unknown anchor"
3710 );
3711 assert_eq!(parser.next_event().unwrap().unwrap_err(), first_error);
3712 assert!(parser.next_event().is_none());
3713 assert!(parser.peek().is_none());
3714 }
3715
3716 #[test]
3717 fn test_peek_and_next_return_none_after_stream_end() {
3718 let mut parser = Parser::new_from_str("");
3719
3720 assert!(matches!(
3721 parser.next_event().unwrap().unwrap().0,
3722 Event::StreamStart
3723 ));
3724 assert!(matches!(
3725 parser.next_event().unwrap().unwrap().0,
3726 Event::StreamEnd
3727 ));
3728 assert!(parser.next_event().is_none());
3729 assert!(parser.peek().is_none());
3730 }
3731
3732 #[test]
3733 fn test_load_after_stream_already_ended_emits_stream_end() {
3734 let mut parser = Parser::new_from_str("");
3735 while parser.next_event().is_some() {}
3736
3737 let mut sink = CollectingSink::default();
3738 parser.load(&mut sink, true).unwrap();
3739
3740 assert_eq!(sink.events, vec![Event::StreamEnd]);
3741 }
3742
3743 #[test]
3744 fn test_load_full_stream_fuses_iterator_after_stream_end() {
3745 let mut parser = Parser::new_from_str("a: 1\n");
3746 let mut sink = CollectingSink::default();
3747
3748 parser.load(&mut sink, true).unwrap();
3749
3750 assert!(matches!(sink.events.last(), Some(Event::StreamEnd)));
3751 assert!(parser.next_event().is_none());
3752 assert!(parser.peek().is_none());
3753 }
3754
3755 #[test]
3756 fn test_load_after_peek_delivers_buffered_document_end_before_stream_end() {
3757 let mut parser = Parser::new_from_str("a");
3758 for _ in 0..3 {
3759 parser.next_event().unwrap().unwrap();
3760 }
3761
3762 assert_eq!(parser.peek().unwrap().unwrap().0, Event::DocumentEnd);
3763
3764 let mut sink = CollectingSink::default();
3765 parser.load(&mut sink, true).unwrap();
3766
3767 assert_eq!(sink.events, vec![Event::DocumentEnd, Event::StreamEnd]);
3768 assert!(parser.next_event().is_none());
3769 }
3770
3771 #[test]
3772 fn test_load_visits_nested_collection_events() {
3773 let mut parser = Parser::new_from_str("root:\n - item: value\n - [a, b]\n");
3774 let mut sink = CollectingSink::default();
3775
3776 parser.load(&mut sink, true).unwrap();
3777
3778 assert_eq!(
3779 sink.events,
3780 vec![
3781 Event::StreamStart,
3782 Event::DocumentStart(false, None),
3783 Event::MappingStart(StructureStyle::Block, 0, None),
3784 Event::Scalar("root".into(), ScalarStyle::Plain, 0, None),
3785 Event::SequenceStart(StructureStyle::Block, 0, None),
3786 Event::MappingStart(StructureStyle::Block, 0, None),
3787 Event::Scalar("item".into(), ScalarStyle::Plain, 0, None),
3788 Event::Scalar("value".into(), ScalarStyle::Plain, 0, None),
3789 Event::MappingEnd,
3790 Event::SequenceStart(StructureStyle::Flow, 0, None),
3791 Event::Scalar("a".into(), ScalarStyle::Plain, 0, None),
3792 Event::Scalar("b".into(), ScalarStyle::Plain, 0, None),
3793 Event::SequenceEnd,
3794 Event::SequenceEnd,
3795 Event::MappingEnd,
3796 Event::DocumentEnd,
3797 Event::StreamEnd,
3798 ]
3799 );
3800 }
3801
3802 #[derive(Clone, Debug, PartialEq, Eq)]
3803 enum ValidationError {
3804 ForbiddenValue,
3805 }
3806
3807 #[cfg(feature = "error_messages")]
3808 #[derive(Debug)]
3809 struct ReceiverFailure;
3810
3811 #[cfg(feature = "error_messages")]
3812 impl fmt::Display for ReceiverFailure {
3813 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3814 write!(f, "receiver failed")
3815 }
3816 }
3817
3818 #[cfg(feature = "error_messages")]
3819 impl core::error::Error for ReceiverFailure {}
3820
3821 struct FailingSink<'input> {
3822 events: Vec<Event<'input>>,
3823 }
3824
3825 impl<'input> TryEventReceiver<'input> for FailingSink<'input> {
3826 type Error = ValidationError;
3827
3828 fn on_event(&mut self, ev: Event<'input>) -> Result<(), Self::Error> {
3829 let should_fail = matches!(&ev, Event::Scalar(value, ..) if value.as_ref() == "bad");
3830 self.events.push(ev);
3831 if should_fail {
3832 Err(ValidationError::ForbiddenValue)
3833 } else {
3834 Ok(())
3835 }
3836 }
3837 }
3838
3839 #[test]
3840 fn test_try_load_stops_on_receiver_error() {
3841 let mut parser = Parser::new_from_str("ok: bad\nafter: value\n");
3842 let mut sink = FailingSink { events: Vec::new() };
3843
3844 let err = parser.try_load(&mut sink, true).unwrap_err();
3845
3846 assert_eq!(err, TryLoadError::Receiver(ValidationError::ForbiddenValue));
3847 assert!(sink
3848 .events
3849 .iter()
3850 .any(|event| matches!(event, Event::Scalar(value, ..) if value == "ok")));
3851 assert!(sink
3852 .events
3853 .iter()
3854 .any(|event| matches!(event, Event::Scalar(value, ..) if value == "bad")));
3855 assert!(!sink
3856 .events
3857 .iter()
3858 .any(|event| matches!(event, Event::Scalar(value, ..) if value == "after")));
3859 }
3860
3861 struct SpannedFailingSink {
3862 failed_span: Option<Span>,
3863 }
3864
3865 impl<'input> TrySpannedEventReceiver<'input> for SpannedFailingSink {
3866 type Error = Span;
3867
3868 fn on_event(&mut self, ev: Event<'input>, span: Span) -> Result<(), Self::Error> {
3869 if matches!(ev, Event::Scalar(value, ..) if value.as_ref() == "bad") {
3870 self.failed_span = Some(span);
3871 Err(span)
3872 } else {
3873 Ok(())
3874 }
3875 }
3876 }
3877
3878 #[test]
3879 fn test_try_load_spanned_receiver_gets_span() {
3880 let mut parser = Parser::new_from_str("value: bad\n");
3881 let mut sink = SpannedFailingSink { failed_span: None };
3882
3883 let err = parser.try_load(&mut sink, false).unwrap_err();
3884
3885 let TryLoadError::Receiver(span) = err else {
3886 panic!("expected receiver error");
3887 };
3888
3889 assert_eq!(Some(span), sink.failed_span);
3890 assert!(!span.is_empty());
3891 }
3892
3893 #[cfg(feature = "error_messages")]
3894 struct NeverFails {
3895 count: usize,
3896 }
3897
3898 #[cfg(feature = "error_messages")]
3899 impl<'input> TryEventReceiver<'input> for NeverFails {
3900 type Error = ValidationError;
3901
3902 fn on_event(&mut self, _ev: Event<'input>) -> Result<(), Self::Error> {
3903 self.count += 1;
3904 Ok(())
3905 }
3906 }
3907
3908 #[cfg(feature = "error_messages")]
3909 #[test]
3910 fn test_try_load_returns_scan_error() {
3911 let mut parser = Parser::new_from_str("%YAML 1.2\n%YAML 1.2\n---\n");
3912 let mut sink = NeverFails { count: 0 };
3913
3914 let err = parser.try_load(&mut sink, true).unwrap_err();
3915
3916 let TryLoadError::Scan(err) = err else {
3917 panic!("expected scan error");
3918 };
3919 assert_eq!(err.kind(), &ErrorKind::DuplicateVersionDirective);
3920 assert_eq!(err.info(), "duplicate version directive");
3921 }
3922
3923 #[cfg(feature = "error_messages")]
3924 #[test]
3925 fn test_try_load_error_display_and_source_cover_both_variants() {
3926 let scan = ScanError::from_kind(Marker::new(3, 1, 3), ErrorKind::UnexpectedEof);
3927 let scan_err: TryLoadError<ReceiverFailure> = scan.into();
3928
3929 assert!(scan_err
3930 .to_string()
3931 .starts_with("parser error: unexpected eof"));
3932 assert!(scan_err.source().is_some());
3933
3934 let receiver_err = TryLoadError::Receiver(ReceiverFailure);
3935
3936 assert_eq!(receiver_err.to_string(), "receiver error: receiver failed");
3937 assert!(receiver_err.source().is_some());
3938 }
3939
3940 #[cfg(feature = "error_messages")]
3941 #[test]
3942 fn test_try_load_requires_buffered_stream_start() {
3943 let mut parser = Parser::new_from_str("");
3944 let span = Span::empty(Marker::new(0, 1, 0));
3945 parser.current = Some((
3946 Event::Scalar("value".into(), ScalarStyle::Plain, 0, None),
3947 span,
3948 ));
3949 let mut sink = NeverFails { count: 0 };
3950
3951 let err = parser.try_load(&mut sink, true).unwrap_err();
3952
3953 let TryLoadError::Scan(err) = err else {
3954 panic!("expected scan error");
3955 };
3956 assert_eq!(err.info(), "did not find expected <stream-start>");
3957 }
3958
3959 #[test]
3960 fn test_try_load_after_stream_already_ended_emits_stream_end() {
3961 let mut parser = Parser::new_from_str("");
3962 while parser.next_event().is_some() {}
3963
3964 let mut sink = FailingSink { events: Vec::new() };
3965 parser.try_load(&mut sink, true).unwrap();
3966
3967 assert_eq!(sink.events, vec![Event::StreamEnd]);
3968 }
3969
3970 #[test]
3971 fn test_try_load_full_stream_fuses_iterator_after_stream_end() {
3972 let mut parser = Parser::new_from_str("a: 1\n");
3973 let mut sink = FailingSink { events: Vec::new() };
3974
3975 parser.try_load(&mut sink, true).unwrap();
3976
3977 assert!(matches!(sink.events.last(), Some(Event::StreamEnd)));
3978 assert!(parser.next_event().is_none());
3979 assert!(parser.peek().is_none());
3980 }
3981
3982 #[test]
3983 fn test_try_load_after_peek_delivers_buffered_document_end_before_stream_end() {
3984 let mut parser = Parser::new_from_str("a");
3985 for _ in 0..3 {
3986 parser.next_event().unwrap().unwrap();
3987 }
3988
3989 assert_eq!(parser.peek().unwrap().unwrap().0, Event::DocumentEnd);
3990
3991 let mut sink = FailingSink { events: Vec::new() };
3992 parser.try_load(&mut sink, true).unwrap();
3993
3994 assert_eq!(sink.events, vec![Event::DocumentEnd, Event::StreamEnd]);
3995 assert!(parser.next_event().is_none());
3996 }
3997
3998 #[test]
3999 fn test_load_single_document_stops_before_next_document() {
4000 let mut parser = Parser::new_from_str("a: 1\n---\nb: 2\n");
4001 let mut sink = CollectingSink::default();
4002
4003 parser.load(&mut sink, false).unwrap();
4004
4005 assert!(sink
4006 .events
4007 .iter()
4008 .any(|event| matches!(event, Event::Scalar(value, ..) if value == "a")));
4009 assert!(!sink
4010 .events
4011 .iter()
4012 .any(|event| matches!(event, Event::Scalar(value, ..) if value == "b")));
4013 assert!(matches!(sink.events.last(), Some(Event::DocumentEnd)));
4014 }
4015
4016 #[cfg(feature = "error_messages")]
4017 #[test]
4018 fn test_duplicate_version_directive_errors() {
4019 assert_eq!(
4020 first_error_info("%YAML 1.2\n%YAML 1.2\n---\n"),
4021 "duplicate version directive"
4022 );
4023 }
4024
4025 #[cfg(feature = "error_messages")]
4026 #[test]
4027 fn test_unsupported_yaml_major_version_errors() {
4028 assert_eq!(
4029 first_error_info("%YAML 9.9\n--- a\n"),
4030 "unsupported YAML major version"
4031 );
4032 }
4033
4034 #[test]
4035 fn test_document_start_emits_yaml_version() {
4036 let events = Parser::new_from_str("%YAML 1.2\n---\nvalue\n")
4037 .map(|event| event.unwrap().0)
4038 .collect::<Vec<_>>();
4039
4040 assert!(matches!(
4041 events.get(1),
4042 Some(Event::DocumentStart(
4043 true,
4044 Some(YamlVersion { major: 1, minor: 2 })
4045 ))
4046 ));
4047 }
4048
4049 #[test]
4050 fn test_document_start_allows_supported_major_future_minor_version() {
4051 let events = Parser::new_from_str("%YAML 1.9\n---\nvalue\n")
4052 .map(|event| event.unwrap().0)
4053 .collect::<Vec<_>>();
4054
4055 assert!(matches!(
4056 events.get(1),
4057 Some(Event::DocumentStart(
4058 true,
4059 Some(YamlVersion { major: 1, minor: 9 })
4060 ))
4061 ));
4062 }
4063
4064 #[test]
4065 fn test_document_start_keeps_version_and_tags_across_comment() {
4066 let events = Parser::new_from_str(
4067 "%YAML 1.2\n# directive comment\n%TAG !e! tag:example.com,2026:\n---\nkey: !e!thing value\n",
4068 )
4069 .map(|event| event.unwrap().0)
4070 .filter(|event| {
4071 #[cfg(feature = "comments")]
4072 {
4073 !matches!(event, Event::Comment(..))
4074 }
4075 #[cfg(not(feature = "comments"))]
4076 {
4077 let _ = event;
4078 true
4079 }
4080 })
4081 .collect::<Vec<_>>();
4082
4083 assert!(matches!(
4084 events.get(1),
4085 Some(Event::DocumentStart(
4086 true,
4087 Some(YamlVersion { major: 1, minor: 2 })
4088 ))
4089 ));
4090
4091 let tag = events
4092 .iter()
4093 .find_map(|event| match event {
4094 Event::Scalar(value, _, _, Some(tag)) if value == "value" => Some(tag),
4095 _ => None,
4096 })
4097 .expect("expected tagged scalar after comment-separated directives");
4098
4099 assert_eq!(tag.handle, "tag:example.com,2026:");
4100 assert_eq!(tag.suffix, "thing");
4101 }
4102
4103 #[cfg(feature = "comments")]
4104 #[test]
4105 fn tag_directive_state_borrows_str_input_across_comment() {
4106 let mut parser = Parser::new_from_str(
4107 "%TAG !e! tag:example.com,2026:\n# directive comment\n---\nkey: value\n",
4108 );
4109
4110 while let Some(event) = parser.next_event() {
4111 if matches!(event.unwrap().0, Event::Comment(..)) {
4112 break;
4113 }
4114 }
4115
4116 assert!(matches!(
4117 parser.tags.get("!e!"),
4118 Some(Cow::Borrowed("tag:example.com,2026:"))
4119 ));
4120 assert!(parser
4121 .pending_document_tag_handles
4122 .iter()
4123 .any(|handle| matches!(handle, Cow::Borrowed("!e!"))));
4124 }
4125
4126 #[test]
4127 fn test_each_document_can_declare_own_yaml_version() {
4128 let document_starts = Parser::new_from_str(
4129 "%YAML 1.2\n---\na\n...\n%YAML 1.2\n---\nb\n...\n%YAML 1.1\n---\nc\n",
4130 )
4131 .filter_map(|event| match event.unwrap().0 {
4132 Event::DocumentStart(explicit, version) => Some((explicit, version)),
4133 _ => None,
4134 })
4135 .collect::<Vec<_>>();
4136
4137 assert_eq!(
4138 document_starts,
4139 vec![
4140 (true, Some(YamlVersion::new(1, 2))),
4141 (true, Some(YamlVersion::new(1, 2))),
4142 (true, Some(YamlVersion::new(1, 1))),
4143 ]
4144 );
4145 }
4146
4147 #[cfg(feature = "error_messages")]
4148 #[test]
4149 fn test_duplicate_tag_directive_errors() {
4150 assert_eq!(
4151 first_error_info("%TAG !t! tag:test,2024:\n%TAG !t! tag:other,2024:\n---\n"),
4152 "the TAG directive must only be given at most once per handle in the same document"
4153 );
4154 }
4155
4156 #[cfg(feature = "error_messages")]
4157 #[test]
4158 fn duplicate_tag_directive_across_comment_is_rejected() {
4159 let input = concat!(
4160 "%TAG !e! tag:example.com,2000:one/\n",
4161 "# separator\n",
4162 "%TAG !e! tag:example.com,2000:two/\n",
4163 "---\n",
4164 );
4165
4166 assert_eq!(
4167 first_error_info(input),
4168 "the TAG directive must only be given at most once per handle in the same document"
4169 );
4170 }
4171
4172 #[test]
4173 fn test_keep_tags_inherited_handle_can_be_redeclared_in_next_document() {
4174 let input = concat!(
4175 "%TAG !e! tag:example.com,2000:one/\n",
4176 "---\n",
4177 "first: !e!thing value\n",
4178 "...\n",
4179 "%TAG !e! tag:example.com,2000:two/\n",
4180 "---\n",
4181 "second: !e!thing value\n",
4182 );
4183
4184 let tags = Parser::new_from_str(input)
4185 .keep_tags(true)
4186 .filter_map(|event| match event.expect("input should parse").0 {
4187 Event::Scalar(value, _, _, Some(tag)) if value == "value" => {
4188 Some(tag.handle.clone())
4189 }
4190 _ => None,
4191 })
4192 .collect::<Vec<_>>();
4193
4194 assert_eq!(
4195 tags,
4196 vec!["tag:example.com,2000:one/", "tag:example.com,2000:two/"]
4197 );
4198 }
4199
4200 #[cfg(feature = "error_messages")]
4201 #[test]
4202 fn test_directive_after_implicit_document_requires_explicit_end() {
4203 assert_eq!(
4204 first_error_info("---\nkey: value\n%YAML 1.2\n---\n"),
4205 "missing explicit document end marker before directive"
4206 );
4207 }
4208
4209 #[cfg(feature = "error_messages")]
4210 #[test]
4211 fn test_anchor_offset_overflow_reports_error() {
4212 let mut parser = Parser::new_from_str("&a value");
4213 parser.set_anchor_offset(usize::MAX);
4214
4215 let err = parser
4216 .find_map(Result::err)
4217 .expect("anchor registration should overflow");
4218
4219 assert_eq!(
4220 err.info(),
4221 "while parsing anchor, anchor count exceeded supported limit"
4222 );
4223 }
4224
4225 #[test]
4226 fn test_alias_resolves_to_registered_anchor_id() {
4227 let events = Parser::new_from_str("- &a value\n- *a\n")
4228 .map(|event| event.unwrap().0)
4229 .collect::<Vec<_>>();
4230
4231 assert!(events.iter().any(|event| matches!(event, Event::Alias(1))));
4232 }
4233
4234 #[test]
4235 fn test_anchor_then_tag_applies_both_to_scalar() {
4236 let events = Parser::new_from_str("&a !!str value")
4237 .map(|event| event.unwrap().0)
4238 .collect::<Vec<_>>();
4239
4240 let Some(Event::Scalar(value, _, anchor_id, Some(tag))) = events
4241 .iter()
4242 .find(|event| matches!(event, Event::Scalar(value, ..) if value == "value"))
4243 else {
4244 panic!("expected tagged anchored scalar");
4245 };
4246
4247 assert_eq!(value, "value");
4248 assert_eq!(*anchor_id, 1);
4249 assert_eq!(tag.handle, "tag:yaml.org,2002:");
4250 assert_eq!(tag.suffix, "str");
4251 assert_eq!(tag.original_handle, "!!");
4252 assert_eq!(tag.original(), "!!str");
4253 }
4254
4255 #[test]
4256 fn test_tag_then_anchor_applies_both_to_scalar() {
4257 let events = Parser::new_from_str("!!str &a value")
4258 .map(|event| event.unwrap().0)
4259 .collect::<Vec<_>>();
4260
4261 let Some(Event::Scalar(value, _, anchor_id, Some(tag))) = events
4262 .iter()
4263 .find(|event| matches!(event, Event::Scalar(value, ..) if value == "value"))
4264 else {
4265 panic!("expected tagged anchored scalar");
4266 };
4267
4268 assert_eq!(value, "value");
4269 assert_eq!(*anchor_id, 1);
4270 assert_eq!(tag.handle, "tag:yaml.org,2002:");
4271 assert_eq!(tag.suffix, "str");
4272 assert_eq!(tag.original_handle, "!!");
4273 assert_eq!(tag.original(), "!!str");
4274 }
4275
4276 #[test]
4277 fn test_tag_directive_preserves_original_handle() {
4278 let events =
4279 Parser::new_from_str("%TAG !e! tag:example.com,2000:\n---\nconfig: !e!keep value\n")
4280 .map(|event| event.unwrap().0)
4281 .collect::<Vec<_>>();
4282
4283 let (value, tag) = events
4284 .iter()
4285 .find_map(|event| match event {
4286 Event::Scalar(value, _, _, Some(tag)) if value == "value" => Some((value, tag)),
4287 _ => None,
4288 })
4289 .expect("expected tagged scalar");
4290
4291 assert_eq!(value, "value");
4292 assert_eq!(tag.handle, "tag:example.com,2000:");
4293 assert_eq!(tag.suffix, "keep");
4294 assert_eq!(tag.original_handle, "!e!");
4295 assert_eq!(tag.parts(), ("tag:example.com,2000:", "keep"));
4296 assert_eq!(tag.original_parts(), ("!e!", "keep"));
4297 assert_eq!(tag.original(), "!e!keep");
4298 }
4299
4300 #[test]
4301 fn test_verbatim_tag_original_is_normalized_author_spelling() {
4302 let events = Parser::new_from_str("key: !<tag:example.com,2000:thing> value\n")
4303 .map(|event| event.unwrap().0)
4304 .collect::<Vec<_>>();
4305
4306 let Some(Event::Scalar(value, _, _, Some(tag))) = events
4307 .iter()
4308 .find(|event| matches!(event, Event::Scalar(value, ..) if value == "value"))
4309 else {
4310 panic!("expected tagged scalar");
4311 };
4312
4313 assert_eq!(value, "value");
4314 assert_eq!(tag.handle, "");
4315 assert_eq!(tag.suffix, "tag:example.com,2000:thing");
4316 assert_eq!(tag.original_handle, "");
4317 assert_eq!(tag.parts(), ("", "tag:example.com,2000:thing"));
4318 assert_eq!(tag.original_parts(), ("", "tag:example.com,2000:thing"));
4319 assert_eq!(tag.original(), "!<tag:example.com,2000:thing>");
4320 }
4321
4322 #[test]
4323 fn test_multiple_tag_directives_are_kept_within_document() {
4324 let text = r"
4325%TAG !a! tag:a,2024:
4326%TAG !b! tag:b,2024:
4327---
4328first: !a!x foo
4329second: !b!y bar
4330";
4331
4332 let mut seen_a = false;
4333 let mut seen_b = false;
4334 for event in Parser::new_from_str(text) {
4335 let (event, _) = event.unwrap();
4336 if let Event::Scalar(_, _, _, Some(tag)) = event {
4337 if tag.handle == "tag:a,2024:" {
4338 seen_a = true;
4339 } else if tag.handle == "tag:b,2024:" {
4340 seen_b = true;
4341 }
4342 }
4343 }
4344
4345 assert!(seen_a);
4346 assert!(seen_b);
4347 }
4348
4349 #[cfg(feature = "error_messages")]
4350 #[test]
4351 fn test_tags_are_cleared_when_next_document_has_no_directives() {
4352 let text = r"
4353%TAG !t! tag:test,2024:
4354--- !t!1
4355foo
4356--- !t!2
4357bar
4358";
4359
4360 let mut parser = Parser::new_from_str(text);
4361 for event in parser.by_ref() {
4362 let (event, _) = event.unwrap();
4363 if let Event::DocumentEnd = event {
4364 break;
4365 }
4366 }
4367
4368 match parser.next().unwrap().unwrap().0 {
4369 Event::DocumentStart(true, None) => {}
4370 _ => panic!("expected explicit second document start"),
4371 }
4372
4373 let err = parser.next().unwrap().unwrap_err();
4374 assert!(format!("{err}").contains("the handle wasn't declared"));
4375 }
4376
4377 #[cfg(feature = "error_messages")]
4378 #[test]
4379 fn test_pull_parser_clears_anchors_between_documents() {
4380 let mut parser = Parser::new_from_str(
4381 "--- &a value
4382--- *a
4383",
4384 );
4385
4386 for event in parser.by_ref() {
4387 let (event, _) = event.unwrap();
4388 if matches!(event, Event::DocumentEnd) {
4389 break;
4390 }
4391 }
4392
4393 match parser.next().unwrap().unwrap().0 {
4394 Event::DocumentStart(true, None) => {}
4395 _ => panic!("expected explicit second document start"),
4396 }
4397
4398 let err = parser.next().unwrap().unwrap_err();
4399 assert!(format!("{err}").contains("unknown anchor"));
4400 }
4401
4402 #[test]
4403 fn test_keep_tags_across_multiple_documents() {
4404 let text = r#"
4405%YAML 1.1
4406%TAG !t! tag:test,2024:
4407--- !t!1 &1
4408foo: "bar"
4409--- !t!2 &2
4410baz: "qux"
4411"#;
4412 for x in Parser::new_from_str(text).keep_tags(true) {
4413 let x = x.unwrap();
4414 if let Event::MappingStart(_, _, tag) = x.0 {
4415 let tag = tag.unwrap();
4416 assert_eq!(tag.handle, "tag:test,2024:");
4417 }
4418 }
4419
4420 for x in Parser::new_from_str(text).keep_tags(false) {
4421 if x.is_err() {
4422 return;
4424 }
4425 }
4426 panic!("Test failed, did not encounter error")
4427 }
4428
4429 #[test]
4430 fn test_flow_sequence_mapping_allows_empty_key() {
4431 let parser = Parser::new_from_str("[?: value]");
4432 for event in parser {
4433 event.expect("parser should accept flow sequence mappings with empty keys");
4434 }
4435 }
4436
4437 #[test]
4438 fn test_keep_tags_does_not_persist_default_tag_handles() {
4439 let text = "%TAG !! tag:evil,2024:\n--- !!int 1\n--- !!int 2\n";
4440
4441 let mut int_tags = Vec::new();
4442 for event in Parser::new_from_str(text).keep_tags(true) {
4443 let event = event.unwrap().0;
4444 if let Event::Scalar(_, _, _, Some(tag)) = event {
4445 if tag.suffix == "int" {
4446 int_tags.push(tag.handle.clone());
4447 }
4448 }
4449 }
4450
4451 assert_eq!(int_tags, vec!["tag:evil,2024:", "tag:yaml.org,2002:"]);
4452 }
4453
4454 #[test]
4455 fn test_keep_tags_does_not_persist_primary_tag_handle() {
4456 let text = "%TAG ! tag:evil,2024:\n--- !int 1\n--- !int 2\n";
4457
4458 let tags = Parser::new_from_str(text)
4459 .keep_tags(true)
4460 .filter_map(|event| match event.expect("input should parse").0 {
4461 Event::Scalar(_, _, _, Some(tag)) if tag.suffix == "int" => {
4462 Some(tag.handle.clone())
4463 }
4464 _ => None,
4465 })
4466 .collect::<Vec<_>>();
4467
4468 assert_eq!(tags, vec!["tag:evil,2024:", "!"]);
4469 }
4470
4471 #[test]
4472 fn common_tag_storage_preserves_comparison_and_hashing() {
4473 let parsed = first_tagged_scalar_tag("!!str value");
4474 let constructed = Tag::with_original_handle("tag:yaml.org,2002:", "str", "!!");
4475 assert!(matches!(parsed.handle, Cow::Borrowed(_)));
4476 assert!(matches!(parsed.suffix, Cow::Borrowed(_)));
4477 assert!(matches!(parsed.original_handle, Cow::Borrowed(_)));
4478 assert_eq!(parsed, constructed);
4479 assert_eq!(parsed.cmp(&constructed), core::cmp::Ordering::Equal);
4480 #[cfg(feature = "std")]
4481 {
4482 use core::hash::{Hash, Hasher};
4483 use std::collections::hash_map::DefaultHasher;
4484
4485 let hash = |tag: &Tag| {
4486 let mut hasher = DefaultHasher::new();
4487 tag.hash(&mut hasher);
4488 hasher.finish()
4489 };
4490 assert_eq!(hash(&parsed), hash(&constructed));
4491 }
4492 }
4493
4494 #[test]
4495 fn test_resolve_tag_distinguishes_non_specific_and_primary_handle_tags() {
4496 let mut parser = Parser::new_from_str("");
4497 parser
4498 .tags
4499 .insert("!".into(), "tag:local.example,2024:".into());
4500
4501 for (handle, suffix, expected_prefix, original) in [
4502 ("", "!", "", "!"),
4503 ("!", "foo", "tag:local.example,2024:", "!foo"),
4504 ] {
4505 let tag = parser
4506 .resolve_tag(
4507 Span::empty(Marker::new(0, 1, 0)),
4508 Cow::Borrowed(handle),
4509 Cow::Borrowed(suffix),
4510 )
4511 .unwrap();
4512
4513 assert_eq!(tag.parts(), (expected_prefix, suffix));
4514 assert_eq!(tag.original_parts(), (handle, suffix));
4515 assert_eq!(tag.original(), original);
4516 assert_eq!(tag.to_string(), format!("{expected_prefix}{suffix}"));
4517 }
4518 }
4519
4520 #[test]
4521 fn test_load_after_peek_stream_start() {
4522 #[derive(Default)]
4523 struct Sink<'input> {
4524 events: Vec<Event<'input>>,
4525 }
4526
4527 impl<'input> EventReceiver<'input> for Sink<'input> {
4528 fn on_event(&mut self, ev: Event<'input>) {
4529 self.events.push(ev);
4530 }
4531 }
4532
4533 let mut parser = Parser::new_from_str("key: value\n");
4534 let mut sink = Sink::default();
4535
4536 assert_eq!(parser.peek().unwrap().unwrap().0, Event::StreamStart);
4537 parser.load(&mut sink, false).unwrap();
4538
4539 assert!(matches!(sink.events.first(), Some(Event::StreamStart)));
4540 assert!(matches!(sink.events.get(1), Some(Event::DocumentStart(..))));
4541 }
4542}