diff --git a/.gitignore b/.gitignore
index 18b12d1c..0ca6673f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
build
Cargo.lock
Icon?
+public/test_site/test.txt
diff --git a/Cargo.toml b/Cargo.toml
index b25ed80f..a90f2398 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ name = "serde_yml"
readme = "README.md"
repository = "https://github.com/sebastienrousseau/serde_yml"
rust-version = "1.60"
-version = "0.0.9"
+version = "0.0.10"
include = [
"/CONTRIBUTING.md",
"/LICENSE-APACHE",
@@ -40,7 +40,7 @@ include = [
[dependencies]
indexmap = "2.2.6"
itoa = "1.0.11"
-libyml = "0.0.1"
+libyml = "0.0.3"
log = { version = "0.4.21", features = ["std"] }
memchr = "2.7.2"
ryu = "1.0.18"
diff --git a/README.md b/README.md
index 28917b7e..7992858c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
@@ -41,17 +41,17 @@ and for inspiring this project.
```toml
[dependencies]
serde = "1.0"
-serde_yml = "0.0.9"
+serde_yml = "0.0.10"
```
Release notes are available under [GitHub releases][04].
-## Using Serde YAML
+## Using Serde YML
[API documentation is available in rustdoc form][docs.rs] but the general idea
is:
-[docs.rs]: https://docs.rs/serde_yaml
+[docs.rs]: https://docs.rs/serde_yml
```rust
use serde::{Serialize, Deserialize};
diff --git a/TEMPLATE.md b/TEMPLATE.md
index 3810d322..51e8225c 100644
--- a/TEMPLATE.md
+++ b/TEMPLATE.md
@@ -42,21 +42,21 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
#### Forked Serde YAML
-- **Hard reset**: Hard reset to the latest @dtolnay [latest release](https://github.com/dtolnay/serde-yaml/commit/2009506d33767dfc88e979d6bc0d53d09f941c94) to keep traceability and retain commits history to the original [Serde YAML](https://github.com/dtolnay/serde-yaml) codebase and credits to the maintainers.
-- **Renaming**: This project, has been renamed to `Serde YML` to avoid confusion with the original Serde YAML crate which is now archived and no longer maintained. While `Serde YML` started as a fork of serde-yaml, it has now evolved into a separate library with its own goals and direction in mind and does not intend to replace the original serde-yaml crate.
+- **Hard reset**: Hard reset to the latest @dtolnay [latest release](https://github.com/dtolnay/serde-yaml/commit/2009506d33767dfc88e979d6bc0d53d09f941c94) to keep traceability and retain commits history to the original [Serde YAML](https://github.com/dtolnay/serde-yaml) codebase and credits to the maintainers.
+- **Renaming**: This project, has been renamed to `Serde YML` to avoid confusion with the original Serde YAML crate which is now archived and no longer maintained. While `Serde YML` started as a fork of serde-yaml, it has now evolved into a separate library with its own goals and direction in mind and does not intend to replace the original serde-yaml crate.
#### CI Improvements
-- **ci(serde-yaml)**: Added a missing release workflow and made minor tweaks to the README for better clarity and documentation. This update ensures smoother and more reliable release processes.
- - Commit: `ci(serde-yaml): :green_heart: add missing release workflow and minor tweaks in README`
+- **ci(serde-yaml)**: Added a missing release workflow and made minor tweaks to the README for better clarity and documentation. This update ensures smoother and more reliable release processes.
+ - Commit: `ci(serde-yaml): :green_heart: add missing release workflow and minor tweaks in README`
#### Testing Enhancements
-- **test(serde-yaml)**: Enhanced test coverage by adding new unit tests for `mapping.rs`. These tests ensure the robustness and reliability of the `Mapping` struct and its associated methods.
+- **test(serde-yaml)**: Enhanced test coverage by adding new unit tests for `mapping.rs`. These tests ensure the robustness and reliability of the `Mapping` struct and its associated methods.
- - Commit: `test(serde-yaml): :white_check_mark: add new tests for `mapping.rs``
+ - Commit: `test(serde-yaml): :white_check_mark: add new tests for`mapping.rs``
-- **test(serde-yaml)**: Expanded the test suite by adding comprehensive unit tests for the `ser.rs` module. The new tests cover various serialization scenarios, including scalar values, sequences, maps, nested structures, optional fields, and custom serializers.
- - Commit: `test(serde-yaml): :white_check_mark: add unit tests for the `ser.rs` module`
+- **test(serde-yaml)**: Expanded the test suite by adding comprehensive unit tests for the `ser.rs` module. The new tests cover various serialization scenarios, including scalar values, sequences, maps, nested structures, optional fields, and custom serializers.
+ - Commit: `test(serde-yaml): :white_check_mark: add unit tests for the`ser.rs`module`
-**Full Changelog**: https://github.com/sebastienrousseau/serde_yml/commits/v0.0.9
+**Full Changelog**:
diff --git a/examples/example.rs b/examples/example.rs
index 095a928b..d2afb97a 100644
--- a/examples/example.rs
+++ b/examples/example.rs
@@ -11,9 +11,15 @@
/// Contains the example modules for the `loader` module.
mod loader;
+/// Contains the example modules for the `modules` module.
+mod modules;
+
/// Contains the example modules for the `serializer` module.
mod serializer;
+/// Contains the example modules for the `value` module.
+mod value;
+
/// Examples for the `with` module.
mod with;
@@ -29,9 +35,15 @@ fn main() {
// Run the example module `loader`.
loader::main();
+ // Run the example module `modules`.
+ modules::main();
+
// Run the example module `serializer`.
serializer::main();
+ // Run the example module `value`.
+ value::main();
+
// Run the example module `with`.
with::main();
diff --git a/examples/libyml/emitter_examples.rs b/examples/libyml/emitter_examples.rs
new file mode 100644
index 00000000..f683bc24
--- /dev/null
+++ b/examples/libyml/emitter_examples.rs
@@ -0,0 +1,345 @@
+//! Examples for the `Emitter` struct and its methods in the `emitter` module.
+//!
+//! This file demonstrates the creation, usage, and various functionalities of the `Emitter` for emitting YAML events, including scalars, sequences, mappings, and document/stream events.
+
+use serde_yml::libyml::emitter::{
+ Emitter, Event, Mapping, Scalar, ScalarStyle, Sequence,
+};
+use std::io::Cursor;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed
+ println!("\n❯ Executing examples/libyml/emitter_examples.rs");
+
+ // Example: Emitting a stream start and end event
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted stream start and end: {}", output);
+
+ // Example: Emitting a document start and end event with a scalar
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted document with scalar: {}", output);
+
+ // Example: Emitting a sequence
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted sequence: {}", output);
+
+ // Example: Emitting a mapping
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted mapping: {}", output);
+
+ // Example: Flushing the emitter
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.flush().unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted and flushed: {}", output);
+
+ // Example: Emitting scalar with tag
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: Some("!mytag".to_string()),
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted scalar with tag: {}", output);
+
+ // Example: Emitting sequence with tag
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence {
+ tag: Some("!mytag".to_string()),
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted sequence with tag: {}", output);
+
+ // Example: Emitting mapping with tag
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping {
+ tag: Some("!mytag".to_string()),
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted mapping with tag: {}", output);
+
+ // Example: Emitting an empty sequence
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted empty sequence: {}", output);
+
+ // Example: Emitting an empty mapping
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted empty mapping: {}", output);
+
+ // Example: Emitting a nested sequence
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted nested sequence: {}", output);
+
+ // Example: Emitting a nested mapping
+ let mut buffer = Cursor::new(Vec::new());
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested_key",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested_value",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ let output =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ println!("\n✅ Emitted nested mapping: {}", output);
+}
diff --git a/examples/libyml/mod.rs b/examples/libyml/mod.rs
index 3a0ae6ce..f9fa13d1 100644
--- a/examples/libyml/mod.rs
+++ b/examples/libyml/mod.rs
@@ -1,8 +1,32 @@
/// This module contains the `tag` example.
-pub(crate) mod tag;
+pub(crate) mod tag_examples;
+
+/// This module contains the `emitter` example.
+pub(crate) mod emitter_examples;
+
+/// This module contains the `parser` example.
+pub(crate) mod parser_examples;
+
+/// This module contains the `safe_cstr` example.
+pub(crate) mod safe_cstr_examples;
+
+/// This module contains the `util` example.
+pub(crate) mod util_examples;
/// The main function that runs all the example modules.
pub(crate) fn main() {
+ // Run the example module `emitter`.
+ emitter_examples::main();
+
+ // Run the example module `parser`.
+ parser_examples::main();
+
+ // Run the example module `safe_cstr`.
+ safe_cstr_examples::main();
+
// Run the example module `tag`.
- tag::main();
+ tag_examples::main();
+
+ // Run the example module `util`.
+ util_examples::main();
}
diff --git a/examples/libyml/parser_examples.rs b/examples/libyml/parser_examples.rs
new file mode 100644
index 00000000..f7d7f06b
--- /dev/null
+++ b/examples/libyml/parser_examples.rs
@@ -0,0 +1,285 @@
+//! Examples for the `Parser` struct and its methods in the `parser` module.
+//!
+//! This file demonstrates the creation, usage, and event parsing of `Parser` instances,
+//! as well as handling different types of YAML events and input scenarios.
+
+use serde_yml::libyml::parser::{Event, Parser};
+use std::borrow::Cow;
+
+#[allow(clippy::single_match)]
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/parser_examples.rs");
+
+ // Example 1: Creating a parser and parsing a stream start event
+ {
+ let input = Cow::Borrowed(b"foo: bar\n");
+ let mut parser = Parser::new(Cow::Borrowed(input.as_ref()));
+ match parser.parse_next_event() {
+ Ok((event, _)) => {
+ match event {
+ Event::StreamStart => {
+ println!("\n✅ Stream start event parsed successfully.")
+ }
+ _ => println!("\n❌ Unexpected event."),
+ }
+ }
+ Err(err) => println!("Error parsing event: {:?}", err),
+ }
+ }
+
+ // Example 2: Parsing a stream end event
+ {
+ let input = Cow::Borrowed(b"foo: bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::StreamEnd) {
+ println!("\n✅ Stream end event parsed successfully.");
+ break;
+ }
+ }
+ }
+
+ // Example 3: Parsing a document start event
+ {
+ let input = Cow::Borrowed(b"---\nfoo: bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::DocumentStart) {
+ println!(
+ "\n✅ Document start event parsed successfully."
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 4: Parsing a document end event
+ {
+ let input =
+ Cow::Borrowed(b"foo: bar\n---\nbaz: qux\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::DocumentEnd) {
+ println!(
+ "\n✅ Document end event parsed successfully."
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 5: Parsing a scalar event
+ {
+ let input = Cow::Borrowed(b"bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if let Event::Scalar(scalar) = event {
+ println!(
+ "\n✅ Scalar event parsed successfully with value: {:?}",
+ scalar.value
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 6: Parsing a sequence start event
+ {
+ let input = Cow::Borrowed(b"- item1\n- item2\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceStart(_)) {
+ println!(
+ "\n✅ Sequence start event parsed successfully."
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 7: Parsing a sequence end event
+ {
+ let input = Cow::Borrowed(b"- item1\n- item2\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceEnd) {
+ println!(
+ "\n✅ Sequence end event parsed successfully."
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 8: Parsing a mapping start event
+ {
+ let input = Cow::Borrowed(b"key: value\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::MappingStart(_)) {
+ println!(
+ "\n✅ Mapping start event parsed successfully."
+ );
+ break;
+ }
+ }
+ }
+
+ // Example 9: Parsing a mapping end event
+ {
+ let input = Cow::Borrowed(b"key: value\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::MappingEnd) {
+ println!("\n✅ Mapping end event parsed successfully.");
+ break;
+ }
+ }
+ }
+
+ // Example 10: Handling unexpected input
+ {
+ let input = Cow::Borrowed(b"unexpected: [value").as_ref(); // Malformed YAML
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ match parser.parse_next_event() {
+ Ok(_) => println!(
+ "\n❌ Unexpectedly parsed malformed input without error."
+ ),
+ Err(err) => {
+ println!("\n❌ Error parsing malformed input: {:?}", err)
+ }
+ }
+ }
+
+ // Example 11: Handling empty input
+ {
+ let input = Cow::Borrowed(b"").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ match parser.parse_next_event() {
+ Ok((event, _)) => match event {
+ Event::StreamEnd => println!("Stream end event parsed successfully for empty input."),
+ _ => println!("Unexpected event for empty input."),
+ },
+ Err(err) => println!("Error parsing empty input: {:?}", err),
+ }
+ }
+
+ // Example 12: Parsing nested sequences
+ {
+ let input =
+ Cow::Borrowed(b"- item1\n- - nested1\n - nested2\n")
+ .as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_nested_start = false;
+
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceStart(_)) {
+ if found_nested_start {
+ println!("\n✅ Nested sequence start event parsed successfully.");
+ break;
+ } else {
+ found_nested_start = true;
+ }
+ }
+ }
+
+ if !found_nested_start {
+ println!("\n❌ Nested sequence start event was not found.");
+ }
+ }
+
+ // Example 13: Parsing mixed content (sequence and mapping)
+ {
+ let input =
+ Cow::Borrowed(b"- item1\nkey: value\n- item2\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_sequence = false;
+ let mut found_mapping = false;
+
+ while let Ok((event, _)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceStart(_)) {
+ found_sequence = true;
+ }
+ if matches!(event, Event::MappingStart(_)) {
+ found_mapping = true;
+ }
+ if found_sequence && found_mapping {
+ println!("\n✅ Mixed content parsed successfully (sequence and mapping).");
+ break;
+ }
+ }
+
+ if !found_sequence {
+ println!("\n❌ Sequence start event was not found.");
+ }
+ if !found_mapping {
+ println!("\n❌ Mapping start event was not found.");
+ }
+ }
+
+ // Example 14: Error handling with invalid input
+ {
+ let input = Cow::Borrowed(b"invalid: [yaml").as_ref(); // Invalid YAML
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ match parser.parse_next_event() {
+ Ok(_) => println!(
+ "\n❌ Unexpectedly parsed invalid input without error."
+ ),
+ Err(err) => println!(
+ "\n✅ Correctly handled error for invalid input: {:?}",
+ err
+ ),
+ }
+ }
+
+ // Example 15: Parser initialization check
+ {
+ let input = Cow::Borrowed(b"foo: bar\n").as_ref();
+ let parser = Parser::new(Cow::Borrowed(input));
+ if parser.is_ok() {
+ println!("\n✅ Parser initialized successfully.");
+ } else {
+ println!("\n❌ Parser failed to initialize.");
+ }
+ }
+
+ // Example 16: Parsing complex nested structures
+ {
+ let input = Cow::Borrowed(
+ b"- item1\n- item2:\n - nested1\n - nested2\n- item3\n",
+ )
+ .as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ match event {
+ Event::SequenceStart(_) => {
+ println!("\n✅ Sequence start event found.")
+ }
+ Event::MappingStart(_) => {
+ println!("\n✅ Mapping start event found.")
+ }
+ Event::Scalar(scalar) => {
+ println!("\n✅ Scalar value: {:?}", scalar.value)
+ }
+ _ => {}
+ }
+ }
+ }
+
+ // Example 17: Handling comments in YAML (if supported)
+ {
+ let input =
+ Cow::Borrowed(b"# This is a comment\nfoo: bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ while let Ok((event, _)) = parser.parse_next_event() {
+ match event {
+ Event::Scalar(scalar) => {
+ println!("\n✅ Scalar value: {:?}", scalar.value)
+ }
+ // Event::Comment(comment) => println!("\n✅ Comment: {:?}", comment), // Uncomment if comments are supported
+ _ => {}
+ }
+ }
+ }
+}
diff --git a/examples/libyml/safe_cstr_examples.rs b/examples/libyml/safe_cstr_examples.rs
new file mode 100644
index 00000000..8477cfa1
--- /dev/null
+++ b/examples/libyml/safe_cstr_examples.rs
@@ -0,0 +1,137 @@
+//! Examples for the `CStr` struct and its methods in the `safe_cstr` module.
+//!
+//! This file demonstrates the creation, usage, and comparison of `CStr` instances,
+//! as well as the usage of its various methods.
+
+use serde_yml::libyml::safe_cstr::{CStr, CStrError};
+use std::ffi::CString;
+use std::ptr::NonNull;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/safe_cstr_examples.rs");
+
+ // Example: Creating a new CStr instance from a byte slice with a null terminator
+ let bytes: &'static [u8] = b"hello\0";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => {
+ println!("\n✅ Created a new CStr instance: {:?}", cstr)
+ }
+ Err(_) => println!("\n❌ Failed to create CStr instance"),
+ }
+
+ // Example: Creating a new CStr instance from a byte slice without a null terminator
+ let bytes: &'static [u8] = b"hello";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(_) => println!("\n❌ This should not happen"),
+ Err(CStrError) => println!("\n✅ Correctly failed to create CStr instance without null terminator"),
+ }
+
+ // Example: Creating a new CStr instance from an empty byte slice
+ let bytes: &'static [u8] = b"";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(_) => println!("\n❌ This should not happen"),
+ Err(CStrError) => println!("\n✅ Correctly failed to create CStr instance from empty byte slice"),
+ }
+
+ // Example: Creating a new CStr instance from a byte slice with only a null terminator
+ let bytes: &'static [u8] = b"\0";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => {
+ println!("\n✅ Created an empty CStr instance: {:?}", cstr)
+ }
+ Err(_) => println!("\n❌ Failed to create CStr instance"),
+ }
+
+ // Example: Creating a new CStr instance from a byte slice with one character and a null terminator
+ let bytes: &'static [u8] = b"a\0";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => println!(
+ "\n✅ Created a CStr instance with one character: {:?}",
+ cstr
+ ),
+ Err(_) => println!("\n❌ Failed to create CStr instance"),
+ }
+
+ // Example: Creating a new CStr instance from a non-null pointer
+ let c_string = CString::new("hello").unwrap();
+ let ptr = NonNull::new(c_string.into_raw()).unwrap();
+ let cstr = CStr::from_ptr(ptr);
+ println!(
+ "\n✅ Created a new CStr instance from a pointer: {:?}",
+ cstr
+ );
+
+ // Example: Calculating the length of the CStr instance
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!("\n✅ Length of the CStr instance: {}", cstr.len());
+
+ // Example: Checking if the CStr instance is empty
+ let bytes: &'static [u8] = b"\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!("\n✅ Is the CStr instance empty? {}", cstr.is_empty());
+
+ // Example: Retrieving the underlying byte slice of the CStr instance
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!(
+ "\n✅ The underlying byte slice of the CStr instance: {:?}",
+ cstr.to_bytes()
+ );
+
+ // Example: Using the Display implementation for CStr
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!(
+ "\n✅ Display representation of the CStr instance: {}",
+ cstr
+ );
+
+ // Example: Using the Debug implementation for CStr
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!(
+ "\n✅ Debug representation of the CStr instance: {:?}",
+ cstr
+ );
+
+ // Example: Using the Display implementation for CStr with invalid UTF-8
+ let bytes: &'static [u8] = b"hello\xFFworld\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!("\n✅ Display representation of the CStr instance with invalid UTF-8: {}", cstr);
+
+ // Example: Using the Debug implementation for CStr with invalid UTF-8
+ let bytes: &'static [u8] = b"hello\xFFworld\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ println!("\n✅ Debug representation of the CStr instance with invalid UTF-8: {:?}", cstr);
+
+ // Example: Handling the custom CStrError error type
+ let error = CStrError;
+ println!("\n✅ Custom CStrError message: {}", error);
+
+ // Example: Creating a CStr instance with a very long string
+ const LONG_STRING_SIZE: usize = 10_000;
+ let mut long_string = Vec::with_capacity(LONG_STRING_SIZE + 1);
+ long_string.extend(std::iter::repeat(b'a').take(LONG_STRING_SIZE));
+ long_string.push(b'\0');
+ let bytes = Box::leak(long_string.into_boxed_slice());
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => println!("\n✅ Created a CStr instance with a long string: Length = {}", cstr.len()),
+ Err(_) => println!("\n❌ Failed to create CStr instance with long string"),
+ }
+
+ // Example: Creating a CStr instance with Unicode characters
+ let bytes: &'static [u8] = "hello🌍\0".as_bytes();
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => println!("\n✅ Created a CStr instance with Unicode characters: {:?}", cstr),
+ Err(_) => println!("\n❌ Failed to create CStr instance with Unicode characters"),
+ }
+
+ // Example: Creating a CStr instance with multiple null terminators
+ let bytes: &'static [u8] = b"hello\0world\0";
+ match CStr::from_bytes_with_nul(bytes) {
+ Ok(cstr) => println!("\n✅ Created a CStr instance with multiple null terminators: {:?}", cstr),
+ Err(_) => println!("\n❌ Failed to create CStr instance with multiple null terminators"),
+ }
+}
diff --git a/examples/libyml/tag.rs b/examples/libyml/tag.rs
deleted file mode 100644
index bae73fde..00000000
--- a/examples/libyml/tag.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-//! Examples for the `Tag` struct and its methods in the `tag` module.
-//!
-//! This file demonstrates the creation, usage, and comparison of `Tag` instances,
-//! as well as the usage of its various methods.
-
-use serde_yml::libyml::tag::Tag;
-use serde_yml::libyml::tag::TagFormatError;
-
-pub(crate) fn main() {
- // Print a message to indicate the file being executed.
- println!("\n❯ Executing examples/libyml/tag.rs");
-
- // Example: Creating a new Tag instance
- let tag_null = Tag::new(Tag::NULL);
- println!(
- "\n✅ Created a new Tag instance for NULL: {:?}",
- tag_null
- );
-
- // Example: Creating a Tag instance for a custom tag
- let custom_tag = Tag::new("tag:example.org,2024:custom");
- println!(
- "\n✅ Created a new Tag instance for custom tag: {:?}",
- custom_tag
- );
-
- // Example: Checking if a Tag starts with a prefix
- match custom_tag.starts_with("tag:example.org") {
- Ok(true) => {
- println!("\n✅ The tag starts with the given prefix.")
- }
- Ok(false) => println!(
- "\n✅ The tag does not start with the given prefix."
- ),
- Err(TagFormatError) => {
- println!("\n✅ Error: The prefix is longer than the tag.")
- }
- }
-
- // Example: Comparing a Tag with a &str
- let comparison_str = "tag:example.org,2024:custom";
- if custom_tag == comparison_str {
- println!("\n✅ The tag is equal to the given string slice.");
- } else {
- println!(
- "\n✅ The tag is not equal to the given string slice."
- );
- }
-
- // Example: Using Deref to access the underlying byte slice
- let tag_bytes: &[u8] = &custom_tag;
- println!(
- "\n✅ The underlying byte slice of the tag: {:?}",
- tag_bytes
- );
-
- // Example: Using the Debug implementation
- println!(
- "\n✅ Debug representation of the custom tag: {:?}",
- custom_tag
- );
-
- // Example: Using Tag constants
- let tag_bool = Tag::new(Tag::BOOL);
- println!(
- "\n✅ Created a new Tag instance for BOOL: {:?}",
- tag_bool
- );
- let tag_int = Tag::new(Tag::INT);
- println!("\n✅ Created a new Tag instance for INT: {:?}", tag_int);
- let tag_float = Tag::new(Tag::FLOAT);
- println!(
- "\n✅ Created a new Tag instance for FLOAT: {:?}",
- tag_float
- );
-}
diff --git a/examples/libyml/tag_examples.rs b/examples/libyml/tag_examples.rs
new file mode 100644
index 00000000..cd3c93f1
--- /dev/null
+++ b/examples/libyml/tag_examples.rs
@@ -0,0 +1,164 @@
+//! Examples for the `Tag` struct and its methods in the `tag` module.
+//!
+//! This file demonstrates the creation, usage, and comparison of `Tag` instances,
+//! as well as the usage of its various methods.
+
+use serde_yml::libyml::tag::{Tag, TagFormatError};
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/tag_examples.rs");
+
+ // Example: Creating a new Tag instance
+ let tag_null = Tag::new(Tag::NULL);
+ println!(
+ "\n✅ Created a new Tag instance for NULL: {:?}",
+ tag_null
+ );
+
+ // Example: Creating a Tag instance for a custom tag
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ println!(
+ "\n✅ Created a new Tag instance for custom tag: {:?}",
+ custom_tag
+ );
+
+ // Example: Checking if a Tag starts with a prefix
+ match custom_tag.starts_with("tag:example.org") {
+ Ok(true) => {
+ println!("\n✅ The tag starts with the given prefix.")
+ }
+ Ok(false) => println!(
+ "\n✅ The tag does not start with the given prefix."
+ ),
+ Err(TagFormatError) => {
+ println!("\n✅ Error: The prefix is longer than the tag.")
+ }
+ }
+
+ // Example: Comparing a Tag with a &str
+ let comparison_str = "tag:example.org,2024:custom";
+ if custom_tag == comparison_str {
+ println!("\n✅ The tag is equal to the given string slice.");
+ } else {
+ println!(
+ "\n✅ The tag is not equal to the given string slice."
+ );
+ }
+
+ // Example: Using Deref to access the underlying byte slice
+ let tag_bytes: &[u8] = &custom_tag;
+ println!(
+ "\n✅ The underlying byte slice of the tag: {:?}",
+ tag_bytes
+ );
+
+ // Example: Using the Debug implementation
+ println!(
+ "\n✅ Debug representation of the custom tag: {:?}",
+ custom_tag
+ );
+
+ // Example: Using Tag constants
+ let tag_bool = Tag::new(Tag::BOOL);
+ println!(
+ "\n✅ Created a new Tag instance for BOOL: {:?}",
+ tag_bool
+ );
+ let tag_int = Tag::new(Tag::INT);
+ println!("\n✅ Created a new Tag instance for INT: {:?}", tag_int);
+ let tag_float = Tag::new(Tag::FLOAT);
+ println!(
+ "\n✅ Created a new Tag instance for FLOAT: {:?}",
+ tag_float
+ );
+
+ // Example: Handling TagFormatError when the prefix is longer than the tag
+ match custom_tag.starts_with("tag:example.org,2024:custom:extra") {
+ Ok(_) => println!("\n✅ The tag starts with the given prefix."),
+ Err(TagFormatError) => {
+ println!("\n✅ Error: The prefix is longer than the tag.")
+ }
+ }
+
+ // Example: Validating a list of YAML tags
+ let tags = vec![
+ Tag::new("tag:example.org,2024:custom1"),
+ Tag::new("tag:example.org,2024:custom2"),
+ Tag::new("tag:example.com,2024:other"),
+ ];
+
+ for tag in &tags {
+ if tag.starts_with("tag:example.org").unwrap_or(false) {
+ println!("\n✅ The tag {:?} starts with the prefix 'tag:example.org'", tag);
+ } else {
+ println!("\n✅ The tag {:?} does not start with the prefix 'tag:example.org'", tag);
+ }
+ }
+
+ // Example: Comparing tags with different formats
+ let another_custom_tag = Tag::new("tag:example.org,2024:custom");
+ if custom_tag == another_custom_tag {
+ println!("\n✅ The custom_tag is equal to another_custom_tag.");
+ } else {
+ println!(
+ "\n✅ The custom_tag is not equal to another_custom_tag."
+ );
+ }
+
+ // Example: Filtering tags based on a prefix
+ let filtered_tags: Vec<&Tag> = tags
+ .iter()
+ .filter(|tag| {
+ tag.starts_with("tag:example.org").unwrap_or(false)
+ })
+ .collect();
+
+ println!(
+ "\n✅ Filtered tags that start with 'tag:example.org': {:?}",
+ filtered_tags
+ );
+
+ // Example: Creating a custom function to process tags
+ fn print_tag_info(tag: &Tag) {
+ println!("\n📌 Tag info: {:?}", tag);
+ if tag.starts_with("tag:example.org").unwrap_or(false) {
+ println!("✅ This tag starts with 'tag:example.org'");
+ } else {
+ println!(
+ "❌ This tag does not start with 'tag:example.org'"
+ );
+ }
+ }
+
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ print_tag_info(&custom_tag);
+
+ // Example: Error handling with invalid tags
+ let invalid_tag = "invalid:tag";
+ match Tag::new(invalid_tag).starts_with("tag:example.org") {
+ Ok(_) => println!(
+ "\n✅ The invalid_tag starts with the given prefix."
+ ),
+ Err(TagFormatError) => {
+ println!("\n❌ Error: The prefix is longer than the invalid_tag.")
+ }
+ }
+
+ // Example: Real-world scenario - parsing and validating tags from a YAML document
+ let yaml_tags = vec![
+ "tag:example.org,2024:custom1",
+ "tag:example.org,2024:custom2",
+ "tag:example.com,2024:other",
+ "invalid:tag",
+ ];
+
+ for yaml_tag in yaml_tags {
+ let tag = Tag::new(yaml_tag);
+ match tag.starts_with("tag:example.org") {
+ Ok(true) => println!("\n✅ The tag {:?} is valid and starts with 'tag:example.org'", tag),
+ Ok(false) => println!("\n✅ The tag {:?} is valid but does not start with 'tag:example.org'", tag),
+ Err(TagFormatError) => println!("\n❌ The tag {:?} is invalid or the prefix is too long", tag),
+ }
+ }
+}
diff --git a/examples/libyml/util_examples.rs b/examples/libyml/util_examples.rs
new file mode 100644
index 00000000..d3c86eda
--- /dev/null
+++ b/examples/libyml/util_examples.rs
@@ -0,0 +1,69 @@
+//! Examples for the `Owned` and `InitPtr` structs and their methods in the `util` module.
+//!
+//! This file demonstrates the creation, usage, and safety considerations of `Owned` and `InitPtr` instances,
+//! as well as the usage of their various methods.
+
+use serde_yml::libyml::util::{InitPtr, Owned};
+use std::mem::MaybeUninit;
+use std::ops::Deref;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/util_examples.rs");
+
+ // Example: Creating a new uninitialized Owned instance
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ println!(
+ "\n✅ Created a new uninitialized Owned instance: {:?}",
+ uninit_owned
+ );
+
+ // Example: Converting an uninitialized Owned instance to an initialized one
+ let init_owned: Owned =
+ unsafe { Owned::assume_init(uninit_owned) };
+ println!(
+ "\n✅ Converted to an initialized Owned instance: {:?}",
+ init_owned
+ );
+
+ // Example: Dereferencing an Owned instance
+ let init_ptr = init_owned.deref().ptr;
+ println!(
+ "\n✅ Dereferenced the Owned instance to get the InitPtr: {:?}",
+ init_ptr
+ );
+
+ // Example: Creating an InitPtr instance
+ let mut value: i32 = 42;
+ let init_ptr = InitPtr { ptr: &mut value };
+ println!(
+ "\n✅ Created an InitPtr instance: {:?} with value: {}",
+ init_ptr,
+ unsafe { *init_ptr.ptr }
+ );
+
+ // Example: Using the Drop implementation
+ {
+ let drop_owned: Owned, i32> =
+ Owned::new_uninit();
+ println!(
+ "\n✅ Created a new Owned instance to be dropped: {:?}",
+ drop_owned
+ );
+ } // drop_owned goes out of scope here, and memory is deallocated.
+
+ // Example: Creating Owned instances with different types
+ let uninit_owned_f64: Owned, f64> =
+ Owned::new_uninit();
+ println!(
+ "\n✅ Created a new uninitialized Owned instance: {:?}",
+ uninit_owned_f64
+ );
+ let init_owned_f64: Owned =
+ unsafe { Owned::assume_init(uninit_owned_f64) };
+ println!(
+ "\n✅ Converted to an initialized Owned instance: {:?}",
+ init_owned_f64
+ );
+}
diff --git a/examples/modules/mod.rs b/examples/modules/mod.rs
new file mode 100644
index 00000000..3326d899
--- /dev/null
+++ b/examples/modules/mod.rs
@@ -0,0 +1,8 @@
+/// This module contains the `path` example.
+pub(crate) mod path_examples;
+
+/// The main function that runs all the example modules.
+pub(crate) fn main() {
+ // Run the example module `path`.
+ path_examples::main();
+}
diff --git a/examples/modules/path_examples.rs b/examples/modules/path_examples.rs
new file mode 100644
index 00000000..dd4fa0a6
--- /dev/null
+++ b/examples/modules/path_examples.rs
@@ -0,0 +1,230 @@
+//! Examples for the `Path` enum and its usage in the `path` module.
+//!
+//! This file demonstrates the creation, usage, and formatting of `Path` instances,
+//! as well as handling various path scenarios.
+
+use serde_json::to_string;
+use serde_yml::modules::path::Path;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/path_examples.rs");
+
+ // Example: Creating a Path::Root instance
+ let path_root = Path::Root;
+ println!("\n✅ Created a Path::Root instance: {}", path_root); // Output: .
+
+ // Example: Creating a Path::Seq instance
+ let path_seq = Path::Seq {
+ parent: &path_root,
+ index: 42,
+ };
+ println!("\n✅ Created a Path::Seq instance: {}", path_seq); // Output: [42]
+
+ // Example: Creating a Path::Map instance
+ let path_map = Path::Map {
+ parent: &path_root,
+ key: "key",
+ };
+ println!("\n✅ Created a Path::Map instance: {}", path_map); // Output: key
+
+ // Example: Creating a Path::Alias instance
+ let path_alias = Path::Alias { parent: &path_root };
+ println!("\n✅ Created a Path::Alias instance: {}", path_alias); // Output: (empty string)
+
+ // Example: Creating a Path::Unknown instance
+ let path_unknown = Path::Unknown { parent: &path_root };
+ println!("\n✅ Created a Path::Unknown instance: {}", path_unknown); // Output: ?
+
+ // Example: Nested paths
+ let path_nested = Path::Unknown {
+ parent: &Path::Alias {
+ parent: &Path::Map {
+ parent: &Path::Seq {
+ parent: &path_root,
+ index: 0,
+ },
+ key: "key",
+ },
+ },
+ };
+ println!("\n✅ Created a nested Path instance: {}", path_nested); // Output: [0].key..?
+
+ // Example: Deeply nested paths
+ let path_deeply_nested = Path::Unknown {
+ parent: &Path::Alias {
+ parent: &Path::Map {
+ parent: &Path::Seq {
+ parent: &Path::Map {
+ parent: &Path::Seq {
+ parent: &path_root,
+ index: 1,
+ },
+ key: "first",
+ },
+ index: 2,
+ },
+ key: "second",
+ },
+ },
+ };
+ println!(
+ "\n✅ Created a deeply nested Path instance: {}",
+ path_deeply_nested
+ ); // Output: [1].first[2].second..?
+
+ // Example: Path with an empty key in Path::Map
+ let path_map_empty_key = Path::Map {
+ parent: &path_root,
+ key: "",
+ };
+ println!(
+ "\n✅ Created a Path::Map instance with an empty key: {}",
+ path_map_empty_key
+ ); // Output: (empty string)
+
+ // Example: Path with maximum index in Path::Seq
+ let path_seq_max_index = Path::Seq {
+ parent: &path_root,
+ index: usize::MAX,
+ };
+ println!(
+ "\n✅ Created a Path::Seq instance with max index: {}",
+ path_seq_max_index
+ ); // Output: [18446744073709551615]
+
+ // Example: Complex nested paths
+ let path_complex_nested = Path::Unknown {
+ parent: &Path::Alias {
+ parent: &Path::Map {
+ parent: &Path::Seq {
+ parent: &Path::Map {
+ parent: &Path::Seq {
+ parent: &Path::Map {
+ parent: &path_root,
+ key: "third",
+ },
+ index: 3,
+ },
+ key: "second",
+ },
+ index: 2,
+ },
+ key: "first",
+ },
+ },
+ };
+ println!(
+ "\n✅ Created a complex nested Path instance: {}",
+ path_complex_nested
+ ); // Output: [2].first[3].second.third..?
+
+ // Example: Path with multiple unknowns
+ let path_multiple_unknowns = Path::Unknown {
+ parent: &Path::Unknown {
+ parent: &Path::Unknown { parent: &path_root },
+ },
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple unknowns: {}",
+ path_multiple_unknowns
+ ); // Output: .?.?.?
+
+ // Example: Path with multiple aliases
+ let path_multiple_aliases = Path::Alias {
+ parent: &Path::Alias {
+ parent: &Path::Alias { parent: &path_root },
+ },
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple aliases: {}",
+ path_multiple_aliases
+ ); // Output: ..
+
+ // Example: Path with multiple sequences
+ let path_multiple_sequences = Path::Seq {
+ parent: &Path::Seq {
+ parent: &Path::Seq {
+ parent: &path_root,
+ index: 1,
+ },
+ index: 2,
+ },
+ index: 3,
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple sequences: {}",
+ path_multiple_sequences
+ ); // Output: \[1\].\[2\].\[3\]
+
+ // Example: Path with multiple maps
+ let path_multiple_maps = Path::Map {
+ parent: &Path::Map {
+ parent: &Path::Map {
+ parent: &path_root,
+ key: "first",
+ },
+ key: "second",
+ },
+ key: "third",
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple maps: {}",
+ path_multiple_maps
+ ); // Output: first.second.third
+
+ // Example: Path with multiple aliases, sequences, and maps
+ let path_multiple_nested = Path::Alias {
+ parent: &Path::Seq {
+ parent: &Path::Map {
+ parent: &Path::Alias { parent: &path_root },
+ key: "first",
+ },
+ index: 2,
+ },
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple nested paths: {}",
+ path_multiple_nested
+ ); // Output: .first.\[2\].
+
+ // Example: Path with multiple unknowns, aliases, sequences, and maps
+ let path_multiple_complex = Path::Unknown {
+ parent: &Path::Alias {
+ parent: &Path::Seq {
+ parent: &Path::Map {
+ parent: &Path::Unknown { parent: &path_root },
+ key: "first",
+ },
+ index: 2,
+ },
+ },
+ };
+ println!(
+ "\n✅ Created a Path instance with multiple complex paths: {}",
+ path_multiple_complex
+ ); // Output: ?.first.\[2\]..?
+
+ // Example: Serializing and deserializing Path instances
+ let path_to_serialize = Path::Seq {
+ parent: &path_root,
+ index: 42,
+ };
+
+ let serialized = to_string(&path_to_serialize).unwrap();
+ println!("\n✅ Serialized Path::Seq instance: {}", serialized);
+
+ // Example: Comparing Path instances
+ let another_path_seq = Path::Seq {
+ parent: &path_root,
+ index: 42,
+ };
+ if path_seq == another_path_seq {
+ println!("\n✅ The path_seq is equal to another_path_seq.");
+ } else {
+ println!("\n❌ The path_seq is not equal to another_path_seq.");
+ }
+
+ // Example: Debug representation of Path instances
+ println!("\n✅ Debug representation of path_seq: {:?}", path_seq);
+}
diff --git a/examples/value/de_examples.rs b/examples/value/de_examples.rs
new file mode 100644
index 00000000..7c5a10b5
--- /dev/null
+++ b/examples/value/de_examples.rs
@@ -0,0 +1,115 @@
+//! This file demonstrates the deserialization of various data structures such as empty tuples,
+//! empty tuple structs, newtype variants, sequences, maps, option types, and enums with multiple variants using `serde_yml`.
+
+use serde::Deserialize;
+use serde_yml::Value;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/de_examples.rs");
+
+ // Example: Deserializing an empty tuple struct.
+ fn example_deserialize_empty_tuple_struct() {
+ let yaml_str = "---";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Empty;
+
+ let result: Empty = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized Empty tuple struct: {:?}", result);
+ }
+
+ // Example: Deserializing an empty tuple.
+ fn example_deserialize_empty_tuple() {
+ let yaml_str = "---";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ let result: () = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized Empty tuple: {:?}", result);
+ }
+
+ // Example: Deserializing a newtype variant.
+ fn example_deserialize_newtype_variant() {
+ let yaml_str = "!Variant 0";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(i32),
+ }
+
+ let result: E = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized newtype variant: {:?}", result);
+ }
+
+ // Example: Deserializing a struct with multiple fields.
+ fn example_deserialize_struct_with_fields() {
+ let yaml_str = "
+name: \"John Doe\"
+age: 30
+";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Person {
+ name: String,
+ age: i32,
+ }
+
+ let result: Person = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized struct with fields: {:?}", result);
+ }
+
+ // Example: Deserializing a sequence (Vec).
+ fn example_deserialize_sequence() {
+ let yaml_str = "
+- 1
+- 2
+- 3
+";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ let result: Vec = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized sequence: {:?}", result);
+ }
+
+ // Example: Deserializing a map (HashMap).
+ fn example_deserialize_map() {
+ use std::collections::HashMap;
+ let yaml_str = "
+key1: value1
+key2: value2
+";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ let result: HashMap =
+ serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized map: {:?}", result);
+ }
+
+ // Example: Deserializing an option type.
+ fn example_deserialize_option() {
+ let yaml_str_some = "some_value";
+ let value_some: Value =
+ serde_yml::from_str(yaml_str_some).unwrap();
+ let result_some: Option =
+ serde_yml::from_value(value_some).unwrap();
+ println!("\n✅ Deserialized option (Some): {:?}", result_some);
+
+ let yaml_str_none = "---";
+ let value_none: Value =
+ serde_yml::from_str(yaml_str_none).unwrap();
+ let result_none: Option =
+ serde_yml::from_value(value_none).unwrap();
+ println!("\n✅ Deserialized option (None): {:?}", result_none);
+ }
+ // Execute the examples
+ example_deserialize_empty_tuple_struct();
+ example_deserialize_empty_tuple();
+ example_deserialize_newtype_variant();
+ example_deserialize_struct_with_fields();
+ example_deserialize_sequence();
+ example_deserialize_map();
+ example_deserialize_option();
+}
diff --git a/examples/value/index_examples.rs b/examples/value/index_examples.rs
new file mode 100644
index 00000000..b866ec39
--- /dev/null
+++ b/examples/value/index_examples.rs
@@ -0,0 +1,222 @@
+//! Examples for the `Index` trait and its implementations in the `index` module.
+//!
+//! This file demonstrates the usage of the `Index` trait with various implementations,
+//! including indexing into sequences and mappings, and handling out-of-bounds and invalid indices.
+
+use serde_yml::value::Index;
+use serde_yml::Value;
+
+pub(crate) fn main() {
+ // Print a message to indicate the file being executed.
+ println!("\n❯ Executing examples/libyml/index_examples.rs");
+
+ // Example: Indexing into a sequence using usize
+ let sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 1;
+ match index.index_into(&sequence) {
+ Some(value) => {
+ println!("\n✅ Indexed into sequence: {:?}", value)
+ }
+ None => println!("\n❌ Index out of bounds"),
+ }
+
+ // Example: Indexing into a mapping using usize
+ let mut mapping = serde_yml::Mapping::new();
+ mapping
+ .insert(Value::Number(1.into()), Value::String("one".into()));
+ let value = Value::Mapping(mapping);
+ match index.index_into(&value) {
+ Some(value) => {
+ println!("\n✅ Indexed into mapping: {:?}", value)
+ }
+ None => println!("\n❌ Key not found"),
+ }
+
+ // Example: Indexing into a sequence with out-of-bounds index using usize
+ let index = 3;
+ match index.index_into(&sequence) {
+ Some(value) => {
+ println!("\n✅ Indexed into sequence: {:?}", value)
+ }
+ None => println!("\n❌ Index out of bounds"),
+ }
+
+ // Example: Indexing into a mapping with a non-numeric key using usize
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ match index.index_into(&value) {
+ Some(value) => {
+ println!("\n✅ Indexed into mapping: {:?}", value)
+ }
+ None => println!("\n❌ Key not found"),
+ }
+
+ // Example: Mutably indexing into a sequence using usize
+ let mut sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 1;
+ if let Some(value) = index.index_into_mut(&mut sequence) {
+ *value = Value::Number(3.into());
+ println!("\n✅ Mutably indexed into sequence: {:?}", sequence);
+ }
+
+ // Example: Mutably indexing into a mapping using usize
+ let mut mapping = serde_yml::Mapping::new();
+ mapping
+ .insert(Value::Number(1.into()), Value::String("one".into()));
+ let mut value = Value::Mapping(mapping);
+ if let Some(value) = index.index_into_mut(&mut value) {
+ *value = Value::String("two".into());
+ println!("\n✅ Mutably indexed into mapping: {:?}", value);
+ }
+
+ // Example: Mutably indexing into a sequence with out-of-bounds index using usize
+ let index = 3;
+ if let Some(value) = index.index_into_mut(&mut sequence) {
+ *value = Value::Number(4.into());
+ } else {
+ println!("\n❌ Index out of bounds");
+ }
+
+ // Example: Using index_or_insert with a sequence using usize
+ let mut sequence = Value::Sequence(vec![Value::Number(1.into())]);
+ let index = 1;
+ if index >= sequence.as_sequence().unwrap().len() {
+ for _ in sequence.as_sequence().unwrap().len()..=index {
+ sequence.as_sequence_mut().unwrap().push(Value::Null);
+ }
+ }
+ index
+ .index_or_insert(&mut sequence)
+ .clone_from(&Value::Number(2.into()));
+ println!("\n✅ Used index_or_insert with sequence: {:?}", sequence);
+
+ // Example: Using index_or_insert with a mapping using usize
+ let mapping = serde_yml::Mapping::new();
+ let mut value = Value::Mapping(mapping);
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("one".into()));
+ let mut expected_mapping = serde_yml::Mapping::new();
+ expected_mapping
+ .insert(Value::Number(1.into()), Value::String("one".into()));
+ println!("\n✅ Used index_or_insert with mapping: {:?}", value);
+
+ // Example: Indexing into a non-indexable value
+ let value = Value::String("hello".into());
+ match index.index_into(&value) {
+ Some(value) => println!("\n✅ Indexed into value: {:?}", value),
+ None => println!("\n❌ Cannot index into non-indexable value"),
+ }
+
+ // Example: Mutably indexing into a non-indexable value
+ let mut value = Value::String("hello".into());
+ if let Some(value) = index.index_into_mut(&mut value) {
+ *value = Value::String("world".into());
+ println!("\n✅ Mutably indexed into value: {:?}", value);
+ } else {
+ println!("\n❌ Cannot index into non-indexable value");
+ }
+
+ // Example: Using index_or_insert with a non-indexable value
+ let value = Value::String("hello".into());
+ let result = std::panic::catch_unwind(move || {
+ let mut value_owned = value.clone();
+ index.index_or_insert(&mut value_owned);
+ });
+ match result {
+ Ok(_) => println!("\n❌ Should have panicked"),
+ Err(_) => {
+ println!("\n✅ Correctly panicked for non-indexable value")
+ }
+ }
+
+ // Example: Using index_or_insert with a null value
+ let value = Value::Null;
+ let result = std::panic::catch_unwind(move || {
+ let mut value_owned = value.clone();
+ index.index_or_insert(&mut value_owned);
+ });
+ match result {
+ Ok(_) => println!("\n❌ Should have panicked"),
+ Err(_) => println!("\n✅ Correctly panicked for null value"),
+ }
+
+ // Example: Indexing into a mapping using &str
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = "key";
+ match index.index_into(&value) {
+ Some(value) => {
+ println!("\n✅ Indexed into mapping with &str: {:?}", value)
+ }
+ None => println!("\n❌ Key not found"),
+ }
+
+ // Example: Mutably indexing into a mapping using &str
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = "key";
+ if let Some(value) = index.index_into_mut(&mut value) {
+ *value = Value::String("new_value".into());
+ println!(
+ "\n✅ Mutably indexed into mapping with &str: {:?}",
+ value
+ );
+ }
+
+ // Example: Using index_or_insert with a mapping using &str
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = "new_key";
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ println!(
+ "\n✅ Used index_or_insert with mapping and &str: {:?}",
+ value
+ );
+
+ // Example: Indexing into a nested mapping
+ let mut nested_mapping = serde_yml::Mapping::new();
+ nested_mapping.insert(
+ Value::String("inner_key".into()),
+ Value::String("inner_value".into()),
+ );
+ let mut outer_mapping = serde_yml::Mapping::new();
+ outer_mapping.insert(
+ Value::String("outer_key".into()),
+ Value::Mapping(nested_mapping),
+ );
+ let value = Value::Mapping(outer_mapping);
+ let index = Value::String("outer_key".into());
+ if let Some(inner_value) = index
+ .index_into(&value)
+ .and_then(|v| "inner_key".index_into(v))
+ {
+ println!("\n✅ Indexed into nested mapping: {:?}", inner_value);
+ } else {
+ println!("\n❌ Key not found in nested mapping");
+ }
+}
diff --git a/examples/value/mod.rs b/examples/value/mod.rs
new file mode 100644
index 00000000..780763b1
--- /dev/null
+++ b/examples/value/mod.rs
@@ -0,0 +1,14 @@
+/// This module contains the `de` examples.
+pub(crate) mod de_examples;
+
+/// This module contains the `index` examples.
+pub(crate) mod index_examples;
+
+/// The main function that runs all the example modules.
+pub(crate) fn main() {
+ // Run the example module `de_examples`.
+ de_examples::main();
+
+ // Run the example module `index_examples`.
+ index_examples::main();
+}
diff --git a/src/lib.rs b/src/lib.rs
index c6aabebb..9d1ec43c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,7 +45,7 @@
//!
//! ```toml
//! [dependencies]
-//! serde_yml = "0.0.9"
+//! serde_yml = "0.0.10"
//! ```
//!
//! ## Usage
diff --git a/src/libyml/emitter.rs b/src/libyml/emitter.rs
index c5b95c24..6057909f 100644
--- a/src/libyml/emitter.rs
+++ b/src/libyml/emitter.rs
@@ -28,9 +28,9 @@ use std::{
/// Errors that can occur during YAML emission.
#[derive(Debug)]
-pub(crate) enum Error {
+pub enum Error {
/// Errors related to libyml.
- Libyaml(libyml::error::Error),
+ Libyml(libyml::error::Error),
/// I/O errors.
Io(io::Error),
}
@@ -143,7 +143,7 @@ pub struct Mapping {
impl<'a> Emitter<'a> {
/// Creates a new YAML emitter.
- pub(crate) fn new(write: Box) -> Emitter<'a> {
+ pub fn new(write: Box) -> Emitter<'a> {
let owned = Owned::>::new_uninit();
let pin = unsafe {
let emitter = addr_of_mut!((*owned.ptr).sys);
@@ -168,10 +168,7 @@ impl<'a> Emitter<'a> {
}
/// Emits a YAML event.
- pub(crate) fn emit(
- &mut self,
- event: Event<'_>,
- ) -> Result<(), Error> {
+ pub fn emit(&mut self, event: Event<'_>) -> Result<(), Error> {
let mut sys_event = MaybeUninit::::uninit();
let sys_event = sys_event.as_mut_ptr();
unsafe {
@@ -285,7 +282,7 @@ impl<'a> Emitter<'a> {
}
};
if initialize_status.fail {
- return Err(Error::Libyaml(libyml::Error::emit_error(
+ return Err(Error::Libyml(libyml::Error::emit_error(
emitter,
)));
}
@@ -297,7 +294,7 @@ impl<'a> Emitter<'a> {
}
/// Flushes the YAML emitter.
- pub(crate) fn flush(&mut self) -> Result<(), Error> {
+ pub fn flush(&mut self) -> Result<(), Error> {
unsafe {
let emitter = addr_of_mut!((*self.pin.ptr).sys);
if yaml_emitter_flush(emitter).fail {
@@ -309,18 +306,18 @@ impl<'a> Emitter<'a> {
/// Retrieves the inner writer from the YAML emitter.
#[allow(unused_mut)]
- pub(crate) fn into_inner(mut self) -> Box {
+ pub fn into_inner(mut self) -> Box {
let sink = Box::new(io::sink());
unsafe { mem::replace(&mut (*self.pin.ptr).write, sink) }
}
/// Retrieves the error from the YAML emitter.
- fn error(&mut self) -> Error {
+ pub fn error(&mut self) -> Error {
let emitter = unsafe { &mut *self.pin.ptr };
if let Some(write_error) = emitter.write_error.take() {
Error::Io(write_error)
} else {
- Error::Libyaml(unsafe {
+ Error::Libyml(unsafe {
libyml::Error::emit_error(&emitter.sys)
})
}
diff --git a/src/libyml/error.rs b/src/libyml/error.rs
index c2621d66..f85f909a 100644
--- a/src/libyml/error.rs
+++ b/src/libyml/error.rs
@@ -17,30 +17,30 @@ pub struct Error {
///
/// This field uses the `yaml_error_type_t` type from the `libyml` crate,
/// which represents different types of errors.
- kind: sys::YamlErrorTypeT,
+ pub kind: sys::YamlErrorTypeT,
/// A null-terminated string describing the problem that caused the error.
///
/// The `CStr<'static>` type represents a borrowed C-style string with a static lifetime.
- problem: CStr<'static>,
+ pub problem: CStr<'static>,
/// The offset of the problem that caused the error.
- problem_offset: u64,
+ pub problem_offset: u64,
/// The mark indicating the position of the problem that caused the error.
///
/// The `Mark` type represents a position in the YAML input.
- problem_mark: Mark,
+ pub problem_mark: Mark,
/// An optional null-terminated string providing additional context for the error.
///
/// The `CStr<'static>` type represents a borrowed C-style string with a static lifetime.
- context: Option>,
+ pub context: Option>,
/// The mark indicating the position of the context related to the error.
///
/// The `Mark` type represents a position in the YAML input.
- context_mark: Mark,
+ pub context_mark: Mark,
}
impl Error {
@@ -191,7 +191,7 @@ pub struct Mark {
///
/// This field is marked as `pub(super)`, which means it is accessible within the current module
/// and its parent module, but not from outside the crate.
- pub(super) sys: sys::YamlMarkT,
+ pub sys: sys::YamlMarkT,
}
impl Mark {
diff --git a/src/libyml/parser.rs b/src/libyml/parser.rs
index 940cd935..222ebf9a 100644
--- a/src/libyml/parser.rs
+++ b/src/libyml/parser.rs
@@ -35,7 +35,7 @@ pub struct Parser<'input> {
///
/// Pinning is used to ensure that the `Parser` remains at a fixed memory
/// location, which is required for safe interaction with the `libyml` library.
- pin: Owned>,
+ pub pin: Owned>,
}
/// Represents a pinned parser for YAML deserialization.
@@ -44,13 +44,13 @@ pub struct Parser<'input> {
/// for parsing YAML documents. It is pinned to a specific lifetime `'input`
/// to ensure that the borrowed input data remains valid throughout the
/// lifetime of the parser.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ParserPinned<'input> {
/// The underlying `YamlParserT` struct from the `libyml` library.
- sys: sys::YamlParserT,
+ pub sys: sys::YamlParserT,
/// The input data being parsed.
- input: Cow<'input, [u8]>,
+ pub input: Cow<'input, [u8]>,
}
/// Represents a YAML event encountered during parsing.
@@ -180,6 +180,30 @@ impl<'input> Parser<'input> {
if sys::yaml_parser_parse(parser, event).fail {
return Err(Error::parse_error(parser));
}
+
+ let event_type = (*event).type_;
+
+ // Handle specific cases
+ if event_type == sys::YamlNoEvent
+ || event_type == sys::YamlStreamEndEvent
+ {
+ let mark = Mark {
+ sys: (*event).start_mark,
+ };
+ sys::yaml_event_delete(event);
+ return Ok((Event::StreamEnd, mark));
+ }
+
+ if event_type == sys::YamlScalarEvent
+ && (*event).data.scalar.value.is_null()
+ {
+ let mark = Mark {
+ sys: (*event).start_mark,
+ };
+ sys::yaml_event_delete(event);
+ return Ok((Event::StreamEnd, mark));
+ }
+
let ret = convert_event(&*event, &(*self.pin.ptr).input);
let mark = Mark {
sys: (*event).start_mark,
@@ -188,8 +212,28 @@ impl<'input> Parser<'input> {
Ok((ret, mark))
}
}
+ /// Checks if the parser is initialized and ready to parse YAML.
+ ///
+ /// This function returns `true` if the parser is initialized and ready to parse YAML, and `false` otherwise.
+ pub fn is_ok(&self) -> bool {
+ unsafe {
+ let parser = addr_of_mut!((*self.pin.ptr).sys);
+ if sys::yaml_parser_initialize(parser).fail {
+ return false;
+ }
+ sys::yaml_parser_set_encoding(
+ parser,
+ sys::YamlUtf8Encoding,
+ );
+ let input_ptr = (*self.pin.ptr).input.as_ptr();
+ let input_len = (*self.pin.ptr).input.len() as u64;
+ sys::yaml_parser_set_input_string(
+ parser, input_ptr, input_len,
+ );
+ true
+ }
+ }
}
-
unsafe fn convert_event<'input>(
sys: &sys::YamlEventT,
input: &'input Cow<'input, [u8]>,
diff --git a/src/libyml/util.rs b/src/libyml/util.rs
index 04936550..0a31dbe1 100644
--- a/src/libyml/util.rs
+++ b/src/libyml/util.rs
@@ -8,7 +8,7 @@ use std::{
/// A struct representing ownership of a pointer to a value of type `T`.
/// `Init` represents the initialization state of the value.
#[derive(Debug)]
-pub(crate) struct Owned {
+pub struct Owned {
ptr: NonNull,
marker: PhantomData>,
}
@@ -19,7 +19,7 @@ impl Owned {
/// # Safety
/// The created instance contains uninitialized memory, and should be properly
/// initialized before use.
- pub(crate) fn new_uninit() -> Owned, T> {
+ pub fn new_uninit() -> Owned, T> {
// Allocate memory for `T` but leave it uninitialized.
let boxed = Box::new(MaybeUninit::::uninit());
Owned {
@@ -35,7 +35,7 @@ impl Owned {
///
/// # Safety
/// The caller must ensure that `definitely_init` is properly initialized.
- pub(crate) unsafe fn assume_init(
+ pub unsafe fn assume_init(
definitely_init: Owned, T>,
) -> Owned {
let ptr = definitely_init.ptr;
@@ -49,8 +49,10 @@ impl Owned {
/// A transparent wrapper around a mutable pointer of type `T`.
#[repr(transparent)]
-pub(crate) struct InitPtr {
- pub(crate) ptr: *mut T,
+#[derive(Debug)]
+pub struct InitPtr {
+ /// The mutable pointer.
+ pub ptr: *mut T,
}
impl Deref for Owned {
diff --git a/src/modules/error.rs b/src/modules/error.rs
index 4e0abc86..d6aa1bbd 100644
--- a/src/modules/error.rs
+++ b/src/modules/error.rs
@@ -76,7 +76,7 @@ pub enum ErrorImpl {
/// A generic error message with an optional position.
Message(String, Option),
/// An error originating from the `libyml` library.
- Libyaml(libyml::Error),
+ Libyml(libyml::Error),
/// An I/O error.
IoError(io::Error),
/// An error encountered while converting a byte slice to a string using UTF-8 encoding.
@@ -115,7 +115,7 @@ impl Display for ErrorImpl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ErrorImpl::Message(msg, _) => write!(f, "Error: {}", msg),
- ErrorImpl::Libyaml(_) => write!(f, "Error: An error occurred in the Libyaml library"),
+ ErrorImpl::Libyml(_) => write!(f, "Error: An error occurred in the Libyml library"),
ErrorImpl::IoError(err) => write!(f, "I/O Error: {}", err),
ErrorImpl::FromUtf8(err) => write!(f, "UTF-8 Conversion Error: {}", err),
ErrorImpl::EndOfStream => write!(f, "Unexpected End of YAML Stream: The YAML stream ended unexpectedly while parsing a value"),
@@ -191,14 +191,14 @@ pub fn fix_mark(
impl From for Error {
fn from(err: libyml::Error) -> Self {
- Error(Box::new(ErrorImpl::Libyaml(err)))
+ Error(Box::new(ErrorImpl::Libyml(err)))
}
}
impl From for Error {
fn from(err: emitter::Error) -> Self {
match err {
- emitter::Error::Libyaml(err) => Self::from(err),
+ emitter::Error::Libyml(err) => Self::from(err),
emitter::Error::Io(err) => new(ErrorImpl::IoError(err)),
}
}
@@ -255,7 +255,7 @@ impl ErrorImpl {
ErrorImpl::Message(_, Some(Pos { mark, path: _ }))
| ErrorImpl::RecursionLimitExceeded(mark)
| ErrorImpl::UnknownAnchor(mark) => Some(*mark),
- ErrorImpl::Libyaml(err) => Some(err.mark()),
+ ErrorImpl::Libyml(err) => Some(err.mark()),
ErrorImpl::Shared(err) => err.mark(),
_ => None,
}
@@ -270,7 +270,7 @@ impl ErrorImpl {
}
f.write_str(description)
}
- ErrorImpl::Libyaml(_) => unreachable!(),
+ ErrorImpl::Libyml(_) => unreachable!(),
ErrorImpl::IoError(err) => Display::fmt(err, f),
ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
@@ -312,7 +312,7 @@ impl ErrorImpl {
fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- ErrorImpl::Libyaml(err) => Display::fmt(err, f),
+ ErrorImpl::Libyml(err) => Display::fmt(err, f),
ErrorImpl::Shared(err) => err.display(f),
_ => {
self.message(f)?;
@@ -328,7 +328,7 @@ impl ErrorImpl {
fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- ErrorImpl::Libyaml(err) => Debug::fmt(err, f),
+ ErrorImpl::Libyml(err) => Debug::fmt(err, f),
ErrorImpl::Shared(err) => err.debug(f),
_ => {
f.write_str("Error(")?;
diff --git a/src/modules/path.rs b/src/modules/path.rs
index ad285a0c..2899d56e 100644
--- a/src/modules/path.rs
+++ b/src/modules/path.rs
@@ -1,3 +1,4 @@
+use serde::Serialize;
use std::fmt::{self, Display};
/// `Path` represents the path to the current value in the input, like `dependencies.serde.typo1`.
@@ -12,7 +13,7 @@ use std::fmt::{self, Display};
/// - `Map`: Represents a map (object) path with a reference to the parent path and a key.
/// - `Alias`: Represents an alias path with a reference to the parent path.
/// - `Unknown`: Represents an unknown path with a reference to the parent path.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize)]
pub enum Path<'a> {
/// Represents the root path.
Root,
diff --git a/src/value/de.rs b/src/value/de.rs
index 2c4d2ad0..a61ffb64 100644
--- a/src/value/de.rs
+++ b/src/value/de.rs
@@ -14,6 +14,7 @@ use std::fmt::Result as FmtResult;
use std::slice;
use std::vec;
+/// Deserializes a `Value` from a given deserializer.
impl<'de> Deserialize<'de> for Value {
fn deserialize(deserializer: D) -> Result
where
@@ -31,46 +32,46 @@ impl<'de> Deserialize<'de> for Value {
formatter.write_str("any YAML value")
}
- fn visit_bool(self, b: bool) -> Result
+ fn visit_bool(self, value: bool) -> Result
where
E: de::Error,
{
- Ok(Value::Bool(b))
+ Ok(Value::Bool(value))
}
- fn visit_i64(self, i: i64) -> Result
+ fn visit_i64(self, value: i64) -> Result
where
E: de::Error,
{
- Ok(Value::Number(i.into()))
+ Ok(Value::Number(value.into()))
}
- fn visit_u64(self, u: u64) -> Result
+ fn visit_u64(self, value: u64) -> Result
where
E: de::Error,
{
- Ok(Value::Number(u.into()))
+ Ok(Value::Number(value.into()))
}
- fn visit_f64(self, f: f64) -> Result
+ fn visit_f64(self, value: f64) -> Result
where
E: de::Error,
{
- Ok(Value::Number(f.into()))
+ Ok(Value::Number(value.into()))
}
- fn visit_str(self, s: &str) -> Result
+ fn visit_str(self, value: &str) -> Result
where
E: de::Error,
{
- Ok(Value::String(s.to_owned()))
+ Ok(Value::String(value.to_owned()))
}
- fn visit_string(self, s: String) -> Result
+ fn visit_string(self, value: String) -> Result
where
E: de::Error,
{
- Ok(Value::String(s))
+ Ok(Value::String(value))
}
fn visit_unit(self) -> Result
@@ -97,20 +98,20 @@ impl<'de> Deserialize<'de> for Value {
Deserialize::deserialize(deserializer)
}
- fn visit_seq(self, data: A) -> Result
+ fn visit_seq(self, seq: A) -> Result
where
A: SeqAccess<'de>,
{
- let de = SeqAccessDeserializer::new(data);
+ let de = SeqAccessDeserializer::new(seq);
let sequence = Sequence::deserialize(de)?;
Ok(Value::Sequence(sequence))
}
- fn visit_map(self, data: A) -> Result
+ fn visit_map(self, map: A) -> Result
where
A: MapAccess<'de>,
{
- let de = MapAccessDeserializer::new(data);
+ let de = MapAccessDeserializer::new(map);
let mapping = Mapping::deserialize(de)?;
Ok(Value::Mapping(mapping))
}
@@ -134,6 +135,7 @@ impl<'de> Deserialize<'de> for Value {
}
impl Value {
+ /// Deserializes a number from the given `Value`.
fn deserialize_number<'de, V>(
&self,
visitor: V,
@@ -148,6 +150,7 @@ impl Value {
}
}
+/// Visits a `Sequence` value with the given `Visitor`.
fn visit_sequence<'de, V>(
sequence: Sequence,
visitor: V,
@@ -166,6 +169,7 @@ where
}
}
+/// Visits a borrowed `Sequence` value with the given `Visitor`.
fn visit_sequence_ref<'de, V>(
sequence: &'de Sequence,
visitor: V,
@@ -184,6 +188,7 @@ where
}
}
+/// Visits a `Mapping` value with the given `Visitor`.
fn visit_mapping<'de, V>(
mapping: Mapping,
visitor: V,
@@ -202,6 +207,7 @@ where
}
}
+/// Visits a borrowed `Mapping` value with the given `Visitor`.
fn visit_mapping_ref<'de, V>(
mapping: &'de Mapping,
visitor: V,
@@ -538,6 +544,7 @@ impl<'de> Deserializer<'de> for Value {
}
}
+/// Represents an enum deserializer.
struct EnumDeserializer<'a> {
tag: &'a str,
value: Option,
@@ -561,6 +568,7 @@ impl<'de> EnumAccess<'de> for EnumDeserializer<'_> {
}
}
+/// Represents a variant deserializer.
struct VariantDeserializer {
value: Option,
}
@@ -623,11 +631,13 @@ impl<'de> VariantAccess<'de> for VariantDeserializer {
}
}
+/// Represents a sequence deserializer.
pub(crate) struct SeqDeserializer {
iter: vec::IntoIter,
}
impl SeqDeserializer {
+ /// Creates a new `SeqDeserializer` from the given vector of `Value`s.
pub(crate) fn new(vec: Vec) -> Self {
SeqDeserializer {
iter: vec.into_iter(),
@@ -705,12 +715,14 @@ impl<'de> SeqAccess<'de> for SeqDeserializer {
}
}
+/// Represents a map deserializer.
pub(crate) struct MapDeserializer {
iter: ::IntoIter,
value: Option,
}
impl MapDeserializer {
+ /// Creates a new `MapDeserializer` from the given `Mapping`.
pub(crate) fn new(map: Mapping) -> Self {
MapDeserializer {
iter: map.into_iter(),
@@ -984,7 +996,6 @@ impl<'de> Deserializer<'de> for &'de Value {
{
self.deserialize_unit(visitor)
}
-
fn deserialize_newtype_struct(
self,
_name: &'static str,
@@ -1104,16 +1115,14 @@ impl<'de> Deserializer<'de> for &'de Value {
visitor.visit_unit()
}
}
-
+/// Represents an enum deserializer for borrowed values.
struct EnumRefDeserializer<'de> {
tag: &'de str,
value: Option<&'de Value>,
}
-
impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> {
type Error = Error;
type Variant = VariantRefDeserializer<'de>;
-
fn variant_seed(
self,
seed: V,
@@ -1127,14 +1136,12 @@ impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> {
Ok((variant, visitor))
}
}
-
+/// Represents a variant deserializer for borrowed values.
struct VariantRefDeserializer<'de> {
value: Option<&'de Value>,
}
-
impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> {
type Error = Error;
-
fn unit_variant(self) -> Result<(), Error> {
match self.value {
Some(value) => {
@@ -1194,20 +1201,18 @@ impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> {
}
}
}
-
+/// Represents a sequence deserializer for borrowed values.
pub(crate) struct SeqRefDeserializer<'de> {
iter: slice::Iter<'de, Value>,
}
-
impl<'de> SeqRefDeserializer<'de> {
+ /// Creates a new SeqRefDeserializer from the given slice of Values.
pub(crate) fn new(slice: &'de [Value]) -> Self {
SeqRefDeserializer { iter: slice.iter() }
}
}
-
impl<'de> Deserializer<'de> for SeqRefDeserializer<'de> {
type Error = Error;
-
#[inline]
fn deserialize_any(
mut self,
@@ -1249,10 +1254,8 @@ impl<'de> Deserializer<'de> for SeqRefDeserializer<'de> {
map struct enum identifier
}
}
-
impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> {
type Error = Error;
-
fn next_element_seed(
&mut self,
seed: T,
@@ -1273,13 +1276,13 @@ impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> {
}
}
}
-
+/// Represents a map deserializer for borrowed values.
pub(crate) struct MapRefDeserializer<'de> {
iter: Option<<&'de Mapping as IntoIterator>::IntoIter>,
value: Option<&'de Value>,
}
-
impl<'de> MapRefDeserializer<'de> {
+ /// Creates a new MapRefDeserializer from the given Mapping.
pub(crate) fn new(map: &'de Mapping) -> Self {
MapRefDeserializer {
iter: Some(map.iter()),
@@ -1287,10 +1290,8 @@ impl<'de> MapRefDeserializer<'de> {
}
}
}
-
impl<'de> MapAccess<'de> for MapRefDeserializer<'de> {
type Error = Error;
-
fn next_key_seed(
&mut self,
seed: T,
@@ -1324,10 +1325,8 @@ impl<'de> MapAccess<'de> for MapRefDeserializer<'de> {
}
}
}
-
impl<'de> Deserializer<'de> for MapRefDeserializer<'de> {
type Error = Error;
-
#[inline]
fn deserialize_any(self, visitor: V) -> Result
where
@@ -1352,8 +1351,8 @@ impl<'de> Deserializer<'de> for MapRefDeserializer<'de> {
map struct enum identifier
}
}
-
impl Value {
+ /// Returns an error indicating that the value is of an invalid type for the given visitor.
#[cold]
fn invalid_type(&self, exp: &dyn Expected) -> E
where
@@ -1361,7 +1360,7 @@ impl Value {
{
de::Error::invalid_type(self.unexpected(), exp)
}
-
+ /// Returns an `Unexpected` instance for the current `Value`.
#[cold]
pub(crate) fn unexpected(&self) -> Unexpected<'_> {
match self {
diff --git a/src/value/index.rs b/src/value/index.rs
index fe068880..dd5c1478 100644
--- a/src/value/index.rs
+++ b/src/value/index.rs
@@ -38,6 +38,7 @@ impl Index for usize {
_ => None,
}
}
+
fn index_into_mut<'v>(
&self,
v: &'v mut Value,
@@ -50,6 +51,7 @@ impl Index for usize {
_ => None,
}
}
+
fn index_or_insert<'v>(
&self,
mut v: &'v mut Value,
@@ -147,12 +149,14 @@ impl Index for Value {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
index_into_mapping(self, v)
}
+
fn index_into_mut<'v>(
&self,
v: &'v mut Value,
) -> Option<&'v mut Value> {
index_into_mut_mapping(self, v)
}
+
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
index_or_insert_mapping(self, v)
}
@@ -162,12 +166,14 @@ impl Index for str {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
index_into_mapping(self, v)
}
+
fn index_into_mut<'v>(
&self,
v: &'v mut Value,
) -> Option<&'v mut Value> {
index_into_mut_mapping(self, v)
}
+
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
index_or_insert_mapping(self, v)
}
@@ -177,12 +183,14 @@ impl Index for String {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
self.as_str().index_into(v)
}
+
fn index_into_mut<'v>(
&self,
v: &'v mut Value,
) -> Option<&'v mut Value> {
self.as_str().index_into_mut(v)
}
+
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
self.as_str().index_or_insert(v)
}
@@ -195,12 +203,14 @@ where
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
(**self).index_into(v)
}
+
fn index_into_mut<'v>(
&self,
v: &'v mut Value,
) -> Option<&'v mut Value> {
(**self).index_into_mut(v)
}
+
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
(**self).index_or_insert(v)
}
@@ -242,83 +252,83 @@ impl fmt::Display for Type<'_> {
// `as_sequence`, or match. The value of this impl is that it adds a way of
// working with Value that is not well served by the existing approaches:
// concise and careless and sometimes that is exactly what you want.
+
+/// Index into a `serde_yml::Value` using the syntax `value[0]` or `value["k"]`.
+///
+/// Returns `Value::Null` if the type of `self` does not match the type of
+/// the index, for example if the index is a string and `self` is a sequence
+/// or a number. Also returns `Value::Null` if the given key does not exist
+/// in the map or the given index is not within the bounds of the sequence.
+///
+/// For retrieving deeply nested values, you should have a look at the
+/// `Value::pointer` method.
+///
+/// # Examples
+///
+/// ```
+/// # use serde_yml::Value;
+/// #
+/// # fn main() -> serde_yml::Result<()> {
+/// let data: serde_yml::Value = serde_yml::from_str(r#"{ x: { y: [z, zz] } }"#)?;
+///
+/// assert_eq!(data["x"]["y"], serde_yml::from_str::(r#"["z", "zz"]"#).unwrap());
+/// assert_eq!(data["x"]["y"][0], serde_yml::from_str::(r#""z""#).unwrap());
+///
+/// assert_eq!(data["a"], serde_yml::from_str::(r#"null"#).unwrap()); // returns null for undefined values
+/// assert_eq!(data["a"]["b"], serde_yml::from_str::(r#"null"#).unwrap()); // does not panic
+/// # Ok(())
+/// # }
+/// ```
impl ops::Index for Value
where
I: Index,
{
type Output = Value;
- /// Index into a `serde_yml::Value` using the syntax `value[0]` or
- /// `value["k"]`.
- ///
- /// Returns `Value::Null` if the type of `self` does not match the type of
- /// the index, for example if the index is a string and `self` is a sequence
- /// or a number. Also returns `Value::Null` if the given key does not exist
- /// in the map or the given index is not within the bounds of the sequence.
- ///
- /// For retrieving deeply nested values, you should have a look at the
- /// `Value::pointer` method.
- ///
- /// # Examples
- ///
- /// ```
- /// # use serde_yml::Value;
- /// #
- /// # fn main() -> serde_yml::Result<()> {
- /// let data: serde_yml::Value = serde_yml::from_str(r#"{ x: { y: [z, zz] } }"#)?;
- ///
- /// assert_eq!(data["x"]["y"], serde_yml::from_str::(r#"["z", "zz"]"#).unwrap());
- /// assert_eq!(data["x"]["y"][0], serde_yml::from_str::(r#""z""#).unwrap());
- ///
- /// assert_eq!(data["a"], serde_yml::from_str::(r#"null"#).unwrap()); // returns null for undefined values
- /// assert_eq!(data["a"]["b"], serde_yml::from_str::(r#"null"#).unwrap()); // does not panic
- /// # Ok(())
- /// # }
- /// ```
fn index(&self, index: I) -> &Value {
static NULL: Value = Value::Null;
index.index_into(self).unwrap_or(&NULL)
}
}
+/// Write into a `serde_yml::Value` using the syntax `value[0] = ...` or
+/// `value["k"] = ...`.
+///
+/// If the index is a number, the value must be a sequence of length bigger
+/// than the index. Indexing into a value that is not a sequence or a
+/// sequence that is too small will panic.
+///
+/// If the index is a string, the value must be an object or null which is
+/// treated like an empty object. If the key is not already present in the
+/// object, it will be inserted with a value of null. Indexing into a value
+/// that is neither an object nor null will panic.
+///
+/// # Examples
+///
+/// ```
+/// # fn main() -> serde_yml::Result<()> {
+/// let mut data: serde_yml::Value = serde_yml::from_str(r#"{x: 0}"#)?;
+///
+/// // replace an existing key
+/// data["x"] = serde_yml::from_str(r#"1"#)?;
+///
+/// // insert a new key
+/// data["y"] = serde_yml::from_str(r#"[false, false, false]"#)?;
+///
+/// // replace a value in a sequence
+/// data["y"][0] = serde_yml::from_str(r#"true"#)?;
+///
+/// // inserted a deeply nested key
+/// data["a"]["b"]["c"]["d"] = serde_yml::from_str(r#"true"#)?;
+///
+/// println!("{:?}", data);
+/// # Ok(())
+/// # }
+/// ```
impl ops::IndexMut for Value
where
I: Index,
{
- /// Write into a `serde_yml::Value` using the syntax `value[0] = ...` or
- /// `value["k"] = ...`.
- ///
- /// If the index is a number, the value must be a sequence of length bigger
- /// than the index. Indexing into a value that is not a sequence or a
- /// sequence that is too small will panic.
- ///
- /// If the index is a string, the value must be an object or null which is
- /// treated like an empty object. If the key is not already present in the
- /// object, it will be inserted with a value of null. Indexing into a value
- /// that is neither an object nor null will panic.
- ///
- /// # Examples
- ///
- /// ```
- /// # fn main() -> serde_yml::Result<()> {
- /// let mut data: serde_yml::Value = serde_yml::from_str(r#"{x: 0}"#)?;
- ///
- /// // replace an existing key
- /// data["x"] = serde_yml::from_str(r#"1"#)?;
- ///
- /// // insert a new key
- /// data["y"] = serde_yml::from_str(r#"[false, false, false]"#)?;
- ///
- /// // replace a value in a sequence
- /// data["y"][0] = serde_yml::from_str(r#"true"#)?;
- ///
- /// // inserted a deeply nested key
- /// data["a"]["b"]["c"]["d"] = serde_yml::from_str(r#"true"#)?;
- ///
- /// println!("{:?}", data);
- /// # Ok(())
- /// # }
- /// ```
fn index_mut(&mut self, index: I) -> &mut Value {
index.index_or_insert(self)
}
diff --git a/tests/libyml/mod.rs b/tests/libyml/mod.rs
new file mode 100644
index 00000000..59402571
--- /dev/null
+++ b/tests/libyml/mod.rs
@@ -0,0 +1,17 @@
+/// This module contains the tests for the `emitter` module.
+pub mod test_emitter;
+
+/// This module contains the tests for the `error` module.
+pub mod test_error;
+
+/// This module contains the tests for the `parser` module.
+pub mod test_parser;
+
+/// This module contains the tests for the `test_safe_cstr` module.
+pub mod test_safe_cstr;
+
+/// This module contains the tests for the `test_tag` module.
+pub mod test_tag;
+
+/// This module contains the tests for the `util` module.
+pub mod test_util;
diff --git a/tests/libyml/test_emitter.rs b/tests/libyml/test_emitter.rs
new file mode 100644
index 00000000..1f030b36
--- /dev/null
+++ b/tests/libyml/test_emitter.rs
@@ -0,0 +1,409 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::libyml::emitter::{
+ Emitter, Event, Mapping, Scalar, ScalarStyle, Sequence,
+ };
+ use std::io::Cursor;
+
+ #[test]
+ fn test_emitter_stream_start_end() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "");
+ }
+
+ #[test]
+ fn test_emitter_document_start_end() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "\n");
+ }
+
+ #[test]
+ fn test_emitter_scalar() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "hello\n");
+ }
+
+ #[test]
+ fn test_emitter_sequence() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "- item1\n- item2\n");
+ }
+
+ #[test]
+ fn test_emitter_mapping() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "key1: value1\nkey2: value2\n");
+ }
+
+ #[test]
+ fn test_emitter_flush() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.flush().unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "hello\n");
+ }
+
+ #[test]
+ fn test_emitter_scalar_with_tag() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: Some("!mytag".to_string()),
+ value: "hello",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "!mytag hello\n");
+ }
+
+ #[test]
+ fn test_emitter_sequence_with_tag() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence {
+ tag: Some("!mytag".to_string()),
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "item2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "!mytag\n- item1\n- item2\n");
+ }
+
+ #[test]
+ fn test_emitter_mapping_with_tag() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping {
+ tag: Some("!mytag".to_string()),
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value1",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "value2",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "!mytag\nkey1: value1\nkey2: value2\n");
+ }
+
+ #[test]
+ fn test_emitter_empty_sequence() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "[]\n");
+ }
+
+ #[test]
+ fn test_emitter_empty_mapping() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "{}\n");
+ }
+
+ #[test]
+ fn test_emitter_nested_sequence() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::SequenceStart(Sequence { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::SequenceEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "- - nested\n");
+ }
+
+ #[test]
+ fn test_emitter_nested_mapping() {
+ let mut buffer = Cursor::new(Vec::with_capacity(100));
+ {
+ let mut emitter = Emitter::new(Box::new(&mut buffer));
+ emitter.emit(Event::StreamStart).unwrap();
+ emitter.emit(Event::DocumentStart).unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "key",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::MappingStart(Mapping { tag: None }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested_key",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter
+ .emit(Event::Scalar(Scalar {
+ tag: None,
+ value: "nested_value",
+ style: ScalarStyle::Plain,
+ }))
+ .unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::MappingEnd).unwrap();
+ emitter.emit(Event::DocumentEnd).unwrap();
+ emitter.emit(Event::StreamEnd).unwrap();
+ }
+ buffer.set_position(0);
+
+ let result =
+ String::from_utf8_lossy(&buffer.into_inner()).to_string();
+ assert_eq!(result, "key:\n nested_key: nested_value\n");
+ }
+}
diff --git a/tests/libyml/test_error.rs b/tests/libyml/test_error.rs
new file mode 100644
index 00000000..c018380f
--- /dev/null
+++ b/tests/libyml/test_error.rs
@@ -0,0 +1,25 @@
+#[cfg(test)]
+mod tests {
+ // use libyml as sys;
+ use serde_yml::libyml::error::Result;
+
+ #[test]
+ fn test_result_ok() {
+ let value: Result = Ok(42);
+ match value {
+ Ok(v) => assert_eq!(v, 42),
+ Err(_) => panic!("Expected Ok(42), but got an Err"),
+ }
+ }
+
+ #[test]
+ fn test_result_ok_with_string() {
+ let value: Result = Ok(String::from("Hello, world!"));
+ match value {
+ Ok(v) => assert_eq!(v, "Hello, world!"),
+ Err(_) => {
+ panic!("Expected Ok(\"Hello, world!\"), but got an Err")
+ }
+ }
+ }
+}
diff --git a/tests/libyml/test_parser.rs b/tests/libyml/test_parser.rs
new file mode 100644
index 00000000..e321e10e
--- /dev/null
+++ b/tests/libyml/test_parser.rs
@@ -0,0 +1,187 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::libyml::parser::Event;
+ use serde_yml::libyml::parser::Parser;
+ use std::borrow::Cow;
+
+ /// Tests the creation of a new `Parser` instance with valid input.
+ /// Verifies that the parser is created successfully and initializes correctly.
+ #[test]
+ fn test_parser_creation() {
+ let input = Cow::Borrowed(b"foo: bar\n");
+ let mut parser = Parser::new(Cow::Borrowed(input.as_ref()));
+ assert!(matches!(
+ parser.parse_next_event().unwrap().0,
+ Event::StreamStart
+ ));
+ }
+
+ /// Tests the `parse_next_event` method for a stream start event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_stream_start_event() {
+ let input = Cow::Borrowed(b"foo: bar\n");
+ let mut parser = Parser::new(Cow::Borrowed(input.as_ref()));
+ let (event, _mark) = parser.parse_next_event().unwrap();
+ assert!(matches!(event, Event::StreamStart));
+ }
+
+ /// Tests the `parse_next_event` method for a stream end event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_stream_end_event() {
+ let input = Cow::Borrowed(b"foo: bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut stream_end_reached = false;
+
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::StreamEnd) {
+ stream_end_reached = true;
+ break;
+ }
+ }
+
+ assert!(stream_end_reached, "StreamEnd event was not reached");
+ }
+
+ /// Tests the `parse_next_event` method for a document start event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_document_start_event() {
+ let input = Cow::Borrowed(b"---\nfoo: bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_start = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::DocumentStart) {
+ found_start = true;
+ break;
+ }
+ }
+ assert!(found_start);
+ }
+
+ /// Tests the `parse_next_event` method for a document end event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_document_end_event() {
+ let input =
+ Cow::Borrowed(b"foo: bar\n---\nbaz: qux\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_end = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::DocumentEnd) {
+ found_end = true;
+ break;
+ }
+ }
+ assert!(found_end);
+ }
+
+ /// Tests the `parse_next_event` method for a scalar event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_scalar_event() {
+ let input = Cow::Borrowed(b"bar\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_scalar = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if let Event::Scalar(scalar) = event {
+ assert_eq!(scalar.value.as_ref(), b"bar");
+ found_scalar = true;
+ break;
+ }
+ }
+ assert!(found_scalar);
+ }
+
+ /// Tests the `parse_next_event` method for a sequence start event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_sequence_start_event() {
+ let input = Cow::Borrowed(b"- item1\n- item2\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_start = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceStart(_)) {
+ found_start = true;
+ break;
+ }
+ }
+ assert!(found_start);
+ }
+
+ /// Tests the `parse_next_event` method for a sequence end event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_sequence_end_event() {
+ let input = Cow::Borrowed(b"- item1\n- item2\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_end = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceEnd) {
+ found_end = true;
+ break;
+ }
+ }
+ assert!(found_end);
+ }
+
+ /// Tests the `parse_next_event` method for a mapping start event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_mapping_start_event() {
+ let input = Cow::Borrowed(b"key: value\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_start = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::MappingStart(_)) {
+ found_start = true;
+ break;
+ }
+ }
+ assert!(found_start);
+ }
+
+ /// Tests the `parse_next_event` method for a mapping end event.
+ /// Verifies that the event is correctly parsed and returned.
+ #[test]
+ fn test_parse_mapping_end_event() {
+ let input = Cow::Borrowed(b"key: value\n").as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_end = false;
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::MappingEnd) {
+ found_end = true;
+ break;
+ }
+ }
+ assert!(found_end);
+ }
+
+ /// Tests the `parse_next_event` method for nested sequences.
+ /// Verifies that the events are correctly parsed and returned.
+ #[test]
+ fn test_parse_nested_sequences() {
+ let input =
+ Cow::Borrowed(b"- item1\n- - nested1\n - nested2\n")
+ .as_ref();
+ let mut parser = Parser::new(Cow::Borrowed(input));
+ let mut found_nested_start = false;
+
+ while let Ok((event, _mark)) = parser.parse_next_event() {
+ if matches!(event, Event::SequenceStart(_)) {
+ if found_nested_start {
+ // Found the nested sequence start
+ break;
+ } else {
+ found_nested_start = true;
+ }
+ }
+ }
+
+ assert!(
+ found_nested_start,
+ "Nested sequence start event was not found"
+ );
+ }
+}
diff --git a/tests/libyml/test_safe_cstr.rs b/tests/libyml/test_safe_cstr.rs
new file mode 100644
index 00000000..1f1366ec
--- /dev/null
+++ b/tests/libyml/test_safe_cstr.rs
@@ -0,0 +1,251 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::libyml::safe_cstr::{CStr, CStrError};
+ use std::{ffi::CString, ptr::NonNull, sync::Arc, thread};
+
+ /// Tests creating a `CStr` from a static byte slice with a null terminator.
+ /// Verifies that the `CStr` is created successfully.
+ #[test]
+ fn test_from_bytes_with_nul() {
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes);
+ assert!(cstr.is_ok());
+ let cstr = cstr.unwrap();
+ assert_eq!(cstr.to_bytes(), b"hello");
+ }
+
+ /// Tests creating a `CStr` from a static byte slice without a null terminator.
+ /// Verifies that an error is returned.
+ #[test]
+ fn test_from_bytes_without_nul() {
+ let bytes: &'static [u8] = b"hello";
+ let cstr = CStr::from_bytes_with_nul(bytes);
+ assert!(cstr.is_err());
+ }
+
+ /// Tests creating a `CStr` from an empty byte slice.
+ /// Verifies that an error is returned.
+ #[test]
+ fn test_from_bytes_empty() {
+ let bytes: &'static [u8] = b"";
+ let cstr = CStr::from_bytes_with_nul(bytes);
+ assert!(cstr.is_err());
+ }
+
+ /// Tests creating a `CStr` from a byte slice with only a null terminator.
+ /// Verifies that the `CStr` is created successfully and is empty.
+ #[test]
+ fn test_from_bytes_with_only_nul() {
+ let bytes: &'static [u8] = b"\0";
+ let cstr = CStr::from_bytes_with_nul(bytes);
+ assert!(cstr.is_ok());
+ let cstr = cstr.unwrap();
+ assert!(cstr.is_empty());
+ }
+
+ /// Tests creating a `CStr` from a byte slice with one character and a null terminator.
+ /// Verifies that the `CStr` is created successfully and has the correct length.
+ #[test]
+ fn test_from_bytes_with_one_char() {
+ let bytes: &'static [u8] = b"a\0";
+ let cstr = CStr::from_bytes_with_nul(bytes);
+ assert!(cstr.is_ok());
+ let cstr = cstr.unwrap();
+ assert_eq!(cstr.to_bytes(), b"a");
+ }
+
+ /// Tests creating a `CStr` from a non-null pointer.
+ /// Verifies that the `CStr` is created successfully.
+ #[test]
+ fn test_from_ptr() {
+ let c_string = CString::new("hello").unwrap();
+ let ptr = NonNull::new(c_string.into_raw()).unwrap();
+ let cstr = CStr::from_ptr(ptr);
+ assert_eq!(cstr.to_bytes(), b"hello");
+ }
+
+ /// Tests calculating the length of the `CStr`.
+ /// Verifies that the length is correct.
+ #[test]
+ fn test_len() {
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.len(), 5);
+ }
+
+ /// Tests checking if the `CStr` is empty.
+ /// Verifies that the correct result is returned.
+ #[test]
+ fn test_is_empty() {
+ let bytes: &'static [u8] = b"\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert!(cstr.is_empty());
+ }
+
+ /// Tests retrieving the underlying byte slice of the `CStr`.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes() {
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"hello");
+ }
+
+ /// Tests the `Display` implementation for `CStr`.
+ /// Verifies that the formatted string is correct.
+ #[test]
+ fn test_display() {
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ let display = format!("{}", cstr);
+ assert_eq!(display, "hello");
+ }
+
+ /// Tests the `Debug` implementation for `CStr`.
+ /// Verifies that the debug representation is correct.
+ #[test]
+ fn test_debug() {
+ let bytes: &'static [u8] = b"hello\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ let debug = format!("{:?}", cstr);
+ assert_eq!(debug, "\"hello\"");
+ }
+
+ /// Tests the `Display` implementation for `CStr` with invalid UTF-8.
+ /// Verifies that the formatted string uses replacement characters.
+ #[test]
+ fn test_display_invalid_utf8() {
+ let bytes: &'static [u8] = b"hello\xFFworld\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ let display = format!("{}", cstr);
+ assert_eq!(display, "hello�world");
+ }
+
+ /// Tests the `Debug` implementation for `CStr` with invalid UTF-8.
+ /// Verifies that the debug representation uses escape sequences.
+ #[test]
+ fn test_debug_invalid_utf8() {
+ let bytes: &'static [u8] = b"hello\xFFworld\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ let debug = format!("{:?}", cstr);
+ assert_eq!(debug, "\"hello\\xffworld\"");
+ }
+
+ /// Tests thread safety of `CStr` struct by sending it between threads.
+ #[test]
+ fn test_send_sync() {
+ let cstr = CStr::from_bytes_with_nul(b"hello\0").unwrap();
+ let arc_cstr = Arc::new(cstr);
+
+ let arc_clone = Arc::clone(&arc_cstr);
+ let handle = thread::spawn(move || {
+ assert_eq!(arc_clone.to_bytes(), b"hello");
+ });
+
+ handle.join().unwrap();
+ }
+
+ /// Tests proper handling of null pointers.
+ /// Verifies that creating a `CStr` from a null pointer is not allowed.
+ #[test]
+ fn test_null_pointer() {
+ let ptr = NonNull::new(std::ptr::null_mut::());
+ assert!(ptr.is_none());
+ }
+
+ /// Tests that allocated resources are properly released.
+ #[test]
+ fn test_resource_release() {
+ let c_string = CString::new("hello").unwrap();
+ let raw = c_string.into_raw();
+ unsafe {
+ let _ = CString::from_raw(raw);
+ }
+ }
+
+ /// Tests the custom `CStrError` error type.
+ /// Verifies that the error message is correct.
+ #[test]
+ fn test_cstr_error() {
+ let error = CStrError;
+ assert_eq!(format!("{}", error), "CStr error occurred");
+ }
+
+ /// Tests the `to_bytes` method with a complex byte array.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_complex() {
+ let bytes: &'static [u8] = b"hello\xFFworld\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"hello\xFFworld");
+ }
+
+ /// Tests the `to_bytes` method with an empty byte array.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_empty() {
+ let bytes: &'static [u8] = b"\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"");
+ }
+
+ /// Tests the `to_bytes` method with a byte array containing a single character.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_single_char() {
+ let bytes: &'static [u8] = b"a\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"a");
+ }
+
+ /// Tests the `to_bytes` method with a byte array containing a single character and a null terminator.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_single_char_with_nul() {
+ let bytes: &'static [u8] = b"a\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"a");
+ }
+
+ /// Tests the `to_bytes` method with a byte array containing a single null terminator.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_single_nul() {
+ let bytes: &'static [u8] = b"\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"");
+ }
+
+ /// Tests the `to_bytes` method with a very long byte array.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_long_string() {
+ const LONG_STRING_SIZE: usize = 10_000;
+ let mut long_string = Vec::with_capacity(LONG_STRING_SIZE + 1);
+ long_string
+ .extend(std::iter::repeat(b'a').take(LONG_STRING_SIZE));
+ long_string.push(b'\0');
+ let bytes = Box::leak(long_string.into_boxed_slice());
+
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes().len(), LONG_STRING_SIZE);
+ }
+
+ /// Tests the `to_bytes` method with Unicode characters.
+ /// Verifies that the byte slice is correct.
+ #[test]
+ fn test_to_bytes_unicode() {
+ let bytes: &'static [u8] = "hello🌍\0".as_bytes();
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), "hello🌍".as_bytes());
+ }
+
+ /// Tests the `to_bytes` method with multiple null terminators within the byte array.
+ /// Verifies that the byte slice is correct up to the first null terminator.
+ #[test]
+ fn test_to_bytes_multiple_nulls() {
+ let bytes: &'static [u8] = b"hello\0world\0";
+ let cstr = CStr::from_bytes_with_nul(bytes).unwrap();
+ assert_eq!(cstr.to_bytes(), b"hello");
+ }
+}
diff --git a/tests/libyml/test_tag.rs b/tests/libyml/test_tag.rs
new file mode 100644
index 00000000..2d74184a
--- /dev/null
+++ b/tests/libyml/test_tag.rs
@@ -0,0 +1,84 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::libyml::tag::{Tag, TagFormatError};
+
+ /// Tests the creation of a new Tag instance using the NULL constant.
+ /// Verifies that the created Tag instance is not null.
+ #[test]
+ fn test_new_tag_null() {
+ let tag_null = Tag::new(Tag::NULL);
+ assert!(!tag_null.is_empty());
+ }
+
+ /// Tests the creation of a new Tag instance with a custom tag.
+ /// Verifies that the created Tag instance matches the provided custom tag.
+ #[test]
+ fn test_new_custom_tag() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ assert_eq!(custom_tag, "tag:example.org,2024:custom");
+ }
+
+ /// Tests if a Tag starts with a given prefix.
+ /// Verifies that the method returns true for a matching prefix and false otherwise.
+ #[test]
+ fn test_tag_starts_with() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ assert!(custom_tag.starts_with("tag:example.org").unwrap());
+ assert!(!custom_tag.starts_with("tag:example.com").unwrap());
+ }
+
+ /// Tests the handling of TagFormatError when the prefix is longer than the tag.
+ /// Verifies that the method returns an error for a longer prefix.
+ #[test]
+ fn test_tag_starts_with_error() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ let result =
+ custom_tag.starts_with("tag:example.org,2024:custom:extra");
+ assert!(result.is_err());
+ assert_eq!(result.unwrap_err(), TagFormatError);
+ }
+
+ /// Tests the comparison of a Tag with a &str.
+ /// Verifies that the comparison returns true for matching values and false otherwise.
+ #[test]
+ fn test_tag_comparison() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ let comparison_str = "tag:example.org,2024:custom";
+ assert_eq!(custom_tag, comparison_str);
+
+ let non_matching_str = "tag:example.org,2024:other";
+ assert_ne!(custom_tag, non_matching_str);
+ }
+
+ /// Tests the Deref implementation to access the underlying byte slice.
+ /// Verifies that the dereferenced value matches the original tag string.
+ #[test]
+ fn test_tag_deref() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ let tag_bytes: &[u8] = &custom_tag;
+ assert_eq!(tag_bytes, b"tag:example.org,2024:custom");
+ }
+
+ /// Tests the Debug implementation for a Tag instance.
+ /// Verifies that the debug representation of the Tag instance is correct.
+ #[test]
+ fn test_tag_debug() {
+ let custom_tag = Tag::new("tag:example.org,2024:custom");
+ let debug_str = format!("{:?}", custom_tag);
+ assert_eq!(debug_str, "\"tag:example.org,2024:custom\"");
+ }
+
+ /// Tests the creation of Tag instances using Tag constants for BOOL, INT, and FLOAT.
+ /// Verifies that the created Tag instances match the respective constants.
+ #[test]
+ fn test_tag_constants() {
+ let tag_bool = Tag::new(Tag::BOOL);
+ assert_eq!(tag_bool, Tag::BOOL);
+
+ let tag_int = Tag::new(Tag::INT);
+ assert_eq!(tag_int, Tag::INT);
+
+ let tag_float = Tag::new(Tag::FLOAT);
+ assert_eq!(tag_float, Tag::FLOAT);
+ }
+}
diff --git a/tests/libyml/test_util.rs b/tests/libyml/test_util.rs
new file mode 100644
index 00000000..60ed549f
--- /dev/null
+++ b/tests/libyml/test_util.rs
@@ -0,0 +1,108 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::libyml::util::{InitPtr, Owned};
+ use std::mem::MaybeUninit;
+ use std::ops::Deref;
+
+ /// Tests that a new uninitialized `Owned` instance can be created.
+ /// Verifies that the pointer in the `Owned` instance is not null.
+ #[test]
+ fn test_new_uninit() {
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ assert!(!uninit_owned.ptr.is_null());
+ }
+
+ /// Tests the `assume_init` function to ensure that it correctly converts
+ /// an uninitialized `Owned` instance to an initialized one.
+ /// Verifies that the pointer in the initialized `Owned` instance is not null.
+ #[test]
+ fn test_assume_init() {
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ let init_owned: Owned =
+ unsafe { Owned::assume_init(uninit_owned) };
+ assert!(!init_owned.ptr.is_null());
+ }
+
+ /// Tests the `deref` implementation for `Owned`.
+ /// Verifies that the dereferenced pointer matches the original pointer.
+ #[test]
+ fn test_deref() {
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ let init_ptr = uninit_owned.ptr;
+ assert_eq!(
+ uninit_owned.deref().ptr as *mut MaybeUninit,
+ init_ptr as *mut MaybeUninit
+ );
+ }
+
+ /// Tests the `drop` implementation for `Owned`.
+ /// Ensures that dropping an uninitialized `Owned` instance does not cause a panic.
+ #[test]
+ fn test_drop() {
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ drop(uninit_owned);
+ }
+
+ /// Tests that an `InitPtr` instance is correctly created and its pointer is not null.
+ #[test]
+ fn test_init_ptr() {
+ let mut value: i32 = 42;
+ let init_ptr = InitPtr { ptr: &mut value };
+ assert!(!init_ptr.ptr.is_null());
+ assert_eq!(unsafe { *init_ptr.ptr }, 42);
+ }
+
+ /// Tests the `deref` implementation for initialized `Owned`.
+ /// Verifies that the dereferenced pointer matches the original pointer after initialization.
+ #[test]
+ fn test_deref_after_init() {
+ let uninit_owned: Owned, i32> =
+ Owned::new_uninit();
+ let init_owned: Owned =
+ unsafe { Owned::assume_init(uninit_owned) };
+ let init_ptr = init_owned.ptr;
+ assert_eq!(init_owned.deref().ptr, init_ptr);
+ }
+
+ /// Tests creating and initializing an `Owned` instance with a different type (f64).
+ #[test]
+ fn test_new_uninit_f64() {
+ let uninit_owned: Owned, f64> =
+ Owned::new_uninit();
+ assert!(!uninit_owned.ptr.is_null());
+ }
+
+ /// Tests the `assume_init` function with a different type (f64).
+ #[test]
+ fn test_assume_init_f64() {
+ let uninit_owned: Owned, f64> =
+ Owned::new_uninit();
+ let init_owned: Owned =
+ unsafe { Owned::assume_init(uninit_owned) };
+ assert!(!init_owned.ptr.is_null());
+ }
+
+ /// Tests the `deref` implementation for `Owned` with a different type (f64).
+ #[test]
+ fn test_deref_f64() {
+ let uninit_owned: Owned, f64> =
+ Owned::new_uninit();
+ let init_ptr = uninit_owned.ptr;
+ assert_eq!(
+ uninit_owned.deref().ptr as *mut MaybeUninit,
+ init_ptr as *mut MaybeUninit
+ );
+ }
+
+ /// Tests the `drop` implementation for `Owned` with a different type (f64).
+ #[test]
+ fn test_drop_f64() {
+ let uninit_owned: Owned, f64> =
+ Owned::new_uninit();
+ drop(uninit_owned);
+ }
+}
diff --git a/tests/mod.rs b/tests/mod.rs
index 6995e2a3..25891795 100644
--- a/tests/mod.rs
+++ b/tests/mod.rs
@@ -1,6 +1,12 @@
+/// This module contains the tests for the `libyml` module.
+pub mod libyml;
+
/// This module contains the tests for the `macros` module.
pub mod macros;
+/// This module contains the tests for the `modules` module.
+pub mod modules;
+
/// This module contains the tests for the `utilities` module.
pub mod utilities;
diff --git a/tests/modules/mod.rs b/tests/modules/mod.rs
new file mode 100644
index 00000000..eff6afb5
--- /dev/null
+++ b/tests/modules/mod.rs
@@ -0,0 +1,2 @@
+/// This module contains the tests for the `path` module.
+pub mod test_path;
diff --git a/tests/modules/test_path.rs b/tests/modules/test_path.rs
new file mode 100644
index 00000000..f859651a
--- /dev/null
+++ b/tests/modules/test_path.rs
@@ -0,0 +1,121 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::modules::path::Path;
+
+ /// Test the Path::Root variant.
+ ///
+ /// This test ensures that the root path is correctly formatted as ".".
+ #[test]
+ fn test_path_root() {
+ let path = Path::Root;
+ assert_eq!(format!("{}", path), ".");
+ }
+
+ /// Test the Path::Seq variant.
+ ///
+ /// This test checks that a sequence path with a given index is correctly formatted.
+ #[test]
+ fn test_path_seq() {
+ let root = Path::Root;
+ let path = Path::Seq {
+ parent: &root,
+ index: 42,
+ };
+ assert_eq!(format!("{}", path), "\\[42\\]");
+ }
+
+ /// Test the Path::Map variant.
+ ///
+ /// This test checks that a map path with a given key is correctly formatted.
+ #[test]
+ fn test_path_map() {
+ let root = Path::Root;
+ let path = Path::Map {
+ parent: &root,
+ key: "key",
+ };
+ assert_eq!(format!("{}", path), "key");
+ }
+
+ /// Test the Path::Alias variant.
+ ///
+ /// This test checks that an alias path is correctly formatted.
+ #[test]
+ fn test_path_alias() {
+ let root = Path::Root;
+ let path = Path::Alias { parent: &root };
+ assert_eq!(format!("{}", path), "");
+ }
+
+ /// Test the Path::Unknown variant.
+ ///
+ /// This test checks that an unknown path is correctly formatted.
+ #[test]
+ fn test_path_unknown() {
+ let root = Path::Root;
+ let path = Path::Unknown { parent: &root };
+ assert_eq!(format!("{}", path), "?");
+ }
+
+ /// Test nested paths.
+ ///
+ /// This test ensures that nested paths with various combinations of variants are correctly formatted.
+ #[test]
+ fn test_path_nested() {
+ let root = Path::Root;
+ let seq = Path::Seq {
+ parent: &root,
+ index: 0,
+ };
+ let map = Path::Map {
+ parent: &seq,
+ key: "key",
+ };
+ let alias = Path::Alias { parent: &map };
+ let unknown = Path::Unknown { parent: &alias };
+ assert_eq!(format!("{}", unknown), "\\[0\\].key..?");
+ }
+
+ /// Test deeply nested paths.
+ ///
+ /// This test checks the formatting of a deeply nested path with multiple levels of sequences and maps.
+ #[test]
+ fn test_deeply_nested_path() {
+ let root = Path::Root;
+ let seq1 = Path::Seq {
+ parent: &root,
+ index: 1,
+ };
+ let map1 = Path::Map {
+ parent: &seq1,
+ key: "first",
+ };
+ let seq2 = Path::Seq {
+ parent: &map1,
+ index: 2,
+ };
+ let map2 = Path::Map {
+ parent: &seq2,
+ key: "second",
+ };
+ let alias = Path::Alias { parent: &map2 };
+ let unknown = Path::Unknown { parent: &alias };
+ assert_eq!(
+ format!("{}", unknown),
+ "\\[1\\].first.\\[2\\].second..?"
+ );
+ }
+
+ /// Test empty key in Path::Map.
+ ///
+ /// This test ensures that a map path with an empty key is correctly handled and formatted.
+ #[test]
+ fn test_path_map_empty_key() {
+ let root = Path::Root;
+ let path = Path::Map {
+ parent: &root,
+ key: "",
+ };
+ assert_eq!(format!("{}", path), "");
+ }
+}
diff --git a/tests/test_path.rs b/tests/test_path.rs
deleted file mode 100644
index fcf2c04c..00000000
--- a/tests/test_path.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#[cfg(test)]
-mod tests {
- use serde_yml::modules::path::Path;
-
- // Tests for Path::Root variant
- #[test]
- fn test_path_root() {
- let path = Path::Root;
- assert_eq!(format!("{}", path), ".");
- }
-
- // Tests for Path::Seq variant
- #[test]
- fn test_path_seq() {
- let root = Path::Root;
- let path = Path::Seq {
- parent: &root,
- index: 42,
- };
- assert_eq!(format!("{}", path), "\\[42\\]");
- }
-
- // Tests for Path::Map variant
- #[test]
- fn test_path_map() {
- let root = Path::Root;
- let path = Path::Map {
- parent: &root,
- key: "key",
- };
- assert_eq!(format!("{}", path), "key");
- }
-
- // Tests for Path::Alias variant
- #[test]
- fn test_path_alias() {
- let root = Path::Root;
- let path = Path::Alias { parent: &root };
- assert_eq!(format!("{}", path), "");
- }
-
- // Tests for Path::Unknown variant
- #[test]
- fn test_path_unknown() {
- let root = Path::Root;
- let path = Path::Unknown { parent: &root };
- assert_eq!(format!("{}", path), "?");
- }
-
- // Tests for nested paths
- #[test]
- fn test_path_nested() {
- let root = Path::Root;
- let seq = Path::Seq {
- parent: &root,
- index: 0,
- };
- let map = Path::Map {
- parent: &seq,
- key: "key",
- };
- let alias = Path::Alias { parent: &map };
- let unknown = Path::Unknown { parent: &alias };
- assert_eq!(format!("{}", unknown), "\\[0\\].key..?");
- }
-}
diff --git a/tests/test_safe_cstr.rs b/tests/test_safe_cstr.rs
deleted file mode 100644
index 17760464..00000000
--- a/tests/test_safe_cstr.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-#[cfg(test)]
-mod tests {
- use serde_yml::libyml::safe_cstr::CStr;
- use std::ptr::NonNull;
-
- #[test]
- fn test_from_ptr() {
- let valid_bytes = b"hello\0";
- let ptr = NonNull::from(valid_bytes).cast();
- let cstr = CStr::from_ptr(ptr);
- assert_eq!(
- cstr.to_bytes(),
- &valid_bytes[..valid_bytes.len() - 1]
- );
- }
-
- #[test]
- fn test_len() {
- let valid_bytes = b"hello\0";
- let cstr = CStr::from_bytes_with_nul(valid_bytes).unwrap();
- assert_eq!(cstr.len(), 5);
-
- let empty_bytes = b"";
- let result = CStr::from_bytes_with_nul(empty_bytes);
- assert!(result.is_err());
- }
-
- #[test]
- fn test_to_bytes() {
- let valid_bytes = b"hello\0";
- let cstr = CStr::from_bytes_with_nul(valid_bytes).unwrap();
- assert_eq!(
- cstr.to_bytes(),
- &valid_bytes[..valid_bytes.len() - 1]
- );
-
- let empty_bytes = b"";
- let result = CStr::from_bytes_with_nul(empty_bytes);
- assert!(result.is_err());
- }
-
- #[test]
- fn test_display() {
- let valid_bytes = b"hello\0";
- let cstr = CStr::from_bytes_with_nul(valid_bytes).unwrap();
- assert_eq!(format!("{}", cstr), "hello");
-
- let invalid_bytes = b"hello\xff\0";
- let cstr = CStr::from_bytes_with_nul(invalid_bytes).unwrap();
- assert_eq!(format!("{}", cstr), "hello�");
- }
-
- #[test]
- fn test_debug() {
- let valid_bytes = b"hello\0";
- let cstr = CStr::from_bytes_with_nul(valid_bytes).unwrap();
- assert_eq!(format!("{:?}", cstr), "\"hello\"");
-
- let invalid_bytes = b"hello\xff\0";
- let cstr = CStr::from_bytes_with_nul(invalid_bytes).unwrap();
- assert_eq!(format!("{:?}", cstr), "\"hello\\xff\"");
- }
-}
diff --git a/tests/value/mod.rs b/tests/value/mod.rs
index eb060588..c9f35328 100644
--- a/tests/value/mod.rs
+++ b/tests/value/mod.rs
@@ -1,6 +1,15 @@
+/// The `test_de` module contains tests for the `Deserialize` trait implementations.
+pub mod test_de;
+
+/// The `test_debug` module contains tests for the `Debug` trait implementations.
+pub mod test_debug;
+
/// The `test_from` module contains tests for the `From` trait implementations.
pub mod test_from;
+/// The `test_index` module contains tests for the `Index` trait implementations.
+pub mod test_index;
+
/// The `test_partial_eq` module contains tests for the `PartialEq` trait implementations.
pub mod test_partial_eq;
diff --git a/tests/value/test_de.rs b/tests/value/test_de.rs
new file mode 100644
index 00000000..47a78917
--- /dev/null
+++ b/tests/value/test_de.rs
@@ -0,0 +1,495 @@
+#[cfg(test)]
+mod tests {
+ use serde::Deserialize;
+ use serde_yml::value::{Tag, TaggedValue, Value};
+
+ /// Test deserialization of a `null` value into `Option<()>`.
+ #[test]
+ fn test_deserialize_null() {
+ let value = Value::Null;
+ let result: Option<()> = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, None);
+ }
+
+ /// Test deserialization of a `bool` value.
+ #[test]
+ fn test_deserialize_bool() {
+ let value = Value::Bool(true);
+ let result: bool = serde_yml::from_value(value).unwrap();
+ assert!(result);
+ }
+
+ /// Test deserialization of an `i64` value.
+ #[test]
+ fn test_deserialize_i64() {
+ let value = Value::Number(42.into());
+ let result: i64 = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, 42);
+ }
+
+ /// Test deserialization of a `u64` value.
+ #[test]
+ fn test_deserialize_u64() {
+ let value = Value::Number(42.into());
+ let result: u64 = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, 42);
+ }
+
+ /// Test deserialization of a `f64` value.
+ #[test]
+ fn test_deserialize_f64() {
+ let value = Value::Number(42.5.into());
+ let result: f64 = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, 42.5);
+ }
+
+ /// Test deserialization of a `String` value.
+ #[test]
+ fn test_deserialize_string() {
+ let value = Value::String("hello".to_string());
+ let result: String = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, "hello");
+ }
+
+ /// Test deserialization of a sequence into a `Vec`.
+ #[test]
+ fn test_deserialize_sequence() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let result: Vec = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, vec![1, 2]);
+ }
+
+ /// Test deserialization of a tagged enum variant.
+ #[test]
+ fn test_deserialize_enum() {
+ let value = Value::Tagged(Box::new(TaggedValue {
+ tag: Tag::new("B"),
+ value: Value::Number(42.into()),
+ }));
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ A,
+ B(i32),
+ C { x: i32 },
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::B(42));
+ }
+
+ /// Test deserialization of a newtype struct.
+ #[test]
+ fn test_deserialize_newtype_struct() {
+ let value = Value::Number(42.into());
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Newtype(i32);
+ let result: Newtype = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Newtype(42));
+ }
+
+ /// Test deserialization of a tuple.
+ #[test]
+ fn test_deserialize_tuple() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let result: (i32, i32) = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, (1, 2));
+ }
+
+ /// Test deserialization of a tuple struct.
+ #[test]
+ fn test_deserialize_tuple_struct() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct TupleStruct(i32, i32);
+ let result: TupleStruct = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, TupleStruct(1, 2));
+ }
+
+ /// Test deserialization of a sequence into a `Vec`.
+ #[test]
+ fn test_deserialize_bytes() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let result: Vec = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, vec![1, 2]);
+ }
+
+ /// Test deserialization of an identifier (string).
+ #[test]
+ fn test_deserialize_identifier() {
+ let value = Value::String("hello".to_string());
+ let result: String = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, "hello");
+ }
+
+ /// Test deserialization of a struct.
+ #[test]
+ fn test_deserialize_struct() {
+ let value = Value::Mapping(
+ vec![
+ (
+ Value::String("x".to_string()),
+ Value::Number(1.into()),
+ ),
+ (
+ Value::String("y".to_string()),
+ Value::Number(2.into()),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ );
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Point {
+ x: i32,
+ y: i32,
+ }
+ let result: Point = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Point { x: 1, y: 2 });
+ }
+
+ /// Test deserialization of a map.
+ #[test]
+ fn test_deserialize_map() {
+ let value = Value::Mapping(
+ vec![
+ (
+ Value::String("x".to_string()),
+ Value::Number(1.into()),
+ ),
+ (
+ Value::String("y".to_string()),
+ Value::Number(2.into()),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ );
+ let result: std::collections::HashMap =
+ serde_yml::from_value(value).unwrap();
+ let mut expected = std::collections::HashMap::new();
+ expected.insert("x".to_string(), 1);
+ expected.insert("y".to_string(), 2);
+ assert_eq!(result, expected);
+ }
+
+ /// Test deserialization of `Option` with `Some` value.
+ #[test]
+ fn test_deserialize_option_some() {
+ let value = Value::Number(42.into());
+ let result: Option = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Some(42));
+ }
+
+ /// Test deserialization of `Option` with `None` value.
+ #[test]
+ fn test_deserialize_option_none() {
+ let value = Value::Null;
+ let result: Option = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, None);
+ }
+
+ /// Test deserialization of a `char` value.
+ #[test]
+ fn test_deserialize_char() {
+ let value = Value::String("a".to_string());
+ let result: char = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, 'a');
+ }
+
+ /// Test deserialization of a unit value.
+ #[test]
+ fn test_deserialize_unit() {
+ let value = Value::Null;
+ let result: () = serde_yml::from_value(value).unwrap();
+ println!(
+ "✅ Deserialized unit value successfully. {:?}",
+ result
+ );
+ }
+ /// Test deserialization of a unit struct.
+ #[test]
+ fn test_deserialize_unit_struct() {
+ let value = Value::Null;
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Unit;
+ let result: Unit = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Unit);
+ }
+ /// Test deserialization of an empty tuple struct.
+ #[test]
+ fn test_deserialize_empty_tuple_struct() {
+ let yaml_str = "---";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Empty;
+
+ let result: Empty = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized Empty tuple struct: {:?}", result);
+ }
+
+ /// Test deserialization of an empty tuple.
+ #[test]
+ fn test_deserialize_empty_tuple() {
+ let yaml_str = "---";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ let result: () = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized Empty tuple: {:?}", result);
+ }
+
+ /// Test deserialization of an empty struct.
+ #[test]
+ fn test_deserialize_empty_struct() {
+ let value = Value::Null;
+ #[derive(Deserialize, PartialEq, Debug)]
+ struct Empty;
+ let result: Empty = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Empty);
+ }
+ /// Test deserialization of a unit variant.
+ #[test]
+ fn test_deserialize_unit_variant() {
+ let value = Value::String("Variant".to_string());
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant,
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant);
+ }
+ /// Test deserialization of a newtype variant.
+ #[test]
+ fn test_deserialize_newtype_variant() {
+ let yaml_str = "!Variant 0";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(i32),
+ }
+
+ let result: E = serde_yml::from_value(value).unwrap();
+ println!("\n✅ Deserialized newtype variant: {:?}", result);
+ }
+
+ /// Test deserialization of a tuple variant.
+ #[test]
+ fn test_deserialize_tuple_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\n- 1\n- 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(i32, i32),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant(1, 2));
+ }
+
+ /// Test deserialization of a struct variant.
+ #[test]
+ fn test_deserialize_struct_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\nx: 1\ny: 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant { x: i32, y: i32 },
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant { x: 1, y: 2 });
+ }
+ /// Test deserialization of a sequence variant.
+ #[test]
+ fn test_deserialize_sequence_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\n- 1\n- 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(Vec),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant(vec![1, 2]));
+ }
+ /// Test deserialization of a map variant.
+ #[test]
+ fn test_deserialize_map_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\nx: 1\ny: 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(std::collections::HashMap),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ let mut expected = std::collections::HashMap::new();
+ expected.insert("x".to_string(), 1);
+ expected.insert("y".to_string(), 2);
+ assert_eq!(result, E::Variant(expected));
+ }
+ /// Test deserialization of a tagged unit variant.
+ #[test]
+ fn test_deserialize_tagged_unit_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant,
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant);
+ }
+ /// Test deserialization of a tagged newtype variant.
+ #[test]
+ fn test_deserialize_tagged_newtype_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant 0\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(i32),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant(0));
+ }
+ /// Test deserialization of a tagged tuple variant.
+ #[test]
+ fn test_deserialize_tagged_tuple_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\n- 1\n- 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(i32, i32),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant(1, 2));
+ }
+ /// Test deserialization of a tagged struct variant.
+ #[test]
+ fn test_deserialize_tagged_struct_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\nx: 1\ny: 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant { x: i32, y: i32 },
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant { x: 1, y: 2 });
+ }
+ /// Test deserialization of a tagged sequence variant.
+ #[test]
+ fn test_deserialize_tagged_sequence_variant() {
+ // YAML representation of the enum variant
+ let yaml_str = "---\n!Variant\n- 1\n- 2\n";
+ let value: Value = serde_yml::from_str(yaml_str).unwrap();
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ Variant(Vec),
+ }
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::Variant(vec![1, 2]));
+ }
+ /// Test deserialization of a `f32` value.
+ #[test]
+ fn test_deserialize_f32() {
+ let value = Value::Number(serde_yml::Number::from(42.5f32));
+ let result: f32 = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, 42.5f32);
+ }
+ /// Test deserialization of a `()` value.
+ #[test]
+ fn test_deserialize_unit_value() {
+ let value = Value::Null;
+ let result: () = serde_yml::from_value(value).unwrap();
+ println!(
+ "✅ Deserialized unit value successfully. {:?}",
+ result
+ );
+ }
+
+ /// Test deserialization of a byte array.
+ #[test]
+ fn test_deserialize_byte_array() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ Value::Number(3.into()),
+ ]);
+ let result: [u8; 3] = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, [1, 2, 3]);
+ }
+
+ /// Test deserialization of an optional byte array.
+ #[test]
+ fn test_deserialize_optional_byte_array() {
+ let value = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ Value::Number(3.into()),
+ ]);
+ let result: Option<[u8; 3]> =
+ serde_yml::from_value(value).unwrap();
+ assert_eq!(result, Some([1, 2, 3]));
+ }
+
+ /// Test deserialization of a unit struct variant.
+ #[test]
+ fn test_deserialize_unit_struct_variant() {
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ V,
+ }
+ let value = Value::String("V".to_string());
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::V);
+ }
+
+ /// Test deserialization of a newtype struct variant.
+ #[test]
+ fn test_deserialize_newtype_struct_variant() {
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ V(i32),
+ }
+ let value = Value::Tagged(Box::new(TaggedValue {
+ tag: Tag::new("V"),
+ value: Value::Number(42.into()),
+ }));
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::V(42));
+ }
+
+ /// Test deserialization of a tuple struct variant.
+ #[test]
+ fn test_deserialize_tuple_struct_variant() {
+ #[derive(Deserialize, PartialEq, Debug)]
+ enum E {
+ V(i32, i32),
+ }
+ let value = Value::Tagged(Box::new(TaggedValue {
+ tag: Tag::new("V"),
+ value: Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]),
+ }));
+ let result: E = serde_yml::from_value(value).unwrap();
+ assert_eq!(result, E::V(1, 2));
+ }
+}
diff --git a/tests/test_debug.rs b/tests/value/test_debug.rs
similarity index 100%
rename from tests/test_debug.rs
rename to tests/value/test_debug.rs
diff --git a/tests/value/test_index.rs b/tests/value/test_index.rs
new file mode 100644
index 00000000..51fb5c74
--- /dev/null
+++ b/tests/value/test_index.rs
@@ -0,0 +1,728 @@
+#[cfg(test)]
+mod tests {
+ use serde_yml::value::Index;
+ use serde_yml::Value;
+
+ /// Test for `index_into` method of `usize` implementation.
+ /// This test verifies that `index_into` correctly indexes into a `Value::Sequence`.
+ #[test]
+ fn test_usize_index_into_sequence() {
+ let sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 1;
+ assert_eq!(
+ index.index_into(&sequence),
+ Some(&Value::Number(2.into()))
+ );
+ }
+
+ /// Test for `index_into` method of `usize` implementation with a `Value::Mapping`.
+ /// This test verifies that `index_into` correctly indexes into a `Value::Mapping` with a numeric key.
+ #[test]
+ fn test_usize_index_into_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::Number(1.into()),
+ Value::String("one".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = 1;
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("one".into()))
+ );
+ }
+
+ /// Test for `index_into` method of `usize` implementation with an out-of-bounds index in `Value::Sequence`.
+ /// This test verifies that `index_into` returns None for an out-of-bounds index.
+ #[test]
+ fn test_usize_index_into_sequence_out_of_bounds() {
+ let sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 3;
+ assert_eq!(index.index_into(&sequence), None);
+ }
+
+ /// Test for `index_into` method of `usize` implementation with a non-numeric key in `Value::Mapping`.
+ /// This test verifies that `index_into` returns None for a non-numeric key.
+ #[test]
+ fn test_usize_index_into_mapping_non_numeric_key() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = 1;
+ assert_eq!(index.index_into(&value), None);
+ }
+
+ /// Test for `index_into_mut` method of `usize` implementation.
+ /// This test verifies that `index_into_mut` correctly indexes into a mutable `Value::Sequence`.
+ #[test]
+ fn test_usize_index_into_mut_sequence() {
+ let mut sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 1;
+ if let Some(value) = index.index_into_mut(&mut sequence) {
+ *value = Value::Number(3.into());
+ }
+ assert_eq!(
+ sequence,
+ Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(3.into())
+ ])
+ );
+ }
+
+ /// Test for `index_into_mut` method of `usize` implementation with a `Value::Mapping`.
+ /// This test verifies that `index_into_mut` correctly indexes into a mutable `Value::Mapping` with a numeric key.
+ #[test]
+ fn test_usize_index_into_mut_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::Number(1.into()),
+ Value::String("one".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = 1;
+ if let Some(value) = index.index_into_mut(&mut value) {
+ *value = Value::String("two".into());
+ }
+ let mut expected_mapping = serde_yml::Mapping::new();
+ expected_mapping.insert(
+ Value::Number(1.into()),
+ Value::String("two".into()),
+ );
+ assert_eq!(value, Value::Mapping(expected_mapping));
+ }
+
+ /// Test for `index_into_mut` method of `usize` implementation with an out-of-bounds index in `Value::Sequence`.
+ /// This test verifies that `index_into_mut` returns None for an out-of-bounds index.
+ #[test]
+ fn test_usize_index_into_mut_sequence_out_of_bounds() {
+ let mut sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = 3;
+ assert_eq!(index.index_into_mut(&mut sequence), None);
+ }
+
+ /// Test for `index_into_mut` method of `usize` implementation with a non-numeric key in `Value::Mapping`.
+ /// This test verifies that `index_into_mut` returns None for a non-numeric key.
+ #[test]
+ fn test_usize_index_into_mut_mapping_non_numeric_key() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = 1;
+ assert_eq!(index.index_into_mut(&mut value), None);
+ }
+
+ /// Test for `index_or_insert` method of `usize` implementation.
+ /// This test verifies that `index_or_insert` correctly indexes or inserts into a `Value::Sequence`.
+ #[test]
+ fn test_usize_index_or_insert_sequence() {
+ let mut sequence =
+ Value::Sequence(vec![Value::Number(1.into())]);
+ let index = 1;
+
+ // Extend the sequence to ensure the index is in bounds
+ if index >= sequence.as_sequence().unwrap().len() {
+ for _ in sequence.as_sequence().unwrap().len()..=index {
+ sequence.as_sequence_mut().unwrap().push(Value::Null);
+ }
+ }
+
+ index
+ .index_or_insert(&mut sequence)
+ .clone_from(&Value::Number(2.into()));
+ assert_eq!(
+ sequence,
+ Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into())
+ ])
+ );
+ }
+
+ /// Test for `index_or_insert` method of `usize` implementation with a `Value::Mapping`.
+ /// This test verifies that `index_or_insert` correctly indexes or inserts into a `Value::Mapping` with a numeric key.
+ #[test]
+ fn test_usize_index_or_insert_mapping() {
+ let mapping = serde_yml::Mapping::new();
+ let mut value = Value::Mapping(mapping);
+ let index = 1;
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("one".into()));
+ let mut expected_mapping = serde_yml::Mapping::new();
+ expected_mapping.insert(
+ Value::Number(1.into()),
+ Value::String("one".into()),
+ );
+ assert_eq!(value, Value::Mapping(expected_mapping));
+ }
+
+ /// Test for `index_or_insert` method of `usize` implementation with an out-of-bounds index in `Value::Sequence`.
+ /// This test verifies that `index_or_insert` inserts a default value for an out-of-bounds index without panicking.
+ #[test]
+ fn test_usize_index_or_insert_sequence_out_of_bounds() {
+ let mut sequence =
+ Value::Sequence(vec![Value::Number(1.into())]);
+ let index = 1;
+ if index >= sequence.as_sequence().unwrap().len() {
+ for _ in sequence.as_sequence().unwrap().len()..=index {
+ sequence.as_sequence_mut().unwrap().push(Value::Null);
+ }
+ }
+ index
+ .index_or_insert(&mut sequence)
+ .clone_from(&Value::Number(2.into()));
+ assert_eq!(
+ sequence,
+ Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into())
+ ])
+ );
+ }
+
+ /// Test for `index_into` method of `usize` implementation with a `Value` other than `Sequence` or `Mapping`.
+ /// This test verifies that `index_into` returns None for a non-indexable `Value`.
+ #[test]
+ fn test_usize_index_into_non_indexable() {
+ let value = Value::String("hello".into());
+ let index = 1;
+ assert_eq!(index.index_into(&value), None);
+ }
+
+ /// Test for `index_into_mut` method of `usize` implementation with a `Value` other than `Sequence` or `Mapping`.
+ /// This test verifies that `index_into_mut` returns None for a non-indexable `Value`.
+ #[test]
+ fn test_usize_index_into_mut_non_indexable() {
+ let mut value = Value::String("hello".into());
+ let index = 1;
+ assert_eq!(index.index_into_mut(&mut value), None);
+ }
+
+ /// Test for `index_or_insert` method of `usize` implementation with a `Value` other than `Sequence` or `Mapping`.
+ /// This test verifies that `index_or_insert` panics for a non-indexable `Value`.
+ #[test]
+ #[should_panic(expected = "cannot access index 1 of YAML string")]
+ fn test_usize_index_or_insert_non_indexable() {
+ let mut value = Value::String("hello".into());
+ let index = 1;
+ index.index_or_insert(&mut value);
+ }
+
+ /// Test for `index_or_insert` method of `usize` implementation with a `Value::Null`.
+ /// This test verifies that `index_or_insert` panics for a `Value::Null`.
+ #[test]
+ #[should_panic(expected = "cannot access index 1 of YAML null")]
+ fn test_usize_index_or_insert_null() {
+ let mut value = Value::Null;
+ let index = 1;
+ index.index_or_insert(&mut value);
+ }
+
+ /// Test `index_into` with a `Value::Mapping`.
+ #[test]
+ fn test_value_index_into_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = Value::String("key".into());
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_value_index_into_non_mapping() {
+ let value = Value::String("hello".into());
+ let index = Value::String("key".into());
+ assert_eq!(index.index_into(&value), None);
+ }
+
+ /// Test `index_into_mut` with a `Value::Mapping`.
+ #[test]
+ fn test_value_index_into_mut_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = Value::String("key".into());
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_value_index_into_mut_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = Value::String("key".into());
+ assert_eq!(index.index_into_mut(&mut value), None);
+ }
+
+ /// Test `index_or_insert` with a `Value::Mapping`.
+ #[test]
+ fn test_value_index_or_insert_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = Value::String("new_key".into());
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ assert_eq!(
+ value.get(&Value::String("new_key".into())),
+ Some(&Value::String("new_value".into()))
+ );
+ }
+
+ /// Test `index_or_insert` with a `Value` other than `Mapping`.
+ #[test]
+ #[should_panic(
+ expected = "cannot access key String(\"key\") in YAML string"
+ )]
+ fn test_value_index_or_insert_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = Value::String("key".into());
+ index.index_or_insert(&mut value);
+ }
+
+ // Tests for the `str` implementation of `Index`
+
+ /// Test `index_into` with a `Value::Mapping`.
+ #[test]
+ fn test_str_index_into_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = "key";
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_str_index_into_non_mapping() {
+ let value = Value::String("hello".into());
+ let index = "key";
+ assert_eq!(index.index_into(&value), None);
+ }
+
+ /// Test `index_into_mut` with a `Value::Mapping`.
+ #[test]
+ fn test_str_index_into_mut_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = "key";
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_str_index_into_mut_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = "key";
+ assert_eq!(index.index_into_mut(&mut value), None);
+ }
+
+ /// Test `index_or_insert` with a `Value::Mapping`.
+ #[test]
+ fn test_str_index_or_insert_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = "new_key";
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ assert_eq!(
+ value.get(&Value::String("new_key".into())),
+ Some(&Value::String("new_value".into()))
+ );
+ }
+
+ /// Test `index_or_insert` with a `Value` other than `Mapping`.
+ #[test]
+ #[should_panic(
+ expected = "cannot access key \"key\" in YAML string"
+ )]
+ fn test_str_index_or_insert_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = "key";
+ index.index_or_insert(&mut value);
+ }
+
+ // Tests for the `String` implementation of `Index`
+
+ /// Test `index_into` with a `Value::Mapping`.
+ #[test]
+ fn test_string_index_into_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = String::from("key");
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_string_index_into_non_mapping() {
+ let value = Value::String("hello".into());
+ let index = String::from("key");
+ assert_eq!(index.index_into(&value), None);
+ }
+
+ /// Test `index_into_mut` with a `Value::Mapping`.
+ #[test]
+ fn test_string_index_into_mut_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = String::from("key");
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a `Value` other than `Mapping`.
+ #[test]
+ fn test_string_index_into_mut_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = String::from("key");
+ assert_eq!(index.index_into_mut(&mut value), None);
+ }
+
+ /// Test `index_or_insert` with a `Value::Mapping`.
+ #[test]
+ fn test_string_index_or_insert_mapping() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = String::from("new_key");
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ assert_eq!(
+ value.get(&Value::String("new_key".into())),
+ Some(&Value::String("new_value".into()))
+ );
+ }
+
+ /// Test `index_or_insert` with a `Value` other than `Mapping`.
+ #[test]
+ #[should_panic(
+ expected = "cannot access key \"key\" in YAML string"
+ )]
+ fn test_string_index_or_insert_non_mapping() {
+ let mut value = Value::String("hello".into());
+ let index = String::from("key");
+ index.index_or_insert(&mut value);
+ }
+
+ // Tests for the reference implementation of `Index`
+
+ /// Test `index_into` with a reference to `usize`.
+ #[test]
+ fn test_ref_usize_index_into() {
+ let sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = &1;
+ assert_eq!(
+ index.index_into(&sequence),
+ Some(&Value::Number(2.into()))
+ );
+ }
+
+ /// Test `index_into` with a reference to `Value`.
+ #[test]
+ fn test_ref_value_index_into() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = &Value::String("key".into());
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into` with a reference to `str`.
+ #[test]
+ fn test_ref_str_index_into() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = &"key";
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into` with a reference to `String`.
+ #[test]
+ fn test_ref_string_index_into() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ let index = &String::from("key");
+ assert_eq!(
+ index.index_into(&value),
+ Some(&Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a reference to `usize`.
+ #[test]
+ fn test_ref_usize_index_into_mut() {
+ let mut sequence = Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into()),
+ ]);
+ let index = &1;
+ assert_eq!(
+ index.index_into_mut(&mut sequence),
+ Some(&mut Value::Number(2.into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a reference to `Value`.
+ #[test]
+ fn test_ref_value_index_into_mut() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = &Value::String("key".into());
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a reference to `str`.
+ #[test]
+ fn test_ref_str_index_into_mut() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = &"key";
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_into_mut` with a reference to `String`.
+ #[test]
+ fn test_ref_string_index_into_mut() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = &String::from("key");
+ assert_eq!(
+ index.index_into_mut(&mut value),
+ Some(&mut Value::String("value".into()))
+ );
+ }
+
+ /// Test `index_or_insert` with a reference to `usize`.
+ #[test]
+ fn test_ref_usize_index_or_insert() {
+ let mut sequence =
+ Value::Sequence(vec![Value::Number(1.into())]);
+ let index = &1;
+
+ // Extend the sequence to ensure the index is in bounds
+ if *index >= sequence.as_sequence().unwrap().len() {
+ for _ in sequence.as_sequence().unwrap().len()..=*index {
+ sequence.as_sequence_mut().unwrap().push(Value::Null);
+ }
+ }
+
+ index
+ .index_or_insert(&mut sequence)
+ .clone_from(&Value::Number(2.into()));
+ assert_eq!(
+ sequence,
+ Value::Sequence(vec![
+ Value::Number(1.into()),
+ Value::Number(2.into())
+ ])
+ );
+ }
+
+ /// Test `index_or_insert` with a reference to `Value`.
+ #[test]
+ fn test_ref_value_index_or_insert() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = &Value::String("new_key".into());
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ assert_eq!(
+ value.get(&Value::String("new_key".into())),
+ Some(&Value::String("new_value".into()))
+ );
+ }
+
+ /// Test `index_or_insert` with a reference to `str`.
+ #[test]
+ fn test_ref_str_index_or_insert() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ let index = &"new_key";
+ index
+ .index_or_insert(&mut value)
+ .clone_from(&Value::String("new_value".into()));
+ assert_eq!(
+ value.get(&Value::String("new_key".into())),
+ Some(&Value::String("new_value".into()))
+ );
+ }
+
+ // Tests for the `ops::Index` implementation
+
+ /// Test indexing with an invalid index.
+ #[test]
+ fn test_index_invalid_index() {
+ let value = Value::Sequence(vec![Value::Number(1.into())]);
+ assert_eq!(value[2], Value::Null);
+ }
+
+ /// Test indexing with an invalid key.
+ #[test]
+ fn test_index_invalid_key() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let value = Value::Mapping(mapping);
+ assert_eq!(value["invalid"], Value::Null);
+ }
+
+ // Tests for the `ops::IndexMut` implementation
+
+ /// Test mutating with an invalid index.
+ #[test]
+ #[should_panic(
+ expected = "cannot access index 2 of YAML sequence of length 1"
+ )]
+ fn test_index_mut_invalid_index() {
+ let mut value = Value::Sequence(vec![Value::Number(1.into())]);
+ value[2] = Value::Number(2.into());
+ }
+
+ /// Test mutating with an invalid key.
+ #[test]
+ fn test_index_mut_invalid_key() {
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ let mut value = Value::Mapping(mapping);
+ value["invalid"] = Value::String("new_value".into());
+
+ assert_eq!(
+ value,
+ Value::Mapping({
+ let mut mapping = serde_yml::Mapping::new();
+ mapping.insert(
+ Value::String("key".into()),
+ Value::String("value".into()),
+ );
+ mapping.insert(
+ Value::String("invalid".into()),
+ Value::String("new_value".into()),
+ );
+ mapping
+ })
+ );
+ }
+}