### Example Input YAML Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md This is an example YAML file used to demonstrate the output of the `dump_events` tool. It includes a sequence with a nested mapping and a sequence. ```yaml - foo: bar - baz: c: [3, 4, 5] ``` -------------------------------- ### bench_compare.toml configuration example Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md This TOML configuration file is required for the `bench_compare` tool. It specifies input/output directories, iteration counts, and details for each parser being benchmarked. ```toml yaml_input_dir = "bench_yaml" # The path to the directory containing the input yaml files iterations = 10 # The number of iterations, if using `run_bench` yaml_output_dir = "yaml_output" # The directory in which `run_bench`'s yamls are saved csv_output = "benchmark.csv" # The CSV output aggregating times for each parser and file [[parsers]] # A parser, can be repeated as many times as there are parsers name = "yaml-rust2" # The name of the parser (used for logging) path = "target/release/" # The path in which the parsers' `run_bench` and `time_parse` are # If there is another parser, another block can be added # [[parsers]] # name = "libfyaml" # path = "../libfyaml/build" ``` -------------------------------- ### run_bench human-readable output Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md This example shows the human-readable output of the `run_bench` command, displaying average, min, max, and 95th percentile parsing times. ```sh # This is meant to be human-readable. # The example below is what this crate implements. $> run_bench file.yaml 100 Average: 1.589485s Min : 1.583078s Max : 1.597028s 95% : 1.593219s ``` -------------------------------- ### time_parse human-readable output Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md This example shows the human-readable output format for the `time_parse` binary, including the time taken and file loading information. ```sh # This is meant to be human-readable. # The example below is what this crate implements. $> time_parse file.yaml Loaded 200MiB in 1.74389s. ``` -------------------------------- ### Import yaml-rust (as yaml_rust) Source: https://github.com/ethiraric/yaml-rust2/blob/master/README.md Example of importing YamlLoader and YamlEmitter when using yaml-rust2 as a drop-in replacement for yaml-rust. ```rust use yaml_rust::{YamlLoader, YamlEmitter}; ``` -------------------------------- ### run_bench --output-yaml for automation Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md This example shows the YAML output format for `run_bench` when the `--output-yaml` flag is used. This structured output is designed for machine parsing and analysis. ```sh # This will be read by this tool. # This must output a YAML as described below. $> run_bench ../file.yaml 10 --output-yaml parser: yaml-rust2 input: ../file.yaml average: 1620303590 min: 1611632108 max: 1636401896 percentile95: 1636401896 iterations: 10 times: - 1636401896 - 1623914538 - 1611632108 - 1612973608 - 1617748930 - 1615419514 - 1612172250 - 1620791346 - 1629339306 - 1622642412 ``` -------------------------------- ### time_parse --short output for automation Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md This example demonstrates the output format when the `--short` option is used with `time_parse`. This output, containing only nanoseconds, is intended for machine parsing. ```sh # This will be read by this tool. # This must output ONLY the time, in nanoseconds. $> time_parse file.yaml --short 1743892394 ``` -------------------------------- ### Use yaml-rust2 with Unchanged Source Code Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Example of using the `yaml_rust` alias after updating `Cargo.toml`. The Rust code remains identical to projects using the original `yaml-rust` crate. ```rust // Source code remains unchanged — only the Cargo.toml changes use yaml_rust::{YamlLoader, YamlEmitter}; fn main() { let docs = YamlLoader::load_from_str("hello: world").unwrap(); assert_eq!(docs[0]["hello"].as_str().unwrap(), "world"); } ``` -------------------------------- ### Standard Event Stream Output Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md The standard output from the `dump_events` tool when processing the example YAML. It shows the sequence of events generated by the parser. ```text ↳ StreamStart ↳ DocumentStart ↳ SequenceStart(0, None) ↳ MappingStart(0, None) ↳ Scalar("foo", Plain, 0, None) ↳ Scalar("bar", Plain, 0, None) ↳ MappingEnd ↳ MappingStart(0, None) ↳ Scalar("baz", Plain, 0, None) ↳ Scalar("~", Plain, 0, None) ↳ Scalar("c", Plain, 0, None) ↳ SequenceStart(0, None) ↳ Scalar("3", Plain, 0, None) ↳ Scalar("4", Plain, 0, None) ↳ Scalar("5", Plain, 0, None) ↳ SequenceEnd ↳ MappingEnd ↳ SequenceEnd ↳ DocumentEnd ↳ StreamEnd ``` -------------------------------- ### Parse YAML and Dump Events with Debugging Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Run the `dump_events` binary with the `YAMLRUST2_DEBUG=1` environment variable to get detailed parser state information. This is helpful for debugging parsing issues and understanding the library's internal workings. ```bash YAMLRUST2_DEBUG=1 cargo run --bin dump_events -- input.yaml ``` -------------------------------- ### time_parse binary synopsis Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md The `time_parse` binary measures the time taken to parse a given YAML file. Use the `--short` option to get only the nanosecond output for automated processing. ```bash time_parse file.yaml [--short] ``` -------------------------------- ### Synopsis of bench_compare commands Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md These are the two primary commands supported by the bench_compare tool. Use `time_parse` for quick single-run timing and `run_bench` for more comprehensive benchmarking. ```bash bench_compare time_parse bench_compare run_bench ``` -------------------------------- ### Run Benchmarks with run_bench (Text Output) Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Execute the parser on a specified YAML file for a given number of iterations. This command outputs simple performance metrics like average, min, max, and 95th percentile times. ```sh $> cargo run --release --bin run_bench -- bench_yaml/big.yaml 10 ``` -------------------------------- ### Run Benchmarks with run_bench (YAML Output) Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md This command runs the parser and outputs the results in YAML format, suitable for further processing. It includes parser name, input file, and detailed timing metrics. ```sh $> cargo run --release --bin run_bench -- bench_yaml/big.yaml 10 --output-yaml ``` -------------------------------- ### run_bench binary synopsis Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/bench_compare/README.md The `run_bench` binary executes multiple parsing iterations for a given file and number of iterations. Use `--output-yaml` for structured YAML output. ```bash run_bench file.yaml [--output-yaml] ``` -------------------------------- ### Add yaml-rust2 as a Drop-in Replacement for yaml-rust Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Configure Cargo.toml to use yaml-rust2 while aliasing it as `yaml_rust` for seamless migration from the original `yaml-rust` crate. ```toml # Cargo.toml [dependencies] # Tell Cargo to fetch yaml-rust2 but expose it under the name "yaml_rust" yaml-rust = { version = "0.11", package = "yaml-rust2" } ``` -------------------------------- ### Parser and EventReceiver Usage Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Illustrates the low-level event-based streaming API using Parser and EventReceiver for processing YAML without building a full tree. ```APIDOC ## `Parser` and `EventReceiver` — Low-level event-based streaming API `Parser` is a push parser that emits `Event` values to any type implementing `EventReceiver` (or `MarkedEventReceiver` for source-position information). This API is suitable for building custom data structures, streaming processing, or validation without constructing the full `Yaml` tree. ```rust use yaml_rust2::parser::{Event, EventReceiver, MarkedEventReceiver, Parser}; use yaml_rust2::scanner::Marker; /// Collect all events with their source positions. struct EventCollector { events: Vec<(Event, Marker)>, } impl MarkedEventReceiver for EventCollector { fn on_event(&mut self, ev: Event, mark: Marker) { self.events.push((ev, mark)); } } fn main() { let yaml = " a: b list: - 1 - 2 "; let mut collector = EventCollector { events: Vec::new() }; let mut parser = Parser::new_from_str(yaml); parser.load(&mut collector, true).unwrap(); for (ev, mark) in &collector.events { println!("line {:>3}, col {:>3}: {:?}", mark.line(), mark.col(), ev); } // Example output: // line 1, col 1: StreamStart // line 2, col 1: DocumentStart // line 2, col 1: MappingStart(0, None) // line 2, col 1: Scalar("a", Plain, 0, None) // line 2, col 4: Scalar("b", Plain, 0, None) // ... // line 6, col 5: Scalar("2", Plain, 0, None) // line 6, col 6: SequenceEnd // line 6, col 6: MappingEnd // line 7, col 1: DocumentEnd // line 7, col 1: StreamEnd // Verify we got StreamStart and StreamEnd assert!(matches!(collector.events.first().unwrap().0, Event::StreamStart)); assert!(matches!(collector.events.last().unwrap().0, Event::StreamEnd)); } ``` ``` -------------------------------- ### Time Parsing with time_parse (Small File) Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Measure the time taken by the parser to emit all events for a small input file. This tool is advised to be run with the `--release` flag. ```sh $> cargo run --release --bin time_parse -- input.yaml ``` -------------------------------- ### Load and Access YAML Data Source: https://github.com/ethiraric/yaml-rust2/blob/master/README.md Demonstrates loading a YAML string, accessing its elements using index notation, and handling potential invalid accesses. Requires `YamlLoader` and `YamlEmitter` imports. ```rust use yaml_rust2::{YamlLoader, YamlEmitter}; fn main() { let s = "\nfoo: - list1 - list2 bar: - 1 - 2.0 "; let docs = YamlLoader::load_from_str(s).unwrap(); // Multi document support, doc is a yaml::Yaml let doc = &docs[0]; // Debug support println!("{:?}", doc); // Index access for map & array assert_eq!(doc["foo"][0].as_str().unwrap(), "list1"); assert_eq!(doc["bar"][1].as_f64().unwrap(), 2.0); // Array/map-like accesses are checked and won't panic. // They will return `BadValue` if the access is invalid. assert!(doc["INVALID_KEY"][100].is_badvalue()); // Dump the YAML object let mut out_str = String::new(); { let mut emitter = YamlEmitter::new(&mut out_str); emitter.dump(doc).unwrap(); // dump the YAML object to a String } println!("{}", out_str); } ``` -------------------------------- ### YamlEmitter::compact and YamlEmitter::multiline_strings Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Controls emitter output formatting for inline notation and multiline strings. `compact(false)` uses block style for nested structures, while `multiline_strings(true)` emits strings with newlines as YAML literal block scalars. ```APIDOC ## `YamlEmitter::compact` / `YamlEmitter::multiline_strings` — Emitter options `compact(bool)` controls compact inline notation for block sequences and mappings (default: `true`). `multiline_strings(bool)` controls whether strings containing `\n` are emitted as YAML literal block scalars (`|` or `|-`) instead of quoted strings (default: `false`). ```rust use yaml_rust2::{YamlEmitter, YamlLoader}; fn main() { let source = r#"{list: [1, 2, 3], note: \"hello\nworld\"}"#; let docs = YamlLoader::load_from_str(source).unwrap(); let doc = &docs[0]; // Non-compact: nested sequences/mappings use block style let mut out_non_compact = String::new(); let mut emitter = YamlEmitter::new(&mut out_non_compact); emitter.compact(false); emitter.multiline_strings(true); emitter.dump(doc).unwrap(); // Compact (default): sequence items follow the dash on the same line let mut out_compact = String::new(); YamlEmitter::new(&mut out_compact).dump(doc).unwrap(); println!("Non-compact:\n{out_non_compact}"); println!("Compact:\n{out_compact}"); // Non-compact output note field uses literal block: // note: |- // hello // world } ``` ``` -------------------------------- ### Upgrade from yaml-rust Source: https://github.com/ethiraric/yaml-rust2/blob/master/README.md Configure your Cargo.toml to use yaml-rust2 as a drop-in replacement for the original yaml-rust crate. This allows you to refer to the crate as `yaml_rust` in your code. ```toml [dependencies] yaml-rust = { version = "#.#", package = "yaml-rust2" } ``` -------------------------------- ### YamlLoader::load_from_parser Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Loads YAML documents from a pre-configured `Parser` instance. ```APIDOC ## YamlLoader::load_from_parser - Load documents from a pre-configured Parser Runs an already-constructed and configured `Parser` through the loader. This is the way to use parser-level options (such as `keep_tags`) together with the high-level `Yaml` document API. ### Method Rust function call ### Parameters - **parser**: `&mut Parser` - A mutable reference to a configured `Parser` instance. ### Returns - `Result, ScanError>` - A vector of Yaml documents or a ScanError if parsing fails. ### Request Example ```rust use yaml_rust2::{parser::Parser, YamlLoader}; let text = "%TAG !t! tag:example.com,2024:\n---\nfoo: bar"; let mut parser = Parser::new_from_str(text).keep_tags(true); let docs = YamlLoader::load_from_parser(&mut parser).unwrap(); assert_eq!(docs[0]["foo"].as_str().unwrap(), "bar"); ``` ``` -------------------------------- ### Add yaml-rust2 to Project Source: https://github.com/ethiraric/yaml-rust2/blob/master/README.md Use this command to add the yaml-rust2 crate as a dependency to your Rust project. ```sh cargo add yaml-rust2 ``` -------------------------------- ### YamlDecoder Usage Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Demonstrates how to use YamlDecoder to read and decode YAML from byte streams with different encoding handling strategies. ```APIDOC ## `YamlDecoder` — Encoding-aware loading from byte streams (feature: `encoding`) `YamlDecoder` wraps any `std::io::Read` source and decodes it to UTF-8 before parsing. It auto-detects UTF-8, UTF-16LE, and UTF-16BE via BOM, or by inspecting the null-byte pattern per the YAML 1.2 spec. Decoding errors are handled via `YAMLDecodingTrap`: `Strict` (default, returns error), `Ignore` (skip bad bytes), `Replace` (insert U+FFFD), or `Call` (custom callback). ```rust use std::ops::ControlFlow; use std::borrow::Cow; use yaml_rust2::yaml::{YamlDecoder, YAMLDecodingTrap}; fn main() { // UTF-8 with BOM let utf8_bom: &[u8] = b"\xef\xbb\xbf---\nkey: value\n"; let docs = YamlDecoder::read(utf8_bom).decode().unwrap(); assert_eq!(docs[0]["key"].as_str().unwrap(), "value"); // Ignore invalid bytes let bad_bytes: &[u8] = b"---\nname\xa9: Alice\n"; let docs = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Ignore) .decode() .unwrap(); assert_eq!(docs[0]["name"].as_str().unwrap(), "Alice"); // Replace invalid bytes with U+FFFD let docs2 = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Replace) .decode() .unwrap(); // key now contains the replacement character assert!(docs2[0].as_hash().is_some()); // Custom callback trap let docs3 = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Call( |_mal_len, _bytes_after, _input, output| { output.push('?'); // substitute with '?' ControlFlow::Continue(()) }, )) .decode() .unwrap(); assert!(docs3[0].as_hash().is_some()); // Strict (default): returns LoadError::Decode on bad bytes let result = YamlDecoder::read(bad_bytes).decode(); assert!(result.is_err()); } ``` ``` -------------------------------- ### Parse YAML and Dump Events Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Use the `dump_events` binary to parse a YAML file and output the resulting event stream. This is useful for understanding the structure of YAML data as processed by the library. ```bash cargo run --bin dump_events -- input.yaml ``` -------------------------------- ### Time Parsing with time_parse (Large File) Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Measure the time taken by the parser to emit all events for a large input file. This tool is advised to be run with the `--release` flag. ```sh $> cargo run --release --bin time_parse -- bench_yaml/big.yaml ``` -------------------------------- ### Generate Large YAML Files Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md Use this command to generate large YAML files for benchmarking. This tool depends on external dependencies and requires a dedicated cargo alias. ```sh cargo gen_large_yaml ``` -------------------------------- ### YamlLoader::load_from_str Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Parses a YAML string into a vector of Yaml documents. This is the primary entry point for the high-level API. ```APIDOC ## YamlLoader::load_from_str - Parse a YAML string into documents Parses a `&str` containing one or more YAML documents and returns a `Vec`. Each element corresponds to one YAML document in the source. Returns a `ScanError` if the input is malformed. This is the primary entry point for the high-level API. ### Method Rust function call ### Parameters - **source**: `&str` - The YAML string to parse. ### Returns - `Result, ScanError>` - A vector of Yaml documents or a ScanError if parsing fails. ### Request Example ```rust use yaml_rust2::{Yaml, YamlLoader}; let source = "name: Alice\nage: 30"; let docs = YamlLoader::load_from_str(source).unwrap(); let doc = &docs[0]; assert_eq!(doc["name"].as_str().unwrap(), "Alice"); ``` ``` -------------------------------- ### Low-Level YAML Event Streaming with Parser Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Utilizes the Parser and EventReceiver traits for a low-level, event-based streaming API. This is suitable for custom data structures, streaming processing, or validation without building a full Yaml tree. ```rust use yaml_rust2::parser::{Event, EventReceiver, MarkedEventReceiver, Parser}; use yaml_rust2::scanner::Marker; /// Collect all events with their source positions. struct EventCollector { events: Vec<(Event, Marker)>, } impl MarkedEventReceiver for EventCollector { fn on_event(&mut self, ev: Event, mark: Marker) { self.events.push((ev, mark)); } } fn main() { let yaml = " a: b list: - 1 - 2 "; let mut collector = EventCollector { events: Vec::new() }; let mut parser = Parser::new_from_str(yaml); parser.load(&mut collector, true).unwrap(); for (ev, mark) in &collector.events { println!("line {:>3}, col {:>3}: {:?}", mark.line(), mark.col(), ev); } // Example output: // line 1, col 1: StreamStart // line 2, col 1: DocumentStart // line 2, col 1: MappingStart(0, None) // line 2, col 1: Scalar("a", Plain, 0, None) // line 2, col 4: Scalar("b", Plain, 0, None) // ... // line 6, col 5: Scalar("2", Plain, 0, None) // line 6, col 6: SequenceEnd // line 6, col 6: MappingEnd // line 7, col 1: DocumentEnd // line 7, col 1: StreamEnd // Verify we got StreamStart and StreamEnd assert!(matches!(collector.events.first().unwrap().0, Event::StreamStart)); assert!(matches!(collector.events.last().unwrap().0, Event::StreamEnd)); } ``` -------------------------------- ### Update Cargo.toml dependency Source: https://github.com/ethiraric/yaml-rust2/blob/master/documents/2024-03-15-FirstRelease.md Replace the `yaml-rust` dependency with `yaml-rust2` in your `Cargo.toml` file. ```diff -yaml-rust = "0.4.4" +yaml-rust2 = "0.8.0" ``` -------------------------------- ### Control YamlEmitter Output Formatting Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Configure YamlEmitter to control compact inline notation and multiline string formatting. `compact(false)` uses block style for nested structures, while `multiline_strings(true)` emits strings with newlines as literal block scalars. ```rust use yaml_rust2::{YamlEmitter, YamlLoader}; fn main() { let source = r#"{list: [1, 2, 3], note: "hello\nworld"}"#; let docs = YamlLoader::load_from_str(source).unwrap(); let doc = &docs[0]; // Non-compact: nested sequences/mappings use block style let mut out_non_compact = String::new(); let mut emitter = YamlEmitter::new(&mut out_non_compact); emitter.compact(false); emitter.multiline_strings(true); emitter.dump(doc).unwrap(); // Compact (default): sequence items follow the dash on the same line let mut out_compact = String::new(); YamlEmitter::new(&mut out_compact).dump(doc).unwrap(); println!("Non-compact:\n{out_non_compact}"); println!("Compact:\n{out_compact}"); // Non-compact output note field uses literal block: // note: |- // hello // world } ``` -------------------------------- ### Yaml type accessor methods Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Provides methods like `as_*`, `into_*`, and `is_*` for interacting with Yaml enum variants. `as_*` methods return Option<&T> or Option by copy/reference without consuming the value, `into_*` methods consume the value, and `is_*` methods return boolean checks. ```APIDOC ## `Yaml` type accessor methods — `as_*`, `into_*`, `is_*` The `Yaml` enum provides a comprehensive family of accessor methods. `as_bool`, `as_i64` return `Option` by copy; `as_str`, `as_hash`, `as_vec` return `Option<&T>` by reference; `as_mut_hash`, `as_mut_vec` return mutable references; `into_bool`, `into_i64`, `into_string`, `into_hash`, `into_vec`, `into_f64` consume the value; `is_null`, `is_badvalue`, `is_array`, `is_hash` return `bool`. ```rust use yaml_rust2::{Yaml, YamlLoader}; fn main() { let src = " integer: -99 float: 2.718 text: hello flag: false items: - x - y mapping: a: 1 "; let doc = &YamlLoader::load_from_str(src).unwrap()[0]; // as_* (borrow, non-consuming) assert_eq!(doc["integer"].as_i64(), Some(-99)); assert_eq!(doc["float"].as_f64().map(|f| (f * 1000.0).round()), Some(2718.0)); assert_eq!(doc["text"].as_str(), Some("hello")); assert_eq!(doc["flag"].as_bool(), Some(false)); assert!(doc["items"].as_vec().is_some()); assert!(doc["mapping"].as_hash().is_some()); // is_* checks assert!(doc["integer"].is_array() == false); assert!(doc["items"].is_array()); assert!(doc["mapping"].is_hash()); // into_* (consuming) let raw = YamlLoader::load_from_str("answer: 42").unwrap().remove(0); let answer: i64 = raw["answer"].clone().into_i64().unwrap(); assert_eq!(answer, 42); let raw2 = YamlLoader::load_from_str("- 1\n- 2\n- 3").unwrap().remove(0); let vec: Vec = raw2.into_vec().unwrap(); assert_eq!(vec.len(), 3); } ``` ``` -------------------------------- ### Serialize Yaml node to string with YamlEmitter Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Use `YamlEmitter` to serialize `Yaml` nodes into any `fmt::Write` sink, typically a `String`. It prepends the `---` document-start marker and supports compact notation and optional literal-block style for multiline strings. ```rust use yaml_rust2::{YamlEmitter, YamlLoader}; fn main() { let source = "name: Bob\nscores:\n - 10\n - 20\nnotes: \"line1\nline2\"" ; let docs = YamlLoader::load_from_str(source).unwrap(); // --- Basic round-trip --- let mut output = String::new(); let mut emitter = YamlEmitter::new(&mut output); emitter.dump(&docs[0]).unwrap(); // output starts with "--- " assert!(output.starts_with("---\ ")); assert!(output.contains("name: Bob")); // --- Multiline literal block style --- let mut output2 = String::new(); let mut emitter2 = YamlEmitter::new(&mut output2); emitter2.multiline_strings(true); // emit \n in strings as literal blocks emitter2.dump(&docs[0]).unwrap(); // "line1\nline2" is now emitted as a "|-" literal block assert!(output2.contains("|-")); } ``` -------------------------------- ### Load YAML documents from a Parser with YamlLoader::load_from_parser Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Use `load_from_parser` to load YAML documents from a pre-configured `Parser`. This method allows using parser-level options, such as `keep_tags`, with the high-level `Yaml` document API. ```rust use yaml_rust2::{parser::Parser, YamlLoader}; fn main() { // Multi-document stream with a shared %TAG directive across documents let text = " %TAG !t! tag:example.com,2024: --- !t!TypeA foo: bar --- !t!TypeB baz: qux "; // keep_tags(true) allows the %TAG directive to apply across all documents let mut parser = Parser::new_from_str(text).keep_tags(true); let docs = YamlLoader::load_from_parser(&mut parser).unwrap(); assert_eq!(docs.len(), 2); assert_eq!(docs[0]["foo"].as_str().unwrap(), "bar"); assert_eq!(docs[1]["baz"].as_str().unwrap(), "qux"); } ``` -------------------------------- ### YamlLoader::load_from_iter Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Parses YAML from any character iterator, enabling lazy or streaming parsing. ```APIDOC ## YamlLoader::load_from_iter - Parse from a character iterator Accepts any `Iterator` as input, enabling lazy or streaming YAML parsing. Returns the same `Vec` result as `load_from_str`. ### Method Rust function call ### Parameters - **iter**: `impl Iterator` - An iterator yielding characters of the YAML source. ### Returns - `Result, ScanError>` - A vector of Yaml documents or a ScanError if parsing fails. ### Request Example ```rust use yaml_rust2::YamlLoader; let yaml_chars = "key: value".chars(); let docs = YamlLoader::load_from_iter(yaml_chars).unwrap(); assert_eq!(docs[0]["key"].as_str().unwrap(), "value"); ``` ``` -------------------------------- ### Handle Encoding Errors with YamlDecoder Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Demonstrates how to configure YamlDecoder to handle byte decoding errors using different strategies like Ignore, Replace, or a custom callback. The default Strict mode returns an error. ```rust use std::ops::ControlFlow; use std::borrow::Cow; use yaml_rust2::yaml::{YamlDecoder, YAMLDecodingTrap}; fn main() { // UTF-8 with BOM let utf8_bom: &[u8] = b"\xef\xbb\xbf---\nkey: value\n"; let docs = YamlDecoder::read(utf8_bom).decode().unwrap(); assert_eq!(docs[0]["key"].as_str().unwrap(), "value"); // Ignore invalid bytes let bad_bytes: &[u8] = b"---\nname\xa9: Alice\n"; let docs = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Ignore) .decode() .unwrap(); assert_eq!(docs[0]["name"].as_str().unwrap(), "Alice"); // Replace invalid bytes with U+FFFD let docs2 = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Replace) .decode() .unwrap(); // key now contains the replacement character assert!(docs2[0].as_hash().is_some()); // Custom callback trap let docs3 = YamlDecoder::read(bad_bytes) .encoding_trap(YAMLDecodingTrap::Call( |_mal_len, _bytes_after, _input, output| { output.push('?'); // substitute with '?' ControlFlow::Continue(()) }, )) .decode() .unwrap(); assert!(docs3[0].as_hash().is_some()); // Strict (default): returns LoadError::Decode on bad bytes let result = YamlDecoder::read(bad_bytes).decode(); assert!(result.is_err()); } ``` -------------------------------- ### Detailed Debug Output Source: https://github.com/ethiraric/yaml-rust2/blob/master/tools/README.md The detailed output from the `dump_events` tool when run with `YAMLRUST2_DEBUG=1`. This output includes parser states and marker information, useful for in-depth analysis. ```text Parser state: StreamStart ↳ StreamStart(Utf8) Marker { index: 0, line: 1, col: 0 } ↳ StreamStart Parser state: ImplicitDocumentStart → fetch_next_token after whitespace Marker { index: 0, line: 1, col: 0 } "-" ↳ BlockSequenceStart Marker { index: 0, line: 1, col: 0 } ↳ DocumentStart Parser state: BlockNode ↳ SequenceStart(0, None) Parser state: BlockSequenceFirstEntry ↳ BlockEntry Marker { index: 2, line: 1, col: 2 } → fetch_next_token after whitespace Marker { index: 2, line: 1, col: 2 } 'f' → fetch_next_token after whitespace Marker { index: 5, line: 1, col: 5 } ':' ↳ BlockMappingStart Marker { index: 5, line: 1, col: 5 } ↳ MappingStart(0, None) Parser state: BlockMappingFirstKey ↳ Key Marker { index: 2, line: 1, col: 2 } ↳ Scalar(Plain, "foo") Marker { index: 2, line: 1, col: 2 } ↳ Scalar("foo", Plain, 0, None) Parser state: BlockMappingValue ↳ Value Marker { index: 5, line: 1, col: 5 } → fetch_next_token after whitespace Marker { index: 7, line: 1, col: 7 } 'b' ↳ Scalar(Plain, "bar") Marker { index: 7, line: 1, col: 7 } ↳ Scalar("bar", Plain, 0, None) Parser state: BlockMappingKey → fetch_next_token after whitespace Marker { index: 11, line: 2, col: 0 } "-" ↳ BlockEnd Marker { index: 11, line: 2, col: 0 } ↳ MappingEnd Parser state: BlockSequenceEntry ↳ BlockEntry Marker { index: 13, line: 2, col: 2 } → fetch_next_token after whitespace Marker { index: 13, line: 2, col: 2 } 'b' → fetch_next_token after whitespace Marker { index: 16, line: 2, col: 5 } ':' ↳ BlockMappingStart Marker { index: 16, line: 2, col: 5 } ↳ MappingStart(0, None) Parser state: BlockMappingFirstKey ↳ Key Marker { index: 13, line: 2, col: 2 } ↳ Scalar(Plain, "baz") Marker { index: 13, line: 2, col: 2 } ↳ Scalar("baz", Plain, 0, None) Parser state: BlockMappingValue ↳ Value Marker { index: 16, line: 2, col: 5 } → fetch_next_token after whitespace Marker { index: 20, line: 3, col: 2 } 'c' → fetch_next_token after whitespace Marker { index: 21, line: 3, col: 3 } ':' ↳ Key Marker { index: 20, line: 3, col: 2 } ↳ Scalar("~", Plain, 0, None) Parser state: BlockMappingKey ↳ Scalar(Plain, "c") Marker { index: 20, line: 3, col: 2 } ↳ Scalar("c", Plain, 0, None) Parser state: BlockMappingValue ↳ Value Marker { index: 21, line: 3, col: 3 } → fetch_next_token after whitespace Marker { index: 23, line: 3, col: 5 } '[' ↳ FlowSequenceStart Marker { index: 23, line: 3, col: 5 } ↳ SequenceStart(0, None) Parser state: FlowSequenceFirstEntry → fetch_next_token after whitespace Marker { index: 24, line: 3, col: 6 } '3' → fetch_next_token after whitespace Marker { index: 25, line: 3, col: 7 } ',' ↳ Scalar(Plain, "3") Marker { index: 24, line: 3, col: 6 } ↳ Scalar("3", Plain, 0, None) Parser state: FlowSequenceEntry ↳ FlowEntry Marker { index: 25, line: 3, col: 7 } → fetch_next_token after whitespace Marker { index: 27, line: 3, col: 9 } '4' → fetch_next_token after whitespace Marker { index: 28, line: 3, col: 10 } ',' ↳ Scalar(Plain, "4") Marker { index: 27, line: 3, col: 9 } ↳ Scalar("4", Plain, 0, None) Parser state: FlowSequenceEntry ↳ FlowEntry Marker { index: 28, line: 3, col: 10 } → fetch_next_token after whitespace Marker { index: 30, line: 3, col: 12 } '5' → fetch_next_token after whitespace Marker { index: 31, line: 3, col: 13 } ']' ↳ Scalar(Plain, "5") Marker { index: 30, line: 3, col: 12 } ↳ Scalar("5", Plain, 0, None) Parser state: FlowSequenceEntry ↳ FlowSequenceEnd Marker { index: 31, line: 3, col: 13 } ↳ SequenceEnd Parser state: BlockMappingKey → fetch_next_token after whitespace Marker { index: 33, line: 4, col: 0 } '\0' ↳ BlockEnd Marker { index: 33, line: 4, col: 0 } ↳ MappingEnd Parser state: BlockSequenceEntry ↳ BlockEnd Marker { index: 33, line: 4, col: 0 } ↳ SequenceEnd Parser state: DocumentEnd ↳ StreamEnd Marker { index: 33, line: 4, col: 0 } ↳ DocumentEnd Parser state: DocumentStart ``` -------------------------------- ### Yaml Type Accessor Methods Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Safely access `Yaml` enum variants using `as_*` (borrowing), `into_*` (consuming), and `is_*` (checking) methods. `as_*` methods return `Option` or `Option<&T>`, while `into_*` methods consume the `Yaml` value. ```rust use yaml_rust2::{Yaml, YamlLoader}; fn main() { let src = " integer: -99 float: 2.718 text: hello flag: false items: - x - y mapping: a: 1 "; let doc = &YamlLoader::load_from_str(src).unwrap()[0]; // as_* (borrow, non-consuming) assert_eq!(doc["integer"].as_i64(), Some(-99)); assert_eq!(doc["float"].as_f64().map(|f| (f * 1000.0).round()), Some(2718.0)); assert_eq!(doc["text"].as_str(), Some("hello")); assert_eq!(doc["flag"].as_bool(), Some(false)); assert!(doc["items"].as_vec().is_some()); assert!(doc["mapping"].as_hash().is_some()); // is_* checks assert!(doc["integer"].is_array() == false); assert!(doc["items"].is_array()); assert!(doc["mapping"].is_hash()); // into_* (consuming) let raw = YamlLoader::load_from_str("answer: 42").unwrap().remove(0); let answer: i64 = raw["answer"].clone().into_i64().unwrap(); assert_eq!(answer, 42); let raw2 = YamlLoader::load_from_str("- 1\n- 2\n- 3").unwrap().remove(0); let vec: Vec = raw2.into_vec().unwrap(); assert_eq!(vec.len(), 3); } ``` -------------------------------- ### Handle YAML Parse Errors with ScanError Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Demonstrates how to handle malformed YAML input using `ScanError`. The error provides detailed location information for debugging. ```rust use yaml_rust2::YamlLoader; fn main() { let bad_yaml = " key: [1, 2]] another: value "; match YamlLoader::load_from_str(bad_yaml) { Ok(_) => panic!("should have failed"), Err(e) => { // Human-readable description println!("Error: {e}"); // e.g.: "did not find expected node content at byte 13 line 2 column 14" // Programmatic access to location let mark = e.marker(); println!("At line {}, column {}", mark.line(), mark.col()); // Short description without location println!("Info: {}", e.info()); } } } ``` -------------------------------- ### Parser::keep_tags Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Explains how to use `Parser::keep_tags(true)` to retain `%TAG` directives across multiple YAML documents in a stream. ```APIDOC ## `Parser::keep_tags` — Retain `%TAG` directives across documents By default, `%TAG` directives apply only to the immediately following document (YAML 1.2 spec). Setting `keep_tags(true)` extends their scope to all subsequent documents in the stream, which is useful for non-standard multi-document streams found in practice. ```rust use yaml_rust2::{parser::Parser, YamlLoader}; fn main() { let multi_doc = " %TAG !t! tag:example.com,2024: --- !t!Alpha x: 1 --- !t!Beta y: 2 "; // Standard behavior: second document tag fails (handle not declared) let result = YamlLoader::load_from_parser( &mut Parser::new_from_str(multi_doc).keep_tags(false) ); assert!(result.is_err()); // Extended behavior: tag persists across all documents let docs = YamlLoader::load_from_parser( &mut Parser::new_from_str(multi_doc).keep_tags(true) ).unwrap(); assert_eq!(docs.len(), 2); assert_eq!(docs[0]["x"].as_i64().unwrap(), 1); assert_eq!(docs[1]["y"].as_i64().unwrap(), 2); } ``` ``` -------------------------------- ### YamlEmitter Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Serializes Yaml nodes back into YAML text. ```APIDOC ## YamlEmitter - Serialize a `Yaml` node to a YAML string `YamlEmitter` writes a `Yaml` document into any `fmt::Write` sink (typically a `String`). It prepends the `---` document-start marker. Supports compact notation and optional literal-block style for multiline strings. ### Method Rust function call ### Parameters - **sink**: `impl fmt::Write` - A mutable reference to a writer, typically a `String`. ### Usage 1. Create a `YamlEmitter` instance with a writer. 2. Optionally configure emitter options like `multiline_strings(true)`. 3. Call `dump()` with the `Yaml` document to serialize. ### Request Example ```rust use yaml_rust2::{YamlEmitter, YamlLoader}; let source = "name: Bob"; let docs = YamlLoader::load_from_str(source).unwrap(); let mut output = String::new(); let mut emitter = YamlEmitter::new(&mut output); emitter.dump(&docs[0]).unwrap(); assert!(output.contains("name: Bob")); ``` ``` -------------------------------- ### Parse YAML string with YamlLoader::load_from_str Source: https://context7.com/ethiraric/yaml-rust2/llms.txt Use `load_from_str` for parsing YAML strings into a `Vec`. It supports various data types and safe access to nested elements. Returns `ScanError` on malformed input. ```rust use yaml_rust2::{Yaml, YamlLoader}; fn main() { let source = " name: Alice age: 30 scores: [95, 87, 100] active: true ratio: 3.14 nothing: ~ "; let docs = YamlLoader::load_from_str(source).unwrap(); let doc = &docs[0]; // String access assert_eq!(doc["name"].as_str().unwrap(), "Alice"); // Integer access assert_eq!(doc["age"].as_i64().unwrap(), 30); // Array element access assert_eq!(doc["scores"][0].as_i64().unwrap(), 95); // Boolean access assert_eq!(doc["active"].as_bool().unwrap(), true); // Float access assert!((doc["ratio"].as_f64().unwrap() - 3.14).abs() < f64::EPSILON); // Null check assert!(doc["nothing"].is_null()); // Safe access: missing key returns BadValue, never panics assert!(doc["nonexistent"]["nested"].is_badvalue()); } ``` -------------------------------- ### Alias yaml-rust2 in Cargo.toml Source: https://github.com/ethiraric/yaml-rust2/blob/master/documents/2024-03-15-FirstRelease.md Use this method to switch to `yaml-rust2` while maintaining the `yaml_rust` alias in your code, avoiding code changes. ```diff -yaml-rust = "0.4.4" +yaml-rust = { version = "0.6", package = "yaml-rust2" } ```