Skip to main content

granit_parser/
lib.rs

1// Copyright 2015, Yuheng Chen.
2// Copyright 2023, Ethiraric.
3// See the LICENSE file at the top-level directory of this distribution.
4
5//! YAML 1.2 parser implementation in pure Rust.
6//!
7//! `granit-parser` is a low-level event parser. It reads YAML input and yields a stream of
8//! [`Event`] values paired with their source [`Span`].
9//! Comments are emitted as [`Event::Comment`]. They are presentation metadata, not YAML data
10//! nodes, so consumers building YAML value trees should ignore them.
11//!
12//! Add it to your project:
13//!
14//! ```sh
15//! cargo add granit-parser
16//! ```
17//!
18//! # Usage
19//!
20//! ```rust
21//! use granit_parser::{Event, Parser, Placement};
22//!
23//! # fn main() -> Result<(), granit_parser::ScanError> {
24//! let yaml = r#"# header
25//! items: # inline
26//!   - milk
27//!   - bread
28//! "#;
29//! let mut comments = Vec::new();
30//!
31//! for next in Parser::new_from_str(yaml) {
32//!     let (event, span) = next?;
33//!     if let Event::Comment(text, placement) = event {
34//!         comments.push((
35//!             text.into_owned(),
36//!             placement,
37//!             span.slice(yaml).unwrap().to_owned(),
38//!         ));
39//!     }
40//! }
41//!
42//! assert_eq!(
43//!     comments,
44//!     [
45//!         (" header".to_owned(), Placement::Above, "# header".to_owned()),
46//!         (" inline".to_owned(), Placement::Right, "# inline".to_owned()),
47//!     ]
48//! );
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! For comment events, the companion [`Span`] covers the whole source comment, including `#` and
54//! excluding the line break. With [`Parser::new_from_str`], [`Span::slice`] returns that source
55//! comment text.
56//!
57//! # Limits
58//!
59//! [`Options`] controls comment emission and limits on buffered comments, simple-key lookahead,
60//! directive retention, and flow- and block-collection nesting. Comment tokens and events are
61//! emitted by default; setting [`Options::emit_comments`] to `false` recognizes and validates
62//! comments without capturing their text or emitting them. The defaults allow 96 buffered comment
63//! events, 1024 characters of simple-key lookahead, 1024 bytes of retained directive data, 16
64//! reserved-directive parameters, 255 nested flow collections, and 255 nested block collections.
65//! Existing constructors use these defaults.
66//! [`Parser::new_from_str_with_options`], [`Parser::new_from_iter_with_options`],
67//! [`Parser::new_from_fallible_iter_with_options`], [`Parser::with_options`],
68//! [`Scanner::with_options`], and [`ParserStack::with_options`] accept customized options created
69//! with [`options!`].
70//!
71//! # Features
72//! **Note:** This crate's MSRV is `1.81.0`.
73//!
74//! #### `error_messages` (enabled by default)
75//! Provides human-readable text through [`ErrorKind`]'s `Display` implementation and
76//! [`ScanError::info`]. Disabling this feature makes both render an empty string while retaining
77//! machine-readable error kinds and source markers.
78//!
79//! #### `std`
80//! Retains the original `std::io::Error` inside [`InputIoError`] when constructed through
81//! `InputIoError::from_io` or its `From<std::io::Error>` implementation. Without this feature,
82//! [`InputIoError::from_message`] remains available for portable `no_std` error reporting.
83//!
84//! #### `debug_prints`
85//! Enables the `debug` module and usage of debug prints in the scanner and the parser. Do not
86//! enable if you are consuming the crate rather than working on it as this can significantly
87//! decrease performance. Output remains opt-in behind a local compile-time toggle in
88//! `src/debug.rs`.
89//!
90//! This feature does not raise the MSRV further.
91//!
92//! This feature enables `std` and is _not_ `no_std` compatible.
93
94#![forbid(unsafe_code)]
95#![warn(missing_docs, clippy::pedantic)]
96#![no_std]
97
98extern crate alloc;
99
100#[cfg(feature = "std")]
101extern crate std;
102
103mod char_traits;
104#[macro_use]
105mod debug;
106mod error;
107pub mod input;
108mod macros;
109mod options;
110mod parser;
111mod parser_stack;
112mod scanner;
113
114pub use crate::error::{ErrorKind, InputIoError, ScanError};
115pub use crate::input::{str::StrInput, BorrowedInput, BufferedInput, FallibleBufferedInput, Input};
116pub use crate::options::Options;
117pub use crate::parser::{
118    Event, EventReceiver, ParseResult, Parser, ParserTrait, SpannedEventReceiver, StructureStyle,
119    Tag, TryEventReceiver, TryLoadError, TrySpannedEventReceiver, YamlVersion,
120};
121pub use crate::parser_stack::{ParserStack, ReplayParser};
122pub use crate::scanner::{
123    Comment, Marker, Placement, ScalarStyle, Scanner, Span, Token, TokenType,
124};
125
126// Keep every Rust example in the package README covered by `cargo test --doc` without duplicating
127// the README in the rendered crate-level documentation.
128#[cfg(doctest)]
129#[doc = include_str!("../README.md")]
130mod readme_doctests {}