Skip to main content

granit_parser/
parser.rs

1//! Home to the YAML Parser.
2//!
3//! The parser takes input from the [`crate::scanner::Scanner`], performs final checks for YAML
4//! compliance, and emits a stream of YAML events. This stream can for instance be used to create
5//! YAML objects.
6
7use 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/// YAML version declared by a `%YAML` directive.
71#[derive(Copy, Clone, PartialEq, Debug, Eq, Hash)]
72pub struct YamlVersion {
73    /// Major version number.
74    pub major: u32,
75    /// Minor version number.
76    pub minor: u32,
77}
78
79impl YamlVersion {
80    /// Create a YAML version value.
81    #[must_use]
82    pub const fn new(major: u32, minor: u32) -> Self {
83        Self { major, minor }
84    }
85}
86
87/// An event generated by the YAML parser.
88///
89/// Events are used in the low-level event-based API (push parser). The API entrypoint is the
90/// [`EventReceiver`] trait.
91#[non_exhaustive]
92#[derive(Clone, PartialEq, Debug, Eq)]
93pub enum Event<'input> {
94    /// Event generated at the very beginning of parsing.
95    StreamStart,
96    /// Last event that will be generated by the parser. Signals EOF.
97    StreamEnd,
98    /// The start of a YAML document.
99    ///
100    DocumentStart(
101        /// Whether this is an explicit document start marker (`---`).
102        ///
103        /// When `false`, the document start is implicit.
104        bool,
105        /// YAML version declared by a preceding `%YAML` directive, if any.
106        Option<YamlVersion>,
107    ),
108    /// The end of a YAML document.
109    ///
110    /// This event is emitted for both explicit document end markers (`...`) and implicit document
111    /// ends.
112    DocumentEnd,
113    /// A resolved YAML alias.
114    ///
115    /// The companion [`Span`] covers the complete `*name` token, preserving the original name
116    /// through its source range. With [`Options::emit_anchor_events`], [`Self::Anchor`] connects
117    /// the target ID to its definition's name and source range.
118    Alias(
119        /// The anchor ID the alias refers to.
120        usize,
121    ),
122    /// Metadata for an anchor definition on the immediately preceding node in its parser's stream.
123    ///
124    /// Emitted only when [`Options::emit_anchor_events`] is `true`, immediately after the
125    /// anchored [`Self::Scalar`], [`Self::SequenceStart`], or [`Self::MappingStart`], before any
126    /// collection children. This is presentation metadata, not an additional YAML node.
127    /// The companion [`Span`] covers the complete `&name` token, whose source position precedes
128    /// the node content. Comments between properties and content can precede the node event.
129    /// Emitting the node first ensures that a failure before its event is emitted cannot leave
130    /// anchor metadata without an associated node event, even during document recovery.
131    ///
132    /// This adjacency guarantee applies to an individual [`Parser`]. See [`crate::ParserStack`]
133    /// for ordering when sources are interleaved.
134    ///
135    /// Repeated names receive distinct IDs; aliases refer to the most recent preceding
136    /// definition in the same document. IDs match those on node and [`Self::Alias`] events,
137    /// including when [`Parser::set_anchor_offset`] is used.
138    Anchor(
139        /// The assigned internal anchor ID.
140        usize,
141        /// The original anchor name, without the leading `&`.
142        Cow<'input, str>,
143    ),
144    /// An alias without a preceding anchor definition in its document.
145    ///
146    /// Emitted only when [`Options::emit_unresolved_aliases`] is `true`. The companion [`Span`]
147    /// covers the complete alias token, including `*`. This event occupies a node position but
148    /// represents an invalid reference; a later anchor definition does not resolve it retroactively.
149    UnresolvedAlias(
150        /// The original alias name, without the leading `*`.
151        Cow<'input, str>,
152    ),
153    /// A YAML source comment.
154    ///
155    /// Comments are presentation metadata, not YAML data nodes. The payload is the raw text
156    /// exactly after `#`, excluding only the line break. The placement is a best-effort hint for
157    /// correlating the comment with nearby YAML presentation. The companion parser [`Span`] covers
158    /// the whole source comment, including `#` and excluding the line break.
159    #[cfg(feature = "comments")]
160    Comment(
161        /// Raw comment payload exactly after `#`, excluding only the line break.
162        Cow<'input, str>,
163        /// Best-effort placement relative to nearby YAML content.
164        Placement,
165    ),
166    /// A YAML scalar value.
167    Scalar(
168        /// The scalar value after YAML escape processing.
169        Cow<'input, str>,
170        /// The source notation used for the scalar.
171        ScalarStyle,
172        /// The anchor ID defined on this scalar, or `0` if it has no anchor.
173        usize,
174        /// The resolved tag attached to this scalar, if any.
175        Option<Cow<'input, Tag>>,
176    ),
177    /// The start of a YAML sequence (array).
178    SequenceStart(
179        /// The notation style used for the sequence.
180        StructureStyle,
181        /// The anchor ID defined on this sequence, or `0` if it has no anchor.
182        usize,
183        /// The resolved tag attached to this sequence, if any.
184        Option<Cow<'input, Tag>>,
185    ),
186    /// The end of a YAML sequence (array).
187    SequenceEnd,
188    /// The start of a YAML mapping (object, hash).
189    MappingStart(
190        /// The notation style used for the mapping (Flow or Block).
191        StructureStyle,
192        /// The anchor ID defined on this mapping, or `0` if it has no anchor.
193        usize,
194        /// The resolved tag attached to this mapping, if any.
195        Option<Cow<'input, Tag>>,
196    ),
197    /// The end of a YAML mapping (object, hash).
198    MappingEnd,
199}
200
201/// The notation style used for a YAML sequence or mapping.
202///
203/// [`StructureStyle::Block`] means block notation:
204///
205/// ```yaml
206/// items:
207///   - milk
208///   - bread
209/// mapping:
210///   name: Ada
211///   active: true
212/// ```
213///
214/// [`StructureStyle::Flow`] means flow notation:
215///
216/// ```yaml
217/// items: [milk, bread]
218/// mapping: {name: Ada, active: true}
219/// ```
220#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
221pub enum StructureStyle {
222    /// Block notation, such as `- item` sequences and `key: value` mappings.
223    Block,
224    /// Flow notation, such as `[item]` sequences and `{key: value}` mappings.
225    Flow,
226}
227
228/// A YAML tag.
229#[derive(Clone, PartialEq, Debug, Eq, Ord, PartialOrd, Hash)]
230pub struct Tag {
231    /// Resolved tag handle or prefix.
232    ///
233    /// Examples include `tag:yaml.org,2002:` for core-schema tags and `!` for local tags.
234    handle: Cow<'static, str>,
235    /// Tag suffix following the resolved handle or prefix.
236    suffix: Cow<'static, str>,
237    /// Tag handle as written in the source before `%TAG` directive resolution.
238    ///
239    /// For example, with `%TAG !e! tag:example.com,2000:`, a source tag `!e!keep` is resolved
240    /// as `handle = "tag:example.com,2000:"` and `suffix = "keep"`, while
241    /// `original_handle = "!e!"`.
242    original_handle: Cow<'static, str>,
243}
244
245const YAML_CORE_SCHEMA_PREFIX: &str = "tag:yaml.org,2002:";
246
247// YAML 1.2.2 defines Core Schema tags by reference:
248// - §10.3.1 says Core Schema uses the same tags as YAML's JSON Schema.
249// - §10.2.1 adds null/bool/int/float to the Failsafe Schema.
250// - §10.1.1 defines the Failsafe Schema tags map/seq/str.
251// Therefore the YAML 1.2.2 Core Schema tag suffixes are:
252// bool, float, int, map, null, seq, and str.
253const 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
272/// Retain common tag components without allocating, and reuse owned scanner strings otherwise.
273fn 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    /// Create a tag from resolved parts.
293    ///
294    /// This is mainly useful for tests and consumers constructing parser-compatible tags by hand.
295    /// When the original source handle matters, use [`Self::with_original_handle`].
296    #[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    /// Create a tag from resolved parts and the handle as written in the source.
307    #[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    /// Return the resolved tag handle or prefix.
321    #[must_use]
322    pub fn handle(&self) -> &str {
323        &self.handle
324    }
325
326    /// Return the suffix following the resolved tag handle or prefix.
327    #[must_use]
328    pub fn suffix(&self) -> &str {
329        &self.suffix
330    }
331
332    /// Return the tag handle as written before `%TAG` directive resolution.
333    #[must_use]
334    pub fn original_handle(&self) -> &str {
335        &self.original_handle
336    }
337
338    /// Return the resolved YAML core-schema suffix for this tag, if it is a known core tag.
339    ///
340    /// The tag is matched by its resolved URI, not by the source handle spelling. For example,
341    /// `!!int`, `!<tag:yaml.org,2002:int>`, and a `%TAG` split such as
342    /// `%TAG !m! tag:yaml.org,2002:i` followed by `!m!nt` all return `Some("int")`.
343    ///
344    /// Authored tag parts are left unchanged; use [`Self::parts`], [`Self::original_parts`], or
345    /// [`Self::original`] to inspect those spellings.
346    #[must_use]
347    pub fn core_suffix(&self) -> Option<&str> {
348        // The handle ends at or before the namespace boundary. The remaining namespace
349        // prefix and the complete type name are both contained in `suffix`.
350        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        // The handle extends beyond the namespace boundary, so the type name is split
356        // between the end of `handle` and `suffix`. Compare against the seven fixed names
357        // directly instead of assembling an allocated String.
358        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    /// Return the type name this tag resolves to within `prefix`, or `None` outside it.
363    ///
364    /// Like [`Self::core_suffix`], the tag is matched by its resolved `handle ++ suffix` URI,
365    /// not the source spelling, so `!!omap`, `!<tag:yaml.org,2002:omap>`, and a `%TAG` split
366    /// such as `%TAG !o! tag:yaml.org,2002:o` then `!o!map` all resolve to `Some("omap")` for
367    /// the `tag:yaml.org,2002:` prefix — but the name is not limited to the seven core types.
368    ///
369    /// Borrows from `self`; allocates only when the handle extends past `prefix`.
370    #[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            // Handle spans the whole prefix; the name is its tail plus the suffix (the tail
374            // is empty unless a `%TAG` split pushed part of the name into the handle).
375            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        // Handle stops inside the prefix; the suffix supplies the rest of the prefix
386        // and then the name.
387        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    /// Returns whether the tag is a YAML tag from the core schema (`!!str`, `!!int`, ...).
394    ///
395    /// The YAML specification specifies [a list of
396    /// tags](https://yaml.org/spec/1.2.2/#103-core-schema) for the Core Schema. This function uses
397    /// the resolved tag URI, so it is independent of how the tag was split between handle and
398    /// suffix.
399    ///
400    /// # Return
401    /// Returns `true` if the resolved tag is a known YAML 1.2.2 Core Schema tag.
402    #[must_use]
403    pub fn is_yaml_core_schema(&self) -> bool {
404        self.core_suffix().is_some()
405    }
406
407    /// Return true for a YAML core-schema tag with the given suffix.
408    ///
409    /// For example, this matches core-schema tags such as `!!str`, `!!int`, `!!float`, `!!bool`,
410    /// `!!null`, `!!map`, or `!!seq` after tag resolution.
411    #[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    /// Return true for a tag outside the YAML 1.2.2 Core Schema tag set.
418    ///
419    /// This checks the resolved tag URI, not just the tag handle spelling. For example,
420    /// `tag:yaml.org,2002:timestamp` is in the YAML tag namespace, but it is not a YAML 1.2.2
421    /// Core Schema tag.
422    #[must_use]
423    pub fn is_custom(&self) -> bool {
424        !self.is_yaml_core_schema()
425    }
426
427    /// Return the tag as `(handle, suffix)`.
428    #[must_use]
429    pub fn parts(&self) -> (&str, &str) {
430        (&self.handle, &self.suffix)
431    }
432
433    /// Return the tag as `(original_handle, suffix)` using the handle from the source token.
434    ///
435    /// This is useful when a consumer needs author spelling such as `!e!keep` instead of the
436    /// resolved URI tag `tag:example.com,2000:keep`.
437    #[must_use]
438    pub fn original_parts(&self) -> (&str, &str) {
439        (&self.original_handle, &self.suffix)
440    }
441
442    /// Return the tag spelling reconstructed from the source handle and suffix.
443    ///
444    /// For ordinary shorthand tags this returns the author-facing spelling, such as `!e!keep` or
445    /// `!!str`. For verbatim tags this returns a normalized verbatim spelling such as
446    /// `!<tag:example.com,2000:thing>`, not necessarily the byte-exact source token.
447    #[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    /// Return the anchor ID defined by this event, if any.
476    ///
477    /// Returns `Some(id)` when this event defines an anchor on a scalar, sequence, or mapping
478    /// node, or describes that definition with [`Self::Anchor`]. The reserved ID `0` returns
479    /// `None`. Returns `None` for all other events, including resolved and unresolved aliases
480    /// (which reference anchors rather than defining them; use [`Self::alias_id`] to obtain a
481    /// resolved target anchor ID).
482    /// To count anchored nodes once, also require [`Self::is_node`], since [`Self::Anchor`]
483    /// repeats the node's ID.
484    #[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    /// Return the target anchor ID if this event is a resolved alias.
500    ///
501    /// Returns `None` for unresolved aliases and non-alias events. Use [`Self::is_alias`] to
502    /// recognize either kind of alias, or match [`Self::UnresolvedAlias`] to obtain its name.
503    #[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    /// Return whether this event is a resolved or unresolved alias.
512    #[must_use]
513    pub fn is_alias(&self) -> bool {
514        matches!(self, Self::Alias(_) | Self::UnresolvedAlias(_))
515    }
516
517    /// Return the resolved tag carried by this node event, if any.
518    #[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    /// Return the scalar value and style, if this event is a scalar.
529    #[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    /// Return whether this event represents a YAML node (value).
538    ///
539    /// Returns `true` for scalars, collection starts, and resolved or unresolved aliases, all of
540    /// which occupy a node position. Returns `false` for structural events such as `StreamStart`,
541    /// `DocumentStart`, collection ends, and presentation metadata such as [`Self::Anchor`].
542    #[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    /// Create an empty scalar.
555    fn empty_scalar() -> Self {
556        // a null scalar
557        Event::Scalar("~".into(), ScalarStyle::Plain, 0, None)
558    }
559
560    /// Create an empty scalar with the given node properties.
561    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/// Anchor metadata retained until its node event has been returned, including through comments.
573#[derive(Debug)]
574struct PendingAnchor<'input> {
575    id: usize,
576    name: Cow<'input, str>,
577    span: Span,
578    node_emitted: bool,
579}
580
581/// A YAML parser.
582#[derive(Debug)]
583#[allow(clippy::struct_excessive_bools)] // Independent parsing policies and state flags.
584pub struct Parser<'input, T: BorrowedInput<'input>> {
585    /// The underlying scanner from which we pull tokens.
586    scanner: Scanner<'input, T>,
587    /// Whether unknown anchors produce unresolved alias nodes instead of terminal errors.
588    emit_unresolved_aliases: bool,
589    /// Whether anchor definition metadata is emitted after the associated node event.
590    emit_anchor_events: bool,
591    /// The anchor token waiting for its node, or ready to emit immediately after that node.
592    pending_anchor: Option<PendingAnchor<'input>>,
593    /// Maximum number of comments retained while resolving an ambiguous collection entry.
594    #[cfg(feature = "comments")]
595    max_buffered_comment_events: usize,
596    /// Maximum number of simultaneously open block collections.
597    block_nesting_limit: usize,
598    /// Number of block collections currently open in the parser state machine.
599    block_level: usize,
600    /// The stack of _previous_ states we were in.
601    ///
602    /// States are pushed in the context of subobjects to this stack. The top-most element is the
603    /// state in which to come back to when exiting the current state.
604    states: Vec<State>,
605    /// The state in which we currently are.
606    state: State,
607    /// The next token from the scanner.
608    token: Option<QueuedToken<'input>>,
609    /// The next YAML event to emit.
610    current: Option<(Event<'input>, Span)>,
611    /// The next parser error to emit after it has been observed by `peek`.
612    current_error: Option<ScanError>,
613    /// A scanner error discovered while ordering events that must be emitted first.
614    ///
615    /// Unlike `current_error`, this has not been exposed through `peek`. It is consumed by
616    /// `next_event_impl` after already-buffered events so `peek`, iteration, and `load` all retain
617    /// the same ordering.
618    #[cfg(feature = "comments")]
619    deferred_error: Option<ScanError>,
620    /// YAML events buffered by parser states that need to emit an earlier synthetic node first.
621    #[cfg(feature = "comments")]
622    queued_events: VecDeque<(Event<'input>, Span)>,
623    /// Retained storage for collecting and ordering comments between syntax events.
624    #[cfg(feature = "comments")]
625    comment_scratch: Vec<(Event<'input>, Span)>,
626
627    /// Pending indentation hint to be attached to the next emitted event span.
628    ///
629    /// This is used to communicate indentation for block mapping keys. It is set when consuming a
630    /// `TokenType::Key` in block style, and is applied to the next emitted node event (the key
631    /// itself).
632    pending_key_indent: Option<usize>,
633    /// Pending anchor ID to attach to a node after an intervening comment.
634    /// `Some(0)` retains an anchor property when the anchor offset is zero.
635    #[cfg(feature = "comments")]
636    pending_node_anchor_id: Option<usize>,
637    /// Pending tag to attach to a node after an intervening comment.
638    #[cfg(feature = "comments")]
639    pending_node_tag: Option<Cow<'input, Tag>>,
640    /// Pending explicit tag token start and raw length after an intervening comment.
641    #[cfg(feature = "comments")]
642    pending_node_tag_span: Option<(Marker, u32)>,
643    /// Pending end marker of the last node-property token before an intervening comment.
644    #[cfg(feature = "comments")]
645    pending_node_property_end: Option<Marker>,
646    /// Pending empty scalar span captured before an intervening comment.
647    pending_empty_scalar_span: Option<Span>,
648    /// End marker of the most recently produced non-metadata event.
649    ///
650    /// Synthetic syntax events use this marker, so presentation metadata must not affect it.
651    last_non_comment_event_end: Option<Marker>,
652    /// Pending YAML version captured before comments preceding an explicit document start.
653    #[cfg(feature = "comments")]
654    pending_document_version: Option<YamlVersion>,
655    /// Whether document directives were already initialized before comments preceding `---`.
656    #[cfg(feature = "comments")]
657    pending_document_directives: bool,
658    /// `%TAG` handles already seen before comments preceding an explicit document start.
659    #[cfg(feature = "comments")]
660    pending_document_tag_handles: BTreeSet<Cow<'input, str>>,
661    /// Anchors that have been encountered in the YAML document.
662    anchors: BTreeMap<Cow<'input, str>, usize>,
663    /// Next ID available for an anchor.
664    ///
665    /// Every anchor is given a unique ID. We use an incrementing ID and this is both the ID to
666    /// return for the next anchor and the count of anchor IDs emitted.
667    anchor_id_count: usize,
668    /// The tag directives (`%TAG`) the parser has encountered.
669    ///
670    /// Key is the handle, and value is the prefix.
671    tags: BTreeMap<Cow<'input, str>, Cow<'input, str>>,
672    /// Whether we have emitted a terminal iterator result.
673    ///
674    /// Terminal means either [`Event::StreamEnd`] or a [`ScanError`]. Emitted means that it has
675    /// been returned from [`Self::next_event`] or [`Self::next`]. If the terminal result is stored
676    /// in [`Self::current`], [`Self::current_error`], or internal comment buffers, this is set to
677    /// `false`.
678    stream_end_emitted: bool,
679    /// Whether parsing stopped on an error, including an error observed only through `peek`.
680    failed: bool,
681    /// Whether the current document has ended without starting the next one yet.
682    at_document_end: bool,
683    /// Make tags global across all documents.
684    keep_tags: bool,
685}
686
687/// Trait to be implemented in order to use the low-level parsing API.
688///
689/// The low-level parsing API is event-based (a push parser), calling [`EventReceiver::on_event`]
690/// for each YAML [`Event`] that occurs.
691/// The [`EventReceiver`] trait only receives events. In order to receive both events and their
692/// location in the source, use [`SpannedEventReceiver`]. Note that [`EventReceiver`]s implement
693/// [`SpannedEventReceiver`] automatically.
694/// With the `comments` feature, non-spanned receivers receive `Event::Comment(text, placement)` like any
695/// other event, but without source location. Spanned receivers receive the same comment event plus
696/// the comment [`Span`] in [`SpannedEventReceiver::on_event`]. For comments, that span covers the
697/// whole source comment, including `#` and excluding the line break. When parsing from an input
698/// with byte offsets, such as [`Parser::new_from_str`], [`Span::slice`] returns that source
699/// comment text.
700///
701/// # Event hierarchy
702/// The event stream starts with an [`Event::StreamStart`] event followed by an
703/// [`Event::DocumentStart`] event. If the YAML document starts with a mapping (an object), an
704/// [`Event::MappingStart`] event is emitted. If it starts with a sequence (an array), an
705/// [`Event::SequenceStart`] event is emitted. Otherwise, an [`Event::Scalar`] event is emitted.
706///
707/// In a mapping, key-values are sent as consecutive data events. Comments can appear in the raw
708/// event stream between a key and its value; they are presentation metadata, not YAML data nodes.
709/// Consumers building YAML data trees should ignore `Event::Comment` and [`Event::Anchor`].
710/// With [`Options::emit_anchor_events`], anchor metadata immediately follows its scalar or
711/// collection-start event and carries the same ID plus the original name and anchor-token span.
712/// Any key/value alternation shortcut applies only after filtering out comments and other
713/// presentation metadata. After that
714/// filtering, the first event after an [`Event::MappingStart`] will be the key, and the following
715/// event will be its value. If the mapping contains no sub-mapping or sub-sequence, then even events
716/// (starting from 0) will always be keys and odd ones will always be values. The mapping ends when
717/// an [`Event::MappingEnd`] event is received.
718///
719/// In a sequence, values are sent consecutively until the [`Event::SequenceEnd`] event.
720///
721/// If a value is a sub-mapping or a sub-sequence, an [`Event::MappingStart`] or
722/// [`Event::SequenceStart`] event will be sent respectively. Following events until the associated
723/// [`Event::MappingEnd`] or [`Event::SequenceEnd`] (beware of nested mappings or sequences) will
724/// be part of the value and not another key-value pair or element in the sequence.
725///
726/// For instance, the following YAML:
727/// ```yaml
728/// a: b
729/// c:
730///   d: e
731/// f:
732///   - g
733///   - h
734/// ```
735/// will emit (indented and commented for visibility):
736/// ```text
737/// StreamStart, DocumentStart, MappingStart,
738///   Scalar("a", ..), Scalar("b", ..)
739///   Scalar("c", ..), MappingStart, Scalar("d", ..), Scalar("e", ..), MappingEnd,
740///   Scalar("f", ..), SequenceStart, Scalar("g", ..), Scalar("h", ..), SequenceEnd,
741/// MappingEnd, DocumentEnd, StreamEnd
742/// ```
743///
744/// # Example
745/// ```
746/// # use granit_parser::{Event, EventReceiver, Parser};
747/// #
748/// /// Sink of events. Collects them into an array.
749/// struct EventSink<'input> {
750///     events: Vec<Event<'input>>,
751/// }
752///
753/// /// Implement `on_event`, pushing into `self.events`.
754/// impl<'input> EventReceiver<'input> for EventSink<'input> {
755///     fn on_event(&mut self, ev: Event<'input>) {
756///         self.events.push(ev);
757///     }
758/// }
759///
760/// /// Load events from a YAML string.
761/// fn str_to_events(yaml: &str) -> Vec<Event<'_>> {
762///     let mut sink = EventSink { events: Vec::new() };
763///     let mut parser = Parser::new_from_str(yaml);
764///     // Load events using our sink as the receiver.
765///     parser.load(&mut sink, true).unwrap();
766///     sink.events
767/// }
768/// ```
769pub trait EventReceiver<'input> {
770    /// Handler called for each YAML event that is emitted by the parser.
771    fn on_event(&mut self, ev: Event<'input>);
772}
773
774/// Trait to be implemented for using the low-level parsing API.
775///
776/// Functionally similar to [`EventReceiver`], but receives a [`Span`] as well as the event.
777/// With the `comments` feature, an `Event::Comment` span is the source range of the whole comment.
778pub trait SpannedEventReceiver<'input> {
779    /// Handler called for each event that occurs.
780    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
789/// Trait to be implemented for fallible event handling without source spans.
790///
791/// This is the fallible counterpart to [`EventReceiver`]. Use it with [`Parser::try_load`] when
792/// event handling may need to stop parsing by returning an application error.
793pub trait TryEventReceiver<'input> {
794    /// Error returned by this receiver.
795    type Error;
796
797    /// Handler called for each YAML event that is emitted by the parser.
798    ///
799    /// Returning an error stops [`Parser::try_load`] immediately.
800    ///
801    /// # Errors
802    /// Returns `Self::Error` when the receiver wants to stop parsing.
803    fn on_event(&mut self, ev: Event<'input>) -> Result<(), Self::Error>;
804}
805
806/// Trait to be implemented for fallible event handling with source spans.
807///
808/// This is the fallible counterpart to [`SpannedEventReceiver`]. Use it with
809/// [`Parser::try_load`] when event handling may need to stop parsing by returning an application
810/// error.
811pub trait TrySpannedEventReceiver<'input> {
812    /// Error returned by this receiver.
813    type Error;
814
815    /// Handler called for each event that occurs.
816    ///
817    /// Returning an error stops [`Parser::try_load`] immediately.
818    ///
819    /// # Errors
820    /// Returns `Self::Error` when the receiver wants to stop parsing.
821    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/// Error returned by [`Parser::try_load`] and [`ParserTrait::try_load`].
833#[derive(Clone, PartialEq, Debug, Eq)]
834pub enum TryLoadError<E> {
835    /// Scanning or parsing failed.
836    Scan(
837        /// The scanner or parser error.
838        ScanError,
839    ),
840    /// The receiver returned an application error.
841    Receiver(
842        /// The error returned by the receiver.
843        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
919/// A convenience alias for a parser event result.
920pub type ParseResult<'input> = Result<(Event<'input>, Span), ScanError>;
921
922/// Trait extracted from `Parser` to support mocking and alternative implementations.
923pub trait ParserTrait<'input> {
924    /// Try to load the next event and return it without consuming it from `self`.
925    fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>>;
926
927    /// Try to load the next event and return it, consuming it from `self`.
928    fn next_event(&mut self) -> Option<ParseResult<'input>>;
929
930    /// Load the YAML from the stream in `self`, pushing events into `recv`.
931    ///
932    /// Use this method when event handling is infallible. If receiver code can return an
933    /// application error and should stop parsing, use [`ParserTrait::try_load`] instead. If the
934    /// caller should directly control when the next event is read, use [`ParserTrait::next_event`]
935    /// or [`Parser`]'s [`core::iter::Iterator`] implementation.
936    ///
937    /// After a scan error, the parser is exhausted: [`ParserTrait::peek`] and
938    /// [`ParserTrait::next_event`] return [`None`], and further calls to `load` or
939    /// [`ParserTrait::try_load`] return `Ok(())` without emitting events.
940    ///
941    /// # Errors
942    /// Returns `ScanError` when scanning or parsing the stream fails.
943    fn load<R: SpannedEventReceiver<'input>>(
944        &mut self,
945        recv: &mut R,
946        multi: bool,
947    ) -> Result<(), ScanError>;
948
949    /// Load the YAML from the stream in `self`, stopping if `recv` returns an error.
950    ///
951    /// If `multi` is set to `true`, the parser will allow parsing of multiple YAML documents
952    /// inside the stream.
953    ///
954    /// If the receiver returns an error, the parser is left positioned immediately after the event
955    /// that caused the receiver error. Callers should treat the parser as partially consumed.
956    ///
957    /// After a scan error, the parser is exhausted: [`ParserTrait::peek`] and
958    /// [`ParserTrait::next_event`] return [`None`], and further calls to `try_load` or
959    /// [`ParserTrait::load`] return `Ok(())` without emitting events.
960    ///
961    /// # Errors
962    /// Returns [`TryLoadError::Scan`] when scanning or parsing the stream fails. Returns
963    /// [`TryLoadError::Receiver`] when `recv` returns an error.
964    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    /// Create a parser over a borrowed string slice.
990    ///
991    /// Every emitted event span has UTF-8 byte offsets into `value`:
992    /// [`Span::byte_range`] returns `Some(start..end)`, with ordered, in-bounds UTF-8
993    /// boundaries. This includes zero-length spans for implicit events and end-of-input.
994    /// [`Span::slice`] returns `Some` when given the same, unchanged source string.
995    ///
996    /// This guarantee applies to spans as emitted, before callers modify their markers.
997    /// Byte offsets remain optional in [`Span`] because other inputs, such as
998    /// [`Self::new_from_iter`], do not provide them. Missing offsets must not be replaced
999    /// with zero or with [`Marker::index`], which counts characters rather than bytes.
1000    #[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    /// Create a parser over a borrowed string slice with configurable behavior and resource
1006    /// limits.
1007    ///
1008    /// The byte-offset guarantee of [`Self::new_from_str`] also applies with custom options.
1009    #[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    /// Create a parser over an iterator of characters.
1020    #[must_use]
1021    pub fn new_from_iter(iter: T) -> Self {
1022        Self::new_from_iter_with_options(iter, Options::default())
1023    }
1024
1025    /// Create a parser over an iterator of characters with configurable behavior and resource
1026    /// limits.
1027    #[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    /// Create a parser over a fallible iterator of characters.
1038    ///
1039    /// The iterator's `None` return value means clean end-of-input. An `Err` item reports a
1040    /// terminal source failure and is returned by the parser as a [`ScanError`] carrying the same
1041    /// [`ErrorKind`]. The iterator is not polled again after its first error.
1042    #[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    /// Create a parser over a fallible iterator of characters with configurable behavior and
1048    /// resource limits.
1049    ///
1050    /// The iterator's `None` return value means clean end-of-input. An `Err` item reports a
1051    /// terminal source failure and is returned by the parser as a [`ScanError`] carrying the same
1052    /// [`ErrorKind`]. The iterator is not polled again after its first error.
1053    #[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    /// Return the next anchor ID that will be assigned by this parser.
1061    #[must_use]
1062    pub fn anchor_offset(&self) -> usize {
1063        self.anchor_id_count
1064    }
1065
1066    /// Set the next anchor ID that will be assigned by this parser.
1067    pub fn set_anchor_offset(&mut self, offset: usize) {
1068        self.anchor_id_count = offset;
1069    }
1070
1071    /// Create a parser over a custom input source.
1072    #[must_use]
1073    pub fn new(src: T) -> Self {
1074        Self::with_options(src, Options::default())
1075    }
1076
1077    /// Create a parser over a custom input source with configurable behavior and resource limits.
1078    ///
1079    /// Use [`crate::options!`] to construct `options` without depending on exhaustive struct
1080    /// literal syntax.
1081    /// Without the `comments` feature, comment capture and emission are compiled out of both
1082    /// the parser and its scanner. YAML comments are still skipped and validated.
1083    #[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            // valid anchor_id starts from 1
1133            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    /// Configure whether tag directives remain active across document boundaries.
1143    ///
1144    /// This behavior is non-standard as per the YAML specification but can be encountered in the
1145    /// wild. Passing `true` enables this non-standard extension and allows the parser to accept
1146    /// input from [test
1147    /// QLJ7](https://github.com/yaml/yaml-test-suite/blob/ccfa74e56afb53da960847ff6e6976c0a0825709/src/QLJ7.yaml)
1148    /// of the yaml-test-suite:
1149    ///
1150    /// ```yaml
1151    /// %TAG !prefix! tag:example.com,2011:
1152    /// --- !prefix!A
1153    /// a: b
1154    /// --- !prefix!B
1155    /// c: d
1156    /// --- !prefix!C
1157    /// e: f
1158    /// ```
1159    ///
1160    /// With `keep_tags` set to `false`, the above YAML is rejected. As per the specification, tags
1161    /// only apply to the document immediately following them. This would error on `!prefix!B`.
1162    ///
1163    /// With `keep_tags` set to `true`, the above YAML is accepted by the parser.
1164    #[must_use]
1165    pub fn keep_tags(mut self, value: bool) -> Self {
1166        self.keep_tags = value;
1167        self
1168    }
1169
1170    /// Try to load the next event and return it without consuming it from `self`.
1171    ///
1172    /// Any subsequent call to [`Parser::peek`] will return the same value, until a call to
1173    /// [`Iterator::next`], [`Parser::load`], or [`Self::proceed_next_document`].
1174    /// If the buffered value is a [`ScanError`], [`Parser::next_event`] returns that error once
1175    /// and then the parser is exhausted.
1176    ///
1177    /// # Errors
1178    /// Returns `ScanError` when loading the next event fails.
1179    pub fn peek(&mut self) -> Option<Result<&(Event<'input>, Span), ScanError>> {
1180        ParserTrait::peek(self)
1181    }
1182
1183    /// Try to load the next event and return it, consuming it from `self`.
1184    ///
1185    /// After this returns a [`ScanError`], subsequent calls return [`None`] unless
1186    /// [`Self::proceed_next_document`] is called to recover at a document boundary.
1187    ///
1188    /// # Errors
1189    /// Returns `ScanError` when loading the next event fails.
1190    pub fn next_event(&mut self) -> Option<ParseResult<'input>> {
1191        ParserTrait::next_event(self)
1192    }
1193
1194    /// Abandon the current document and resume at the next document boundary.
1195    ///
1196    /// This can be called after an error from iteration, [`Self::peek`], or [`Self::load`], or
1197    /// during successful parsing to skip the remainder of a document. Before parsing starts it
1198    /// skips the first document. Immediately after [`Event::DocumentEnd`] it leaves the next
1199    /// document ready to read. Repeated calls skip successive documents.
1200    ///
1201    /// Returns `true` when another document remains, including an empty or malformed document,
1202    /// and `false` at clean EOF. This looks past inter-document comments and end markers without
1203    /// consuming the next document's events. Comments inspected by this lookahead are buffered
1204    /// for subsequent reads; with comment emission enabled, the configured comment-buffer limit
1205    /// applies. Syntax errors encountered in the next document remain available to normal parsing.
1206    ///
1207    /// Read subsequent events using the usual parser methods. They start with the next
1208    /// [`Event::DocumentStart`] (possibly preceded by comments), or [`Event::StreamEnd`] if no
1209    /// document remains. An already consumed stream end stays exhausted. This method does not
1210    /// emit another [`Event::StreamStart`].
1211    ///
1212    /// After a syntax error, recovery scans forward from the scanner's current position to a
1213    /// separated `---` or valid `...` at column zero, or EOF. An explicit end marker also permits
1214    /// a following implicit document and its directive prefix. Indented markers, inline markers,
1215    /// and scalar text such as `---suffix` are not synchronization points. Input is never rewound;
1216    /// event spans retain their original source positions.
1217    /// If a directive prefix fails before its opening `---`, that document's body is skipped too.
1218    ///
1219    /// Open collections, buffered events/comments, and anchor definitions of an abandoned
1220    /// document are discarded. No synthetic collection ends, document end, or error node are
1221    /// emitted for it: consumers building a tree must abandon or mark their own partial nodes.
1222    /// Anchor IDs remain unique across documents. Directives are reset as at a normal document
1223    /// boundary, including the [`Self::keep_tags`] policy.
1224    ///
1225    /// Skipped syntax errors are suppressed. Recovery does not repair content within a document,
1226    /// preserve its anchors for another document, or validate the next document in advance.
1227    /// Ordinary parsing still stops at the first error unless this method is explicitly called.
1228    /// Scanning moves forward with work proportional to the skipped input; no diagnostic list
1229    /// is accumulated. Cancellation can be supplied through a fallible input source.
1230    ///
1231    /// # Example
1232    /// ```
1233    /// use granit_parser::{Event, Parser};
1234    /// # fn main() -> Result<(), granit_parser::ScanError> {
1235    /// let mut parser = Parser::new_from_str("broken: [1, 2\n---\nhealthy: true\n");
1236    /// let error = parser.by_ref().find_map(Result::err).unwrap();
1237    /// assert!(parser.next().is_none());
1238    /// // Record the diagnostic and abandon any open nodes in the consumer's partial tree.
1239    /// assert!(parser.proceed_next_document()?);
1240    /// assert!(matches!(parser.next().unwrap()?.0, Event::DocumentStart(true, _)));
1241    /// let rest = parser.collect::<Result<Vec<_>, _>>()?;
1242    /// assert!(rest.iter().any(|(event, _)| event.scalar().is_some_and(|(v, _)| v == "healthy")));
1243    /// # Ok(())
1244    /// # }
1245    /// ```
1246    ///
1247    /// # Errors
1248    /// Returns a source failure (including I/O, decoding, or cancellation errors supplied by the
1249    /// input). Source failures cannot be recovered and leave the parser exhausted.
1250    /// With comment emission enabled, also returns `ErrorKind::TooManyComments` if looking ahead
1251    /// would exceed the comment-buffer limit; parsing then stays exhausted until recovery is
1252    /// requested again.
1253    pub fn proceed_next_document(&mut self) -> Result<bool, ScanError> {
1254        // A consumed StreamEnd stays exhausted. A terminal error still needs recovery below.
1255        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                // Stay between documents so repeated calls preserve unread trailing comments
1264                // as well as StreamEnd instead of consuming them in the skip loop.
1265                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                    // The boundary was already reached, possibly by peek(). Discard its cached
1289                    // end event and let another proceed call skip the following document.
1290                    if matches!(self.current, Some((Event::DocumentEnd, _))) {
1291                        self.current = None;
1292                    }
1293                    self.at_document_end = false;
1294                    return Ok(());
1295                }
1296                // While the grammar state is valid, consume events through the current document.
1297                // If parsing fails, next_event_impl records the failure and we synchronize below.
1298                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                            // Leave EOF available for the caller's next read, just like peek().
1306                            self.current = Some(event);
1307                            return Ok(());
1308                        }
1309                        Ok(_) => {}
1310                        Err(_) => break,
1311                    }
1312                }
1313            }
1314
1315            // A directive belongs to the document whose opening marker follows it. Abandon
1316            // that body as well, rather than accepting it after silently dropping its header.
1317            let failed_header = matches!(
1318                self.state,
1319                State::ImplicitDocumentStart | State::DocumentStart
1320            ) && self.scanner.in_directive_prefix();
1321            // Discard the failed grammar state and seek a boundary, retaining any marker that
1322            // lookahead already consumed. Source failures propagate instead of becoming EOF.
1323            self.recover_document()?;
1324            if !failed_header || !matches!(self.peek_token()?.1, QueuedTokenType::DocumentStart) {
1325                return Ok(());
1326            }
1327            // This opening marker belongs to the failed header. Loop to skip its body too.
1328        }
1329    }
1330
1331    /// Probe only the next document's prefix, retaining comments and any syntax error for readers.
1332    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            // A header paused at a comment already establishes document presence. Leave EOF
1340            // or an invalid end marker for normal parsing, but retain terminal source failures.
1341            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                    // Source failures can carry any ErrorKind. Consult the scanner's source
1350                    // latch rather than classifying the error by its kind.
1351                    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    /// Implementation function for [`Self::next_event`] without the `Option`.
1421    ///
1422    /// [`Self::next_event`] should conform to the expectations of an [`Iterator`] and return an
1423    /// option. This burdens the parser code. This function is used internally when an option is
1424    /// undesirable.
1425    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        // A node can be buffered behind comments. Wait until that exact node reaches the public
1476        // event stream before emitting its metadata, ahead of any further comments or children.
1477        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    /// Load the next event for [`ParserTrait::try_load`], exhausting the parser on a scan error.
1491    ///
1492    /// A scan error can interrupt a state transition, so the state machine must never run again
1493    /// afterwards. [`ParserTrait::next_event`] latches this itself; `try_load` bypasses it to
1494    /// avoid the `Option` wrapper and needs the same latch.
1495    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    /// Peek at the next token from the scanner.
1535    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    /// Extract and return the next token from the scanner.
1551    ///
1552    /// This function does _not_ make use of `self.token`.
1553    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                    // Keep the allocation when this position has no comments.
1619                    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    /// Take the token buffered by [`Self::peek_token`].
1729    ///
1730    /// # Panics
1731    /// Panics if no token has been buffered.
1732    #[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    /// Skip the next token from the scanner.
1743    fn skip(&mut self) {
1744        self.token = None;
1745    }
1746    /// Pops the top-most state and make it the current state.
1747    ///
1748    /// # Panics
1749    /// Panics if the state stack is empty.
1750    #[track_caller]
1751    fn pop_state(&mut self) {
1752        self.state = self.states.pop().unwrap();
1753    }
1754    /// Push a new state atop the state stack.
1755    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    /// Load the YAML from the stream in `self`, pushing events into `recv`.
1806    ///
1807    /// The contents of the stream are parsed and the corresponding events are sent into the
1808    /// receiver. For detailed explanations about how events work, see [`EventReceiver`].
1809    ///
1810    /// If `multi` is set to `true`, the parser will allow parsing of multiple YAML documents
1811    /// inside the stream.
1812    ///
1813    /// Use this method when event handling is infallible. If receiver code can return an
1814    /// application error and should stop parsing, use [`Parser::try_load`] instead. If the caller
1815    /// should directly control when the next event is read, use [`Parser`]'s
1816    /// [`core::iter::Iterator`] implementation.
1817    ///
1818    /// Note that any [`EventReceiver`] is also a [`SpannedEventReceiver`], so implementing the
1819    /// former is enough to call this function.
1820    ///
1821    /// After a scan error, the parser is exhausted: [`Parser::peek`] and [`Parser::next_event`]
1822    /// return [`None`], and further calls to `load` or [`Parser::try_load`] return `Ok(())`
1823    /// without emitting events.
1824    ///
1825    /// # Example
1826    /// ```
1827    /// # use granit_parser::{Event, EventReceiver, Parser};
1828    /// # fn main() -> Result<(), granit_parser::ScanError> {
1829    /// struct EventSink<'input> {
1830    ///     events: Vec<Event<'input>>,
1831    /// }
1832    ///
1833    /// impl<'input> EventReceiver<'input> for EventSink<'input> {
1834    ///     fn on_event(&mut self, ev: Event<'input>) {
1835    ///         self.events.push(ev);
1836    ///     }
1837    /// }
1838    ///
1839    /// let mut parser = Parser::new_from_str("a: 1\n");
1840    /// let mut sink = EventSink { events: Vec::new() };
1841    ///
1842    /// parser.load(&mut sink, false)?;
1843    ///
1844    /// assert!(sink
1845    ///     .events
1846    ///     .iter()
1847    ///     .any(|ev| matches!(ev, Event::Scalar(value, ..) if value == "a")));
1848    /// # Ok(())
1849    /// # }
1850    /// ```
1851    ///
1852    /// # Errors
1853    /// Returns `ScanError` when loading fails.
1854    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    /// Load the YAML from the stream in `self`, pushing events into `recv`.
1863    ///
1864    /// This is the fallible counterpart to [`Parser::load`]. If `recv` returns an error, parsing
1865    /// stops immediately and that error is returned as [`TryLoadError::Receiver`].
1866    ///
1867    /// If `multi` is set to `true`, the parser will allow parsing of multiple YAML documents
1868    /// inside the stream.
1869    ///
1870    /// If the receiver returns an error, the parser is left positioned immediately after the event
1871    /// that caused the receiver error. Callers should treat the parser as partially consumed.
1872    ///
1873    /// After a scan error, the parser is exhausted: [`Parser::peek`] and [`Parser::next_event`]
1874    /// return [`None`], and further calls to `try_load` or [`Parser::load`] return `Ok(())`
1875    /// without emitting events.
1876    ///
1877    /// # Example
1878    /// ```
1879    /// # use granit_parser::{Event, Parser, TryEventReceiver, TryLoadError};
1880    /// #[derive(Debug, PartialEq, Eq)]
1881    /// enum ValidationError {
1882    ///     ForbiddenScalar,
1883    /// }
1884    ///
1885    /// struct Validator;
1886    ///
1887    /// impl<'input> TryEventReceiver<'input> for Validator {
1888    ///     type Error = ValidationError;
1889    ///
1890    ///     fn on_event(&mut self, ev: Event<'input>) -> Result<(), Self::Error> {
1891    ///         if matches!(ev, Event::Scalar(value, ..) if value.as_ref() == "bad") {
1892    ///             Err(ValidationError::ForbiddenScalar)
1893    ///         } else {
1894    ///             Ok(())
1895    ///         }
1896    ///     }
1897    /// }
1898    ///
1899    /// let mut parser = Parser::new_from_str("value: bad\n");
1900    /// let mut validator = Validator;
1901    ///
1902    /// let err = parser.try_load(&mut validator, false).unwrap_err();
1903    ///
1904    /// assert_eq!(err, TryLoadError::Receiver(ValidationError::ForbiddenScalar));
1905    /// ```
1906    ///
1907    /// # Errors
1908    /// Returns [`TryLoadError::Scan`] when scanning or parsing the stream fails. Returns
1909    /// [`TryLoadError::Receiver`] when `recv` returns an error.
1910    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        // Resume a document start paused to emit comments before handling markers that are only
2004        // ignorable between documents. In particular, `...` is invalid while `---` is still
2005        // required after directives and must not be consumed by the loop below.
2006        #[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        // Anchors are scoped to a single document.
2016        self.anchors.clear();
2017
2018        // Skipping a leading document-end marker can expose a comment that the normal
2019        // `next_event_impl` pre-dispatch check could not see yet. Emit it before deciding whether
2020        // another document starts; presentation-only comments must not create an implicit document.
2021        #[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                // explicit document
2040                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                // explicit document
2050                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        // Keep retained handles on the parser so any early error, including scanner errors,
2062        // leaves them available for document recovery. Comment pauses continue the same header.
2063        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                    // Reserved directives are ignored
2106                }
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            // Default handles never persist, even with the non-standard keep_tags policy.
2218            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        // YAML permits anchor names to be reused. Aliases resolve to the most recent definition.
2227        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                            // `StrInput` can prove that a source has no comments and skips this
2363                            // lookahead, while streaming inputs must probe for one. If that probe
2364                            // discovers a later scanner error, the input backend must not determine
2365                            // whether this already-recognized sequence start is emitted first.
2366                            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            // ex 7.2, an empty scalar can follow a secondary tag
2456            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                // Indentation is only meaningful for block mapping keys.
2499                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            // A missing block-mapping key before `:` is represented as an empty scalar.
2511            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        // Peek before taking the span so that a scanner error leaves this state intact.
2592        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        // Peek before taking the span so that a scanner error leaves this state intact.
2749        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            _ => { /* next */ }
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                // The token that ends an indentless sequence belongs to the enclosing mapping
2847                // (`? key`, `key:`, block end); the end event is empty, at that token's start.
2848                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        // Peek before taking the span so that a scanner error leaves this state intact.
2858        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        // Peek before taking the span so that a scanner error leaves this state intact.
2938        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    /// Resolve a tag from the handle and the suffix.
3033    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            // Bare "!" is a non-specific tag, not a primary handle to expand with %TAG.
3043            Cow::Borrowed("")
3044        } else if let Some(prefix) = self.tags.get(original_handle.as_ref()) {
3045            // Explicit directives also override the default "!!" prefix.
3046            own_tag_component(Cow::Borrowed(prefix.as_ref()))
3047        } else if original_handle == "!!" {
3048            Cow::Borrowed(YAML_CORE_SCHEMA_PREFIX)
3049        } else {
3050            // An undeclared named handle cannot be treated as a local tag.
3051            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            // The parser already completed the stream, so emit the terminal event again and stop.
3141            // Only success reaches `State::End`. The scanner's own stream-end flag is not a
3142            // substitute: it is also set when an error is raised at the end of the stream, such as
3143            // `ExpectedDocumentStart` for a directive-only document, and `StreamEnd` must not be
3144            // re-emitted after such an error.
3145            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            // Only a scan error reaches this point with the latch set: a clean end of stream was
3151            // handled above. The error may have interrupted a state transition, so the state
3152            // machine must not run again. Mirror the fused iterator, which returns `None` here.
3153            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        // Every spelling of `tag:yaml.org,2002:omap` resolves to the same name, even though
3441        // `omap` is not a Core Schema type (so `core_suffix` reports `None`). `mid_split` cuts
3442        // the URI after the namespace prefix (handle longer than `NS`); `inside_split` cuts it
3443        // before the prefix ends (handle a non-empty prefix of `NS`), exercising both branches.
3444        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        // Borrow whenever the resolved name is a contiguous slice of `handle` or `suffix`;
3454        // allocate only when a split lands inside the name itself (handle extends past `NS`).
3455        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        // The non-core `merge` type resolves the same way; core types still flow through
3473        // `core_suffix`.
3474        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        // Tags outside the namespace do not resolve into it.
3483        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                // Test successful
4423                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}