serde_yml-0.0.12/Cargo.lock0000644000000071330000000000100110560ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "indexmap" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "indoc" version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libyml" version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" dependencies = [ "anyhow", "version_check", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_yml" version = "0.0.12" dependencies = [ "indexmap", "indoc", "itoa", "libyml", "memchr", "ryu", "serde", "serde_derive", "version_check", ] [[package]] name = "syn" version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" serde_yml-0.0.12/Cargo.toml0000644000000117200000000000100110760ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56.0" name = "serde_yml" version = "0.0.12" authors = ["Serde YML Contributors"] build = "build.rs" exclude = [ "/.git/*", "/.github/*", "/.gitignore", "/.vscode/*", ] include = [ "/CONTRIBUTING.md", "/LICENSE-APACHE", "/LICENSE-MIT", "/benches/**", "/build.rs", "/Cargo.toml", "/examples/**", "/README.md", "/src/**", "/tests/**", ] autobins = false autoexamples = false autotests = false autobenches = false description = """ A robust Rust library that simplifies the serialization and deserialization of Rust data structures to and from YAML format using the widely-used Serde framework. """ homepage = "https://serdeyml.com" documentation = "https://docs.rs/serde_yml/" readme = "README.md" keywords = [ "yaml", "serde", "serialization", ] categories = [ "encoding", "parser-implementations", ] license = "MIT OR Apache-2.0" repository = "https://github.com/sebastienrousseau/serde_yml" [package.metadata.clippy] warn-lints = [ "clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery", ] [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--generate-link-to-definition", "--cfg", "docsrs", "--document-private-items", "--display-warnings", ] targets = ["x86_64-unknown-linux-gnu"] [profile.dev] opt-level = 0 lto = false codegen-units = 256 debug = 2 debug-assertions = true rpath = false panic = "unwind" overflow-checks = true incremental = true strip = false [profile.release] opt-level = "s" lto = true codegen-units = 1 debug = 0 debug-assertions = false rpath = false panic = "abort" overflow-checks = false incremental = false strip = "symbols" [profile.test] opt-level = 0 lto = false codegen-units = 256 debug = 2 debug-assertions = true rpath = false overflow-checks = true incremental = true strip = false [lib] name = "serde_yml" crate-type = ["lib"] path = "src/lib.rs" doc-scrape-examples = false required-features = [] [[example]] name = "example" path = "examples/example.rs" [[test]] name = "mod" path = "tests/mod.rs" [[test]] name = "test_anchors_and_aliases" path = "tests/test_anchors_and_aliases.rs" [[test]] name = "test_de" path = "tests/test_de.rs" [[test]] name = "test_error" path = "tests/test_error.rs" [[test]] name = "test_lib" path = "tests/test_lib.rs" [[test]] name = "test_loader" path = "tests/test_loader.rs" [[test]] name = "test_mapping" path = "tests/test_mapping.rs" [[test]] name = "test_number" path = "tests/test_number.rs" [[test]] name = "test_ser" path = "tests/test_ser.rs" [[test]] name = "test_serde" path = "tests/test_serde.rs" [[test]] name = "test_tagged" path = "tests/test_tagged.rs" [[test]] name = "test_value" path = "tests/test_value.rs" [[test]] name = "test_with" path = "tests/test_with.rs" [dependencies.indexmap] version = "2.2.4" [dependencies.itoa] version = "1.0" [dependencies.libyml] version = "0.0.5" [dependencies.memchr] version = "2" default-features = false [dependencies.ryu] version = "1.0" [dependencies.serde] version = "1.0.204" [dev-dependencies.indoc] version = "2.0.5" [dev-dependencies.serde] version = "1.0.204" features = ["derive"] [dev-dependencies.serde_derive] version = "1.0.204" [build-dependencies.version_check] version = "0.9.4" [features] default = [] [lints.rust] bare_trait_objects = "allow" dead_code = "deny" deprecated_in_future = "deny" elided_lifetimes_in_paths = "allow" ellipsis_inclusive_range_patterns = "deny" explicit_outlives_requirements = "deny" macro_use_extern_crate = "deny" meta_variable_misuse = "deny" missing_copy_implementations = "warn" missing_debug_implementations = "forbid" missing_docs = "warn" missing_fragment_specifier = "deny" non_ascii_idents = "forbid" non_camel_case_types = "allow" non_upper_case_globals = "allow" noop_method_call = "deny" single_use_lifetimes = "deny" trivial_bounds = "allow" trivial_casts = "deny" trivial_numeric_casts = "deny" unreachable_pub = "forbid" unsafe_code = "allow" unstable_features = "warn" unused_extern_crates = "warn" unused_features = "deny" unused_import_braces = "deny" unused_labels = "deny" unused_lifetimes = "deny" unused_macro_rules = "deny" unused_qualifications = "deny" variant_size_differences = "deny" [lints.rust.future_incompatible] level = "deny" priority = -1 [lints.rust.keyword_idents] level = "deny" priority = -1 [lints.rust.rust_2018_idioms] level = "deny" priority = -1 [lints.rust.rust_2021_compatibility] level = "deny" priority = -1 [lints.rust.unused] level = "deny" priority = -1 serde_yml-0.0.12/Cargo.toml.orig000064400000000000000000000077061046102023000145700ustar 00000000000000[package] authors = ["Serde YML Contributors"] categories = ["encoding", "parser-implementations"] description = """ A robust Rust library that simplifies the serialization and deserialization of Rust data structures to and from YAML format using the widely-used Serde framework. """ documentation = "https://docs.rs/serde_yml/" edition = "2021" exclude = ["/.git/*", "/.github/*", "/.gitignore", "/.vscode/*"] homepage = "https://serdeyml.com" keywords = ["yaml", "serde", "serialization"] license = "MIT OR Apache-2.0" name = "serde_yml" readme = "README.md" repository = "https://github.com/sebastienrousseau/serde_yml" rust-version = "1.56.0" version = "0.0.12" include = [ "/CONTRIBUTING.md", "/LICENSE-APACHE", "/LICENSE-MIT", "/benches/**", "/build.rs", "/Cargo.toml", "/examples/**", "/README.md", "/src/**", "/tests/**", ] # [[bench]] # name = "benchmark" # harness = false # path = "benches/criterion.rs" # [profile.bench] # debug = true [dependencies] indexmap = "2.2.4" itoa = "1.0" libyml = "0.0.5" memchr = { version = "2", default-features = false } ryu = "1.0" serde = { version = "1.0.204" } [build-dependencies] # Dependencies for build scripts. version_check = "0.9.4" # Check the Rust version used to compile the package. [dev-dependencies] indoc = "2.0.5" serde = { version = "1.0.204", features = ["derive"] } serde_derive = "1.0.204" [features] default = [] [lib] crate-type = ["lib"] doc-scrape-examples = false name = "serde_yml" path = "src/lib.rs" required-features = [] [package.metadata.docs.rs] # Specify arguments for rustdoc to enhance documentation quality. rustdoc-args = [ "--generate-link-to-definition", "--cfg", "docsrs", "--document-private-items", "--display-warnings" ] # Build docs with all crate features enabled to cover the entire API. all-features = true # Target platform for the docs, ensuring compatibility with common Linux servers. targets = ["x86_64-unknown-linux-gnu"] # Linting config [lints.rust] ## Warn # box_pointers = "warn" missing_copy_implementations = "warn" missing_docs = "warn" unstable_features = "warn" # unused_crate_dependencies = "warn" unused_extern_crates = "warn" # unused_results = "warn" ## Allow bare_trait_objects = "allow" elided_lifetimes_in_paths = "allow" non_camel_case_types = "allow" non_upper_case_globals = "allow" trivial_bounds = "allow" unsafe_code = "allow" ## Forbid # missing_docs = "warn" missing_debug_implementations = "forbid" non_ascii_idents = "forbid" unreachable_pub = "forbid" ## Deny dead_code = "deny" deprecated_in_future = "deny" ellipsis_inclusive_range_patterns = "deny" explicit_outlives_requirements = "deny" future_incompatible = { level = "deny", priority = -1 } keyword_idents = { level = "deny", priority = -1 } macro_use_extern_crate = "deny" meta_variable_misuse = "deny" missing_fragment_specifier = "deny" noop_method_call = "deny" rust_2018_idioms = { level = "deny", priority = -1 } rust_2021_compatibility = { level = "deny", priority = -1 } single_use_lifetimes = "deny" trivial_casts = "deny" trivial_numeric_casts = "deny" unused = { level = "deny", priority = -1 } unused_features = "deny" unused_import_braces = "deny" unused_labels = "deny" unused_lifetimes = "deny" unused_macro_rules = "deny" unused_qualifications = "deny" variant_size_differences = "deny" [package.metadata.clippy] warn-lints = [ "clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery", ] [profile.dev] codegen-units = 256 debug = true debug-assertions = true incremental = true lto = false opt-level = 0 overflow-checks = true panic = 'unwind' rpath = false strip = false [profile.release] codegen-units = 1 debug = false debug-assertions = false incremental = false lto = true opt-level = "s" overflow-checks = false panic = "abort" rpath = false strip = "symbols" [profile.test] codegen-units = 256 debug = true debug-assertions = true incremental = true lto = false opt-level = 0 overflow-checks = true rpath = false strip = false serde_yml-0.0.12/LICENSE-APACHE000064400000000000000000000227731046102023000136260ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS serde_yml-0.0.12/LICENSE-MIT000064400000000000000000000017771046102023000133370ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serde_yml-0.0.12/README.md000064400000000000000000000446031046102023000131550ustar 00000000000000 Serde YML logo # Serde YML (a fork of Serde YAML) [![Made With Love][made-with-rust]][11] [![Crates.io][crates-badge]][07] [![lib.rs][libs-badge]][12] [![Docs.rs][docs-badge]][08] [![Codecov][codecov-badge]][09] [![Build Status][build-badge]][10] [![GitHub][github-badge]][06] [Serde YML][00] is a Rust library for using the [Serde][01] serialization framework with data in [YAML][05] file format. ## Features - Serialization and deserialization of Rust data structures to/from YAML format - Support for custom structs and enums using Serde's derive macros - Handling of YAML's `!tag` syntax for representing enum variants - Direct access to YAML values through the `Value` type and related types like `Mapping` and `Sequence` - Comprehensive error handling with `Error`, `Location`, and `Result` types - Serialization to YAML using `to_string` and `to_writer` functions - Deserialization from YAML using `from_str`, `from_slice`, and `from_reader` functions - Customizable serialization and deserialization behavior using Serde's `#[serde(with = ...)]` attribute - Support for serializing/deserializing enums using a YAML map with a single key-value pair through the `singleton_map` module - Recursive application of `singleton_map` serialization/deserialization to all enums within a data structure using the `singleton_map_recursive` module - Serialization and deserialization of optional enum fields using the `singleton_map_optional` module - Handling of nested enum structures with optional inner enums using the `singleton_map_recursive` module - Customization of serialization and deserialization logic for enums using the `singleton_map_with` module and custom helper functions ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] serde = "1.0" serde_yml = "0.0.12" ``` ## Usage Here's a quick example on how to use Serde YML to serialize and deserialize a struct to and from YAML: ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Point { x: f64, y: f64, } fn main() -> Result<(), serde_yml::Error> { let point = Point { x: 1.0, y: 2.0 }; // Serialize to YAML let yaml = serde_yml::to_string(&point)?; assert_eq!(yaml, "x: 1.0\ny: 2.0\n"); // Deserialize from YAML let deserialized_point: Point = serde_yml::from_str(&yaml)?; assert_eq!(point, deserialized_point); Ok(()) } ``` ## Documentation For full API documentation, please visit [https://doc.libyml.com/serde-yaml/][04] or [https://docs.rs/serde-yaml][08]. ## Rust Version Compatibility Compiler support: requires rustc 1.56.0+ ## Examples Serde YML provides a set of comprehensive examples. You can find them in the `examples` directory of the project. To run the examples, clone the repository and execute the following command in your terminal from the project: ```shell cargo run --example example ``` The examples cover various scenarios, including serializing and deserializing structs, enums, optional fields, custom structs, and more. Here are a few notable examples: ### Serializing and Deserializing Structs ```rust use serde::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Point { x: f64, y: f64, } fn main() -> Result<(), serde_yml::Error> { let point = Point { x: 1.0, y: 2.0 }; // Serialize to YAML let yaml = serde_yml::to_string(&point)?; assert_eq!(yaml, "x: 1.0\ny: 2.0\n"); // Deserialize from YAML let deserialized_point: Point = serde_yml::from_str(&yaml)?; assert_eq!(point, deserialized_point); Ok(()) } ``` This example demonstrates how to serialize and deserialize a simple struct `Point` to and from YAML using the `serde_yml` crate. ### Serializing and Deserializing Enums ```rust use serde::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Shape { Rectangle { width: u32, height: u32 }, Circle { radius: f64 }, Triangle { base: u32, height: u32 }, } fn main() -> Result<(), serde_yml::Error> { let shapes = vec![ Shape::Rectangle { width: 10, height: 20 }, Shape::Circle { radius: 5.0 }, Shape::Triangle { base: 8, height: 12 }, ]; // Serialize to YAML let yaml = serde_yml::to_string(&shapes)?; println!("Serialized YAML:\n{}", yaml); // Deserialize from YAML let deserialized_shapes: Vec = serde_yml::from_str(&yaml)?; assert_eq!(shapes, deserialized_shapes); Ok(()) } ``` This example demonstrates how to serialize and deserialize an enum `Shape` (with struct variants) to and from YAML using the `serde_yml` crate. ### Serializing and Deserializing Optional Fields ```rust use serde::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct User { name: String, age: Option, #[serde(default)] is_active: bool, } fn main() -> Result<(), serde_yml::Error> { let user = User { name: "John".to_string(), age: Some(30), is_active: true, }; // Serialize to YAML let yaml = serde_yml::to_string(&user)?; println!("Serialized YAML:\n{}", yaml); // Deserialize from YAML let deserialized_user: User = serde_yml::from_str(&yaml)?; assert_eq!(user, deserialized_user); Ok(()) } ``` This example demonstrates how to serialize and deserialize a struct `User` with an optional field `age` to and from YAML using the `serde_yml` crate. ### Serializing and Deserializing a HashMap ```rust use std::collections::HashMap; use serde_yml; fn main() -> Result<(), serde_yml::Error> { let mut map = HashMap::new(); map.insert("name".to_string(), "John".to_string()); map.insert("age".to_string(), "30".to_string()); let yaml = serde_yml::to_string(&map)?; println!("Serialized YAML: {}", yaml); let deserialized_map: HashMap = serde_yml::from_str(&yaml)?; println!("Deserialized map: {:?}", deserialized_map); Ok(()) } ``` This example demonstrates how to serialize and deserialize a `HashMap` to and from YAML using the `serde_yml` crate. ### Serializing and Deserializing Custom Structs ```rust use serde::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, Debug)] struct Person { name: String, age: u32, city: String, } fn main() -> Result<(), serde_yml::Error> { let person = Person { name: "Alice".to_string(), age: 25, city: "New York".to_string(), }; let yaml = serde_yml::to_string(&person)?; println!("Serialized YAML: {}", yaml); let deserialized_person: Person = serde_yml::from_str(&yaml)?; println!("Deserialized person: {:?}", deserialized_person); Ok(()) } ``` This example demonstrates how to serialize and deserialize a custom struct `Person` to and from YAML using the `serde_yml` crate. ### Using Serde derive It can also be used with Serde's derive macros to handle structs and enums defined in your program. Structs serialize in the obvious way: ```rust use serde_derive::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Point { x: f64, y: f64, } fn main() -> Result<(), serde_yml::Error> { let point = Point { x: 1.0, y: 2.0 }; let yaml = serde_yml::to_string(&point)?; assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); let deserialized_point: Point = serde_yml::from_str(&yaml)?; assert_eq!(point, deserialized_point); Ok(()) } ``` Enums serialize using YAML's `!tag` syntax to identify the variant name. ```rust use serde_derive::{Serialize, Deserialize}; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Enum { Unit, Newtype(usize), Tuple(usize, usize, usize), Struct { x: f64, y: f64 }, } fn main() -> Result<(), serde_yml::Error> { let yaml = " - !Newtype 1 - !Tuple [0, 0, 0] - !Struct {x: 1.0, y: 2.0} "; let values: Vec = serde_yml::from_str(yaml).unwrap(); assert_eq!(values[0], Enum::Newtype(1)); assert_eq!(values[1], Enum::Tuple(0, 0, 0)); assert_eq!(values[2], Enum::Struct { x: 1.0, y: 2.0 }); // The last two in YAML's block style instead: let yaml = " - !Tuple - 0 - 0 - 0 - !Struct x: 1.0 'y': 2.0 "; let values: Vec = serde_yml::from_str(yaml).unwrap(); assert_eq!(values[0], Enum::Tuple(0, 0, 0)); assert_eq!(values[1], Enum::Struct { x: 1.0, y: 2.0 }); // Variants with no data can be written using !Tag or just the string name. let yaml = " - Unit # serialization produces this one - !Unit "; let values: Vec = serde_yml::from_str(yaml).unwrap(); assert_eq!(values[0], Enum::Unit); assert_eq!(values[1], Enum::Unit); Ok(()) } ``` This example demonstrates how to use Serde's derive macros to automatically implement the `Serialize` and `Deserialize` traits for a struct `Point`, and then serialize and deserialize it to and from YAML using the `serde_yml` crate. ### Serializing and Deserializing Enums with Custom Serialization and Deserialization ```rust use serde::{Deserialize, Serialize}; use serde::de::{self, Deserializer, MapAccess, Visitor}; use serde::ser::{SerializeMap, Serializer}; use std::fmt; use serde_yml; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(PartialEq, Debug)] struct MyStruct { field: MyEnum, } // Include custom Serialize and Deserialize implementations for MyStruct here // ... fn main() -> Result<(), serde_yml::Error> { let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use custom `Serialize` and `Deserialize` implementations for a struct containing an enum field, and how to leverage `serde_yml` to serialize and deserialize the struct to and from YAML. ### Serializing and Deserializing Optional Enums ```rust use serde::{Deserialize, Serialize}; use serde_yml; use serde_yml::with::singleton_map_optional; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OptionalEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct OptionalStruct { #[serde(with = "singleton_map_optional")] field: Option, } fn main() -> Result<(), serde_yml::Error> { let input = OptionalStruct { field: Some(OptionalEnum::Variant2 { field: 42 }), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: OptionalStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use the `singleton_map_optional` attribute to serialize and deserialize an `Option` field as a single YAML mapping entry with the key being the enum variant name. ### Serializing and Deserializing Nested Enums ```rust use serde::{Deserialize, Serialize}; use serde_yml; use serde_yml::with::singleton_map_recursive; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant1(String), Variant2(Option), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Inner1(i32), Inner2(i32), } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NestedStruct { #[serde(with = "singleton_map_recursive")] field: NestedEnum, } fn main() -> Result<(), serde_yml::Error> { let input = NestedStruct { field: NestedEnum::Variant2(Some(InnerEnum::Inner2(42))), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: NestedStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use the `singleton_map_recursive` attribute to serialize and deserialize a nested enum structure where one of the enum variants contains an optional inner enum. ### Serializing and Deserializing Enums with `singleton_map_recursive` ```rust use serde::{Deserialize, Serialize}; use serde_yml; use serde_yml::with::singleton_map_recursive; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde(with = "singleton_map_recursive")] field: MyEnum, } fn main() -> Result<(), serde_yml::Error> { let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use the `singleton_map_recursive` attribute to serialize and deserialize an enum field as a single YAML mapping entry with the key being the enum variant name. ### Serializing and Deserializing Enums with `singleton_map_with` and Custom Serialization ```rust use serde::{Deserialize, Serialize}; use serde_yml; use serde_yml::with::singleton_map_with; fn custom_serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: serde::Serializer, { // Custom serialization logic singleton_map_with::serialize(value, serializer) } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde( serialize_with = "custom_serialize", deserialize_with = "singleton_map_with::deserialize" )] field: MyEnum, } fn main() -> Result<(), serde_yml::Error> { let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use the `singleton_map_with` attribute in combination with a custom serialization function (`custom_serialize`) to serialize and deserialize an enum field (`MyEnum`) within a struct (`MyStruct`). The `custom_serialize` function is used for serialization, while the `singleton_map_with::deserialize` function is used for deserialization. This allows for additional customization of the serialization process while still leveraging the singleton_map_with attribute for deserialization. ### Serializing and Deserializing Enums with `singleton_map_with` ```rust use serde::{Deserialize, Serialize}; use serde_yml; use serde_yml::with::singleton_map_with; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde(with = "singleton_map_with")] field: MyEnum, } fn main() -> Result<(), serde_yml::Error> { let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); Ok(()) } ``` This example demonstrates how to use the `singleton_map_with` attribute to serialize and deserialize an enum field (`MyEnum`) within a struct (`MyStruct`). The `singleton_map_with` attribute allows for additional customization of the serialization and deserialization process through the use of helper functions. ## Contributing Contributions are welcome! Please submit a Pull Request on [GitHub][06]. ## Credits and Acknowledgements Serde YML is a continuation of the excellent work done by [David Tolnay][03] and the maintainers of the [serde-yaml][02] library. While Serde YML has evolved into a separate library, we express our sincere gratitude to them for their contributions to the Rust community. ## License Licensed under either of the [Apache License](LICENSE-APACHE) or the [MIT license](LICENSE-MIT) at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [00]: https://serdeyml.com [01]: https://github.com/serde-rs/serde [02]: https://github.com/dtolnay/serde-yaml [03]: https://github.com/dtolnay [04]: https://doc.libyml.com/serde-yaml/ [05]: https://yaml.org/ [06]: https://github.com/sebastienrousseau/serde_yml [07]: https://crates.io/crates/serde_yml [08]: https://docs.rs/serde_yml [09]: https://codecov.io/gh/sebastienrousseau/serde_yml [10]: https://github.com/sebastienrousseau/serde-yml/actions?query=branch%3Amaster [11]: https://www.rust-lang.org/ [12]: https://lib.rs/crates/serde_yml [build-badge]: https://img.shields.io/github/actions/workflow/status/sebastienrousseau/serde_yml/release.yml?branch=master&style=for-the-badge&logo=github "Build Status" [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/serde_yml?style=for-the-badge&token=Q9KJ6XXL67&logo=codecov "Codecov" [crates-badge]: https://img.shields.io/crates/v/serde_yml.svg?style=for-the-badge&color=fc8d62&logo=rust "Crates.io" [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.12-orange.svg?style=for-the-badge "View on lib.rs" [docs-badge]: https://img.shields.io/badge/docs.rs-serde__yml-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs "Docs.rs" [github-badge]: https://img.shields.io/badge/github-sebastienrousseau/serde--yml-8da0cb?style=for-the-badge&labelColor=555555&logo=github "GitHub" [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' serde_yml-0.0.12/build.rs000064400000000000000000000032631046102023000133400ustar 00000000000000//! This build script checks if the current Rustc version is at least the //! minimum required version. //! If the current Rustc version is less than the minimum required version, //! the build script will exit the build process with a non-zero exit code. //! //! The minimum required version is specified in the `min_version` variable. use std::process; /// Checks if the current Rustc version is at least the minimum required version /// /// # Arguments /// /// * `min_version` - The minimum required Rustc version as a string. /// /// # Returns /// /// * `Some(true)` - If the current Rustc version is at least the minimum /// required version. /// * `Some(false)` - If the current Rustc version is less than the minimum /// required version. /// * `None` - If the current Rustc version cannot be determined. /// /// # Errors /// /// This function will exit the build process with a non-zero exit code if the /// current Rustc version is less than the minimum required version. /// /// # Examples /// /// ```rust /// let min_version = "1.56"; /// /// match version_check::is_min_version(min_version) { /// Some(true) => println!("Rustc version is at least {}", min_version), /// Some(false) => { /// eprintln!("Rustc version is less than {}", min_version); /// process::exit(1); /// } /// None => { /// eprintln!("Unable to determine Rustc version"); /// process::exit(1); /// } /// } /// ``` fn main() { let min_version = "1.56"; match version_check::is_min_version(min_version) { Some(true) => {} _ => { eprintln!("'fd' requires Rustc version >= {}", min_version); process::exit(1); } } } serde_yml-0.0.12/examples/example.rs000064400000000000000000000024261046102023000155120ustar 00000000000000//! # Serde YML Examples //! //! This crate contains examples that demonstrate the usage of the Serde YML library. //! //! The examples are organized into the following modules: //! //! - `loader` - Contains the example modules for the `loader` module. //! - `with` - Contains the example modules for the `with` module. //! /// 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; /// Examples for the `tag` module. mod libyml; /// The main function that runs all the example modules. /// /// This function is responsible for running all the example modules. /// It does this by calling the `main` function of each example module. /// 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(); // Run the example module `libyml`. libyml::main(); } serde_yml-0.0.12/examples/libyml/emitter_examples.rs000064400000000000000000000274111046102023000207170ustar 00000000000000//! 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); } serde_yml-0.0.12/examples/libyml/mod.rs000064400000000000000000000014731046102023000161270ustar 00000000000000/// This module contains the `tag` example. 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_examples::main(); // Run the example module `util`. util_examples::main(); } serde_yml-0.0.12/examples/libyml/parser_examples.rs000064400000000000000000000231701046102023000205400ustar 00000000000000//! 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 _ => {} } } } } serde_yml-0.0.12/examples/libyml/safe_cstr_examples.rs000064400000000000000000000133351046102023000212170ustar 00000000000000//! 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"), } } serde_yml-0.0.12/examples/libyml/tag_examples.rs000064400000000000000000000126751046102023000200270ustar 00000000000000//! 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), } } } serde_yml-0.0.12/examples/libyml/util_examples.rs000064400000000000000000000043771046102023000202310ustar 00000000000000//! 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 ); } serde_yml-0.0.12/examples/loader/anchors_and_aliases.rs000064400000000000000000000030001046102023000212720ustar 00000000000000use serde_yml::{ de::{Event, Progress}, loader::Loader, }; use std::str; pub(crate) fn main() { // Print a message to indicate the file being executed. println!( "\n❯ Executing examples/loader/anchors_and_anchor_event_map.rs" ); let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); // Print a success message and present the results to the user. println!( "\n✅ Successfully loaded document with {} events:", document.events.len() ); for (event, mark) in &document.events { println!("\tEvent: {:?}, Mark: {:?}", event, mark); } // Perform assertions to verify that the loader is working as expected. assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 1); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[3]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "alias"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[4]; assert!(matches!(event, Event::Alias(0))); } serde_yml-0.0.12/examples/loader/io_errors.rs000064400000000000000000000007551046102023000173330ustar 00000000000000use serde_yml::{de::Progress, loader::Loader}; pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/loader/io_errors.rs"); let faulty_reader = std::io::Cursor::new(b"---\n- key: value\n"); let progress = Progress::Read(Box::new(faulty_reader)); match Loader::new(progress) { Ok(_) => println!("\n✅ Loader created successfully"), Err(e) => println!("Failed to create loader: {}", e), } } serde_yml-0.0.12/examples/loader/mod.rs000064400000000000000000000016741046102023000161100ustar 00000000000000/// This module contains the `single_document` example. pub(crate) mod single_document; /// This module contains the `multiple_documents` example. pub(crate) mod multiple_documents; /// This module contains the `unknown anchor` example. pub(crate) mod unknown_anchor; /// This module contains the `anchors_and_aliases` example. pub(crate) mod anchors_and_aliases; /// this module contains the `io_errors` example. pub(crate) mod io_errors; /// The main function that runs all the example modules. pub(crate) fn main() { // Run the example module `loader_anchors_and_aliases`. anchors_and_aliases::main(); // Run the example module `loader_io_errors`. io_errors::main(); // Run the example module `loader_multiple_documents`. multiple_documents::main(); // Run the example module `loader_single_document`. single_document::main(); // Run the example module `loader_unknown_anchor`. unknown_anchor::main(); } serde_yml-0.0.12/examples/loader/multiple_documents.rs000064400000000000000000000063651046102023000212470ustar 00000000000000// Import necessary modules from the serde_yml crate. use serde_yml::{de::Progress, loader::Loader}; // Define the main function. pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/loader/multiple_documents.rs"); // Define the YAML input string containing multiple documents. let input = "---\nkey1: value1\n...\n---\nkey2: value2\n..."; // Create a progress indicator for the loader using the input string. let progress = Progress::Str(input); // Attempt to create a new loader for deserializing YAML data. match Loader::new(progress) { Ok(mut loader) => { // If the loader creation is successful, print a success message. println!("\n✅ Loader created successfully"); // Attempt to load the first document from the loader. if let Some(document1) = loader.next_document() { // If document loading is successful, print a success message and present the results to the user. println!("\n✅ Document 1 successfully loaded:"); for (event, mark) in &document1.events { println!("\tEvent: {:?}, Mark: {:?}", event, mark); } println!(); // Add a newline for better formatting // Perform assertions to verify that the loader is working as expected. assert_eq!(document1.events.len(), 4); assert!(document1.error.is_none()); assert_eq!(document1.anchor_event_map.len(), 0); } else { // If document loading fails, print an error message. println!("Failed to load document 1"); } // Attempt to load the second document from the loader. if let Some(document2) = loader.next_document() { // If document loading is successful, print a success message and present the results to the user. println!("\n✅ Document 2 successfully loaded:"); for (event, mark) in &document2.events { println!("\tEvent: {:?}, Mark: {:?}", event, mark); } println!(); // Add a newline for better formatting // Perform assertions to verify that the loader is working as expected. assert_eq!(document2.events.len(), 4); assert!(document2.error.is_none()); assert_eq!(document2.anchor_event_map.len(), 0); } else { // If document loading fails, print an error message. println!("Failed to load document 2"); } // Check if there are more documents in the loader. if loader.next_document().is_none() { // If no more documents are present, print a success message. println!("\n✅ All documents loaded successfully"); } else { // If more documents are present, print an error message. println!("Failed to load all documents"); } } Err(e) => { // If loader creation fails, print an error message. println!("Failed to create loader: {}", e); } } } serde_yml-0.0.12/examples/loader/single_document.rs000064400000000000000000000035301046102023000205010ustar 00000000000000// Import necessary modules from the serde_yml crate. use serde_yml::{de::Progress, loader::Loader}; /// Example demonstrating the usage of Serde YML's `Loader` for YAML deserialization. pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/loader/single_document.rs"); // Sample YAML input string let input = "key: value"; // Create a progress indicator for the loader using the input string let progress = Progress::Str(input); // Attempt to create a new loader for deserializing YAML data match Loader::new(progress) { Ok(mut loader) => { // Attempt to retrieve the next YAML document from the loader if let Some(document) = loader.next_document() { // Assert that the number of events in the document is as expected assert_eq!(document.events.len(), 4); // Assert that there are no errors in the document assert!(document.error.is_none()); // Assert that there are no anchor_event_map in the document assert_eq!(document.anchor_event_map.len(), 0); // Print a success message and present the results to the user println!("\n✅ Document successfully loaded:"); for (event, mark) in &document.events { println!("\tEvent: {:?}, Mark: {:?}", event, mark); } } else { // If no document was returned, print an error message println!( "Failed to load document: ❌ No document found" ); } } Err(e) => { // If there was an error creating the loader, print the error message println!("Failed to create loader: ❌ {}", e); } } } serde_yml-0.0.12/examples/loader/unknown_anchor.rs000064400000000000000000000036661046102023000203650ustar 00000000000000// Import necessary modules from the serde_yml crate. use serde_yml::{ de::Progress, loader::Loader, modules::error::ErrorImpl, }; /// Example demonstrating the usage of Serde YML's `Loader` for YAML deserialization. pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/loader/unknown_anchor.rs"); // YAML input string with an unknown anchor let input = "*unknown"; // Create a progress indicator for the loader using the input string let progress = Progress::Str(input); // Create a new loader for deserializing YAML data, unwrapping the result let mut loader = match Loader::new(progress) { Ok(loader) => loader, Err(e) => { // If there was an error creating the loader, print the error message and exit println!("Failed to create loader: ❌ {}", e); return; } }; // Attempt to retrieve the next YAML document from the loader let document = match loader.next_document() { Some(document) => document, None => { // If no document was returned, print an error message and exit println!("Failed to load document: ❌ No document found"); return; } }; // Assert that the number of events in the document is as expected assert_eq!(document.events.len(), 0); // Assert that there is an error in the document assert!(document.error.is_some()); // Assert that there are no anchor_event_map in the document assert_eq!(document.anchor_event_map.len(), 0); // Retrieve the error from the document let error = document.error.unwrap(); // Assert that the error matches the expected UnknownAnchor variant assert!(matches!(*error, ErrorImpl::UnknownAnchor(_))); // Print a success message and present the error to the user println!("\n✅ Document loaded with expected error: \n\t{}", error); } serde_yml-0.0.12/examples/modules/mod.rs000064400000000000000000000003371046102023000163050ustar 00000000000000/// 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(); } serde_yml-0.0.12/examples/modules/path_examples.rs000064400000000000000000000154461046102023000203670ustar 00000000000000//! 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_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: 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); } serde_yml-0.0.12/examples/serializer/basic.rs000064400000000000000000000014161046102023000173070ustar 00000000000000//! //! Example for basic usage of the YAML serializer. //! //! This example demonstrates how to serialize a simple struct into YAML format //! using the `Serializer` provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::Serializer; #[derive(Serialize)] struct Person { name: String, age: u32, city: String, } pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/basic.rs"); let person = Person { name: "John Doe".to_string(), age: 30, city: "New York".to_string(), }; let mut serializer = Serializer::new(std::io::stdout()); person.serialize(&mut serializer).unwrap(); println!("\n✅ Person serialized to YAML."); } serde_yml-0.0.12/examples/serializer/collections.rs000064400000000000000000000015361046102023000205470ustar 00000000000000//! //! Example for serializing collections with the YAML serializer. //! //! This example demonstrates how to serialize various collection types (Vec, //! HashMap) into YAML format using the `Serializer` provided by the `serde_yml` //! crate. //! use serde_yml::{to_string, Result}; use std::collections::HashMap; pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/collections.rs"); let numbers = vec![1, 2, 3, 4, 5]; let yaml = to_string(&numbers)?; println!("\n✅ Vec serialized to YAML:\n{}", yaml); let mut map = HashMap::new(); map.insert("key1", "value1"); map.insert("key2", "value2"); map.insert("key3", "value3"); let yaml = to_string(&map)?; println!("\n✅ HashMap serialized to YAML:\n{}", yaml); Ok(()) } serde_yml-0.0.12/examples/serializer/complex_nested.rs000064400000000000000000000033211046102023000212340ustar 00000000000000//! //! Example for serializing complex nested data structures with the YAML serializer. //! //! This example demonstrates how the serializer handles complex nested data structures //! when serializing a struct into YAML format using the `Serializer` provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; use std::collections::HashMap; #[derive(Serialize)] enum Shape { Circle { radius: f64 }, Rectangle { width: f64, height: f64 }, } #[derive(Serialize)] struct Node { name: String, children: Vec, properties: HashMap, shape: Shape, } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/complex_nested.rs"); let root = Node { name: "root".to_string(), children: vec![ Node { name: "child1".to_string(), children: vec![], properties: HashMap::new(), shape: Shape::Circle { radius: 5.0 }, }, Node { name: "child2".to_string(), children: vec![], properties: [("color".to_string(), "blue".to_string())] .iter() .cloned() .collect(), shape: Shape::Rectangle { width: 10.0, height: 20.0, }, }, ], properties: HashMap::new(), shape: Shape::Circle { radius: 10.0 }, }; let yaml = to_string(&root)?; println!( "\n✅ Complex nested data structure serialized to YAML:\n{}", yaml ); Ok(()) } serde_yml-0.0.12/examples/serializer/custom_serialization.rs000064400000000000000000000017111046102023000224730ustar 00000000000000//! //! Example for custom serialization implementations with the YAML serializer. //! //! This example demonstrates how to use custom serialization implementations //! with the YAML serializer provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; struct Point { x: i32, y: i32, } impl Serialize for Point { fn serialize( &self, serializer: S, ) -> std::result::Result where S: serde::Serializer, { serializer.serialize_str(&format!("({}, {})", self.x, self.y)) } } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!( "\n❯ Executing examples/serializer/custom_serialization.rs" ); let point = Point { x: 3, y: 7 }; let yaml = to_string(&point)?; println!( "\n✅ Point serialized with custom implementation:\n{}", yaml ); Ok(()) } serde_yml-0.0.12/examples/serializer/enums.rs000064400000000000000000000016551046102023000173620ustar 00000000000000//! //! Example for serializing enums with the YAML serializer. //! //! This example demonstrates how to serialize enums with associated data into //! YAML format using the `Serializer` provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; #[derive(Serialize)] enum Shape { Rectangle { width: u32, height: u32 }, Circle { radius: f64 }, Triangle { base: u32, height: u32 }, } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/enums.rs"); let shapes = vec![ Shape::Rectangle { width: 10, height: 20, }, Shape::Circle { radius: 5.0 }, Shape::Triangle { base: 8, height: 12, }, ]; let yaml = to_string(&shapes)?; println!("\n✅ Shapes serialized to YAML:\n{}", yaml); Ok(()) } serde_yml-0.0.12/examples/serializer/error_handling.rs000064400000000000000000000021331046102023000212200ustar 00000000000000//! //! Example for error handling and serialization of custom error types with the YAML serializer. //! //! This example demonstrates how to handle and serialize custom error types //! with the YAML serializer provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; use std::fmt; #[derive(Serialize, Debug)] struct CustomError { message: String, } impl fmt::Display for CustomError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CustomError: {}", self.message) } } impl std::error::Error for CustomError {} #[derive(Serialize)] struct ErrorWrapper { error: Option, } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/error_handling.rs"); let error = CustomError { message: "Something went wrong".to_string(), }; let wrapper = ErrorWrapper { error: Some(error) }; let yaml = to_string(&wrapper)?; println!("\n✅ Custom error type serialized to YAML:\n{}", yaml); Ok(()) } serde_yml-0.0.12/examples/serializer/mod.rs000064400000000000000000000033201046102023000170010ustar 00000000000000//! Example modules for demonstrating the usage of the YAML serializer. //! //! This module contains example modules that demonstrate the usage of the YAML //! serializer provided by the `serde_yml` crate. Each example module demonstrates //! a different aspect of the serializer, such as serializing basic types, structs, //! enums, and collections. //! /// This module contains the `basic` example. pub(crate) mod basic; /// This module contains the `collections` example. pub(crate) mod collections; /// This module contains the `complex_nested` example. pub(crate) mod complex_nested; /// This module contains the `custom_serialization.rs` example. pub(crate) mod custom_serialization; /// This module contains the `enums` example. pub(crate) mod enums; /// This module contains the `error_handling` example. pub(crate) mod error_handling; /// This module contains the `optional_and_default` example. pub(crate) mod optional_and_default; /// This module contains the `structs` example. pub(crate) mod structs; /// The main function that runs all the example modules. pub(crate) fn main() { // Run the example module `basic`. basic::main(); // Run the example module `collections`. let _ = collections::main(); // Run the example module `complex_nested`. let _ = complex_nested::main(); // Run the example module `custom_serialization`. let _ = custom_serialization::main(); // Run the example module `enums`. let _ = enums::main(); // Run the example module `error_handling`. let _ = error_handling::main(); // Run the example module `optional_and_default`. let _ = optional_and_default::main(); // Run the example module `structs`. let _ = structs::main(); } serde_yml-0.0.12/examples/serializer/optional_and_default.rs000064400000000000000000000022311046102023000223750ustar 00000000000000//! //! Example for serializing optional fields and default values with the YAML serializer. //! //! This example demonstrates how the serializer handles optional fields and default values //! when serializing a struct into YAML format using the `Serializer` provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; #[derive(Serialize)] struct User { name: String, age: Option, #[serde(default)] is_active: bool, } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!( "\n❯ Executing examples/serializer/optional_and_default.rs" ); let user1 = User { name: "John".to_string(), age: Some(30), is_active: true, }; let yaml = to_string(&user1)?; println!( "\n✅ User with optional fields serialized to YAML:\n{}", yaml ); let user2 = User { name: "Jane".to_string(), age: None, is_active: false, }; let yaml = to_string(&user2)?; println!( "\n✅ User with default values serialized to YAML:\n{}", yaml ); Ok(()) } serde_yml-0.0.12/examples/serializer/structs.rs000064400000000000000000000017271046102023000177420ustar 00000000000000//! //! Example for serializing structs with the YAML serializer. //! //! This example demonstrates how to serialize nested structs into YAML format //! using the `Serializer` provided by the `serde_yml` crate. //! use serde::Serialize; use serde_yml::{to_string, Result}; #[derive(Serialize)] struct Address { street: String, city: String, country: String, } #[derive(Serialize)] struct User { name: String, age: u32, address: Address, } pub(crate) fn main() -> Result<()> { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/serializer/structs.rs"); let user = User { name: "Alice".to_string(), age: 25, address: Address { street: "123 Main St".to_string(), city: "Anytown".to_string(), country: "USA".to_string(), }, }; let yaml = to_string(&user)?; println!("\n✅ User serialized to YAML:\n{}", yaml); Ok(()) } serde_yml-0.0.12/examples/value/de_examples.rs000064400000000000000000000074071046102023000174650ustar 00000000000000//! 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(); } serde_yml-0.0.12/examples/value/index_examples.rs000064400000000000000000000173051046102023000202020ustar 00000000000000//! 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"); } } serde_yml-0.0.12/examples/value/mod.rs000064400000000000000000000005751046102023000157550ustar 00000000000000/// 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(); } serde_yml-0.0.12/examples/with/mod.rs000064400000000000000000000052711046102023000156120ustar 00000000000000/// This module contains the `singleton_map` example. pub(crate) mod singleton_map; /// This module contains the `singleton_map_recursive` pub(crate) mod singleton_map_recursive; /// This module contains the `singleton_map_enum_variants` example. pub(crate) mod singleton_map_enum_variants; /// This module contains the `singleton_map_recursive_deep_nesting` example. pub(crate) mod singleton_map_recursive_deep_nesting; /// This module contains the `singleton_map_recursive_serialize_deserialize` example. pub(crate) mod singleton_map_recursive_serialize_deserialize; /// This module contains the `singleton_map_optional` example. pub(crate) mod singleton_map_optional; /// This module contains the `singleton_map_with` example. pub(crate) mod singleton_map_with; /// This module contains the `singleton_map_recursive_optional` example. pub(crate) mod singleton_map_recursive_optional; /// This module contains the `singleton_map_recursive_with` example. pub(crate) mod singleton_map_recursive_with; /// This module contains the `singleton_map_with_custom_serialize` example. pub(crate) mod singleton_map_with_custom_serialize; /// This module contains the `singleton_map_custom_serialize_deserialize` example. pub(crate) mod singleton_map_custom_serialize_deserialize; /// This module contains the `nested_singleton_map` example. pub(crate) mod nested_singleton_map; /// The main function that runs all the example modules. pub(crate) fn main() { // Run the example module `loader_anchors_and_aliases`. singleton_map::main(); // Run the example module `singleton_map_recursive`. singleton_map_recursive::main(); // Run the example module `singleton_map_enum_variants`. singleton_map_enum_variants::main(); // Run the example module `singleton_map_recursive_deep_nesting`. singleton_map_recursive_deep_nesting::main(); // Run the example module `singleton_map_recursive_serialize_deserialize`. singleton_map_recursive_serialize_deserialize::main(); // Run the example module `singleton_map_optional`. singleton_map_optional::main(); // Run the example module `singleton_map_with`. singleton_map_with::main(); // Run the example module `singleton_map_recursive_optional`. singleton_map_recursive_optional::main(); // Run the example module `singleton_map_recursive_with`. singleton_map_recursive_with::main(); // Run the example module `singleton_map_with_custom_serialize`. singleton_map_with_custom_serialize::main(); // Run the example module `singleton_map_custom_serialize_deserialize`. singleton_map_custom_serialize_deserialize::main(); // Run the example module `nested_singleton_map`. nested_singleton_map::main(); } serde_yml-0.0.12/examples/with/nested_singleton_map.rs000064400000000000000000000076321046102023000212370ustar 00000000000000//! Example for the `nested_singleton_map` function in the `with` module. //! //! This function is used to recursively serialize and deserialize nested enums //! into a YAML map with a single key-value pair for each enum variant, where the //! key is the enum variant name and the value is the inner value of the enum //! variant. //! use serde::{Deserialize, Serialize}; use serde_yml::with::nested_singleton_map; pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/with/nested_singleton_map.rs"); // Define the inner enum with different variants #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Variant1, Variant2(String), Variant3 { field1: i32, field2: bool }, } // Define the outer enum that contains the inner enum as a field #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OuterEnum { Variant1(InnerEnum), Variant2 { inner: InnerEnum }, } // Define a struct that contains the outer enum as a field #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NestedEnumStruct { #[serde(with = "nested_singleton_map")] field: OuterEnum, } // Example 1: OuterEnum::Variant1(InnerEnum::Variant1) let input1 = NestedEnumStruct { field: OuterEnum::Variant1(InnerEnum::Variant1), }; let yaml1 = serde_yml::to_string(&input1).unwrap(); println!("\n✅ Serialized YAML for Example 1:\n{}", yaml1); let output1: NestedEnumStruct = serde_yml::from_str(&yaml1).unwrap(); println!("\n✅ Deserialized YAML for Example 1:\n{:#?}", output1); assert_eq!(input1, output1); // Example 2: OuterEnum::Variant1(InnerEnum::Variant2("value".to_string())) let input2 = NestedEnumStruct { field: OuterEnum::Variant1(InnerEnum::Variant2( "value".to_string(), )), }; let yaml2 = serde_yml::to_string(&input2).unwrap(); println!("\n✅ Serialized YAML for Example 2:\n{}", yaml2); let output2: NestedEnumStruct = serde_yml::from_str(&yaml2).unwrap(); println!("\n✅ Deserialized YAML for Example 2:\n{:#?}", output2); assert_eq!(input2, output2); // Example 3: OuterEnum::Variant2 { inner: InnerEnum::Variant3 { field1: 42, field2: true } } let input3 = NestedEnumStruct { field: OuterEnum::Variant2 { inner: InnerEnum::Variant3 { field1: 42, field2: true, }, }, }; let yaml3 = serde_yml::to_string(&input3).unwrap(); println!("\n✅ Serialized YAML for Example 3:\n{}", yaml3); let output3: NestedEnumStruct = serde_yml::from_str(&yaml3).unwrap(); println!("\n✅ Deserialized YAML for Example 3:\n{:#?}", output3); assert_eq!(input3, output3); // Example 4: OuterEnum::Variant1(InnerEnum::Variant3 { field1: 99, field2: false }) let input4 = NestedEnumStruct { field: OuterEnum::Variant1(InnerEnum::Variant3 { field1: 99, field2: false, }), }; let yaml4 = serde_yml::to_string(&input4).unwrap(); println!("\n✅ Serialized YAML for Example 4:\n{}", yaml4); let output4: NestedEnumStruct = serde_yml::from_str(&yaml4).unwrap(); println!("\n✅ Deserialized YAML for Example 4:\n{:#?}", output4); assert_eq!(input4, output4); // Example 5: OuterEnum::Variant2 { inner: InnerEnum::Variant2("another value".to_string()) } let input5 = NestedEnumStruct { field: OuterEnum::Variant2 { inner: InnerEnum::Variant2("another value".to_string()), }, }; let yaml5 = serde_yml::to_string(&input5).unwrap(); println!("\n✅ Serialized YAML for Example 5:\n{}", yaml5); let output5: NestedEnumStruct = serde_yml::from_str(&yaml5).unwrap(); println!("\n✅ Deserialized YAML for Example 5:\n{:#?}", output5); assert_eq!(input5, output5); } serde_yml-0.0.12/examples/with/singleton_map.rs000064400000000000000000000024101046102023000176620ustar 00000000000000//! //! Example for the `singleton_map` function in the `with` module. //! //! This function is used to serialize a struct field that contains an enum with //! only one variant into a YAML map with a single key-value pair, where the key //! is the enum variant name and the value is the inner value of the enum //! variant. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map; pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/with/singleton_map.rs"); // Example 1: Using singleton_map for a single enum field #[derive(Serialize, Deserialize, PartialEq, Debug)] enum SingleVariantEnum { Variant(String), } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct SingleVariantStruct { #[serde(with = "singleton_map")] field: SingleVariantEnum, } let input = SingleVariantStruct { field: SingleVariantEnum::Variant("value".to_string()), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: SingleVariantStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_custom_serialize_deserialize.rs000064400000000000000000000050601046102023000257070ustar 00000000000000//! //! Example for using `singleton_map` within a struct that has custom `Serialize` and `Deserialize` implementations. //! //! This example demonstrates the usage of `singleton_map` within a struct that has custom serialization //! and deserialization logic to serialize and deserialize an enum field. //! use serde::{ de::{self, Deserializer, IgnoredAny, MapAccess, Visitor}, ser::{SerializeMap, Serializer}, Deserialize, Serialize, }; use std::fmt; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(PartialEq, Debug)] struct MyStruct { field: MyEnum, } impl Serialize for MyStruct { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut map = serializer.serialize_map(Some(1))?; map.serialize_entry("field", &self.field)?; map.end() } } impl<'de> Deserialize<'de> for MyStruct { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct MyStructVisitor; impl<'de> Visitor<'de> for MyStructVisitor { type Value = MyStruct; fn expecting( &self, formatter: &mut fmt::Formatter, ) -> fmt::Result { formatter.write_str("a MyStruct") } fn visit_map( self, mut map: V, ) -> Result where V: MapAccess<'de>, { let mut field = None; while let Some(key) = map.next_key::()? { if key == "field" { field = Some(map.next_value()?); } else { map.next_value::()?; } } let field = field .ok_or_else(|| de::Error::missing_field("field"))?; Ok(MyStruct { field }) } } deserializer.deserialize_map(MyStructVisitor) } } pub(crate) fn main() { println!("\n❯ Executing examples/with/singleton_map_custom_serialize_deserialize.rs"); let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_enum_variants.rs000064400000000000000000000030221046102023000226150ustar 00000000000000//! //! Example for the `singleton_map_enum_variants` function in the `with` module. //! //! This function is used to serialize a struct field that contains an enum with //! multiple variants into a YAML map with a single key-value pair, where the key //! is the enum variant name and the value is the inner value of the enum //! variant. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map; pub(crate) fn main() { // Print a message to indicate the file being executed. println!( "\n❯ Executing examples/with/singleton_map_enum_variants.rs" ); // Define an enum with multiple variants #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MultiVariantEnum { Unit, Newtype(String), Tuple(i32, bool), Struct { field: f64 }, } // Define a struct containing fields of the enum type #[derive(Serialize, Deserialize, PartialEq, Debug)] struct EnumStruct { #[serde(with = "singleton_map")] field1: MultiVariantEnum, #[serde(with = "singleton_map")] field2: MultiVariantEnum, } let input = EnumStruct { field1: MultiVariantEnum::Unit, field2: MultiVariantEnum::Struct { field: std::f64::consts::PI, }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: EnumStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_optional.rs000064400000000000000000000022521046102023000215730ustar 00000000000000//! //! Example for using `singleton_map_optional` to serialize and deserialize an optional enum field. //! //! This example demonstrates the usage of `singleton_map_optional` to seamlessly serialize and //! deserialize an `Option` field as a single YAML mapping entry with the key being the enum //! variant name. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_optional; pub(crate) fn main() { println!("\n❯ Executing examples/with/singleton_map_optional.rs"); #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OptionalEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct OptionalStruct { #[serde(with = "singleton_map_optional")] field: Option, } let input = OptionalStruct { field: Some(OptionalEnum::Variant2 { field: 42 }), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: OptionalStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_recursive.rs000064400000000000000000000037041046102023000217600ustar 00000000000000//! //! Example for the `singleton_map_recursive` function in the `with` module. //! //! This function is used to serialize a struct field that contains an enum with //! only one variant into a YAML map with a single key-value pair, where the key //! is the enum variant name and the value is the inner value of the enum //! variant. //! // Import necessary crates. use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_recursive; // Define the main function. pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/with/singleton_map_recursive.rs"); // Define an enum with a single variant. #[derive(Serialize, Deserialize, PartialEq, Debug)] enum SingleVariantEnum { Variant(String), } // Define a nested enum with two variants, one containing the single variant enum. #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant1(String), Variant2(SingleVariantEnum), } // Define a struct containing the nested enum field serialized using the `singleton_map_recursive` function. #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NestedStruct { #[serde(with = "singleton_map_recursive")] field: NestedEnum, } // Create an instance of the NestedStruct with a nested enum variant. let input = NestedStruct { field: NestedEnum::Variant2(SingleVariantEnum::Variant( "nested".to_string(), )), }; // Serialize the input struct to YAML format and print it. let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); // Deserialize the YAML string back to a NestedStruct and print it. let output: NestedStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); // Assert that the input and output are equal. assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_recursive_deep_nesting.rs000064400000000000000000000035221046102023000245020ustar 00000000000000//! //! Example for the `singleton_map_recursive_deep_nesting` function in the `with` module. //! //! This example demonstrates the use of the //! `singleton_map_recursive_deep_nesting` function to serialize and deserialize //! a struct field that contains an enum with deeply nested variants into a YAML //! map with a single key-value pair, where the key is the enum variant name and //! the value is the inner value of the enum variant. use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_recursive; pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/with/singleton_map_recursive_deep_nesting.rs"); // Define an enum with deeply nested enums #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant1(String), Variant2(InnerEnum), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Inner1(i32), Inner2(bool, DeepEnum), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum DeepEnum { Deep1(char), Deep2 { field: String }, } // Define a struct containing a field of the deeply nested enum type #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NestedStruct { #[serde(with = "singleton_map_recursive")] field: NestedEnum, } let input = NestedStruct { field: NestedEnum::Variant2(InnerEnum::Inner2( true, DeepEnum::Deep2 { field: "nested".to_string(), }, )), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: NestedStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_recursive_optional.rs000064400000000000000000000026471046102023000236720ustar 00000000000000//! //! Example for using `singleton_map_recursive` to serialize and deserialize a nested enum structure. //! //! This example demonstrates the usage of `singleton_map_recursive` to seamlessly serialize and //! deserialize a nested enum structure where one of the enum variants contains an optional inner //! enum. The nested enums are serialized and deserialized as single YAML mapping entries with the //! keys being the enum variant names. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_recursive; pub(crate) fn main() { println!("\n❯ Executing examples/with/singleton_map_recursive_optional.rs"); #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant1(String), Variant2(Option), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Inner1(i32), Inner2(i32), } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NestedStruct { #[serde(with = "singleton_map_recursive")] field: NestedEnum, } let input = NestedStruct { field: NestedEnum::Variant2(Some(InnerEnum::Inner2(42))), }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: NestedStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_recursive_serialize_deserialize.rs000064400000000000000000000025071046102023000264070ustar 00000000000000//! //! Example for the `serialize` and `deserialize` functions in the `singleton_map_recursive` module. //! //! This example demonstrates the usage of the `serialize` and `deserialize` functions //! from the `singleton_map_recursive` module to serialize and deserialize a //! struct field that contains an enum with multiple variants into a YAML map //! with a single key-value pair, where the key is the enum variant name and the //! value is the inner value of the enum variant. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_recursive; #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde(with = "singleton_map_recursive")] field: MyEnum, } pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/with/singleton_map_recursive_serialize_deserialize.rs"); let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_recursive_with.rs000064400000000000000000000021711046102023000230100ustar 00000000000000//! //! Example for using `singleton_map_recursive` to serialize and deserialize an enum field. //! //! This example demonstrates the usage of `singleton_map_recursive` to seamlessly serialize and //! deserialize an enum field as a single YAML mapping entry with the key being the enum variant name. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_recursive; pub(crate) fn main() { println!( "\n❯ Executing examples/with/singleton_map_recursive_with.rs" ); #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde(with = "singleton_map_recursive")] field: MyEnum, } let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_with.rs000064400000000000000000000023621046102023000207230ustar 00000000000000//! //! Example for using `singleton_map_with` to serialize and deserialize an enum field. //! //! This example demonstrates the usage of `singleton_map_with` to seamlessly serialize and //! deserialize an enum field as a single YAML mapping entry with the key being the enum variant name. //! The `singleton_map_with` attribute allows for additional customization of the serialization //! and deserialization process through the use of helper functions. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_with; pub(crate) fn main() { println!("\n❯ Executing examples/with/singleton_map_with.rs"); #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde(with = "singleton_map_with")] field: MyEnum, } let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/examples/with/singleton_map_with_custom_serialize.rs000064400000000000000000000025601046102023000243640ustar 00000000000000//! //! Example for using `singleton_map_with` in combination with a custom `serialize_with` attribute. //! //! This example demonstrates the usage of `singleton_map_with` in combination with a custom //! serialization function to serialize and deserialize an enum field within a struct. //! use serde::{Deserialize, Serialize}; use serde_yml::with::singleton_map_with; fn custom_serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: serde::Serializer, { // Custom serialization logic singleton_map_with::serialize(value, serializer) } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Variant1(String), Variant2 { field: i32 }, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct MyStruct { #[serde( serialize_with = "custom_serialize", deserialize_with = "singleton_map_with::deserialize" )] field: MyEnum, } pub(crate) fn main() { println!("\n❯ Executing examples/with/singleton_map_with_custom_serialize.rs"); let input = MyStruct { field: MyEnum::Variant2 { field: 42 }, }; let yaml = serde_yml::to_string(&input).unwrap(); println!("\n✅ Serialized YAML:\n{}", yaml); let output: MyStruct = serde_yml::from_str(&yaml).unwrap(); println!("\n✅ Deserialized YAML:\n{:#?}", output); assert_eq!(input, output); } serde_yml-0.0.12/src/de.rs000064400000000000000000002141371046102023000134240ustar 00000000000000use crate::{ libyml::{ error::Mark, parser::{MappingStart, Scalar, ScalarStyle, SequenceStart}, tag::Tag, }, loader::{Document, Loader}, modules::error::{self, Error, ErrorImpl}, modules::path::Path, }; use serde::de::{ self, value::StrDeserializer, Deserialize, DeserializeOwned, DeserializeSeed, Expected, IgnoredAny, Unexpected, Visitor, }; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt::Result as FmtResult; use std::{fmt, io, mem, num::ParseIntError, str, sync::Arc}; type Result = std::result::Result; /// A structure that deserializes YAML into Rust values. /// /// # Examples /// /// Deserializing a single document: /// /// ``` /// use serde::Deserialize; /// use serde_yml::Value; /// /// fn main() -> serde_yml::Result<()> { /// let input = "k: 107\n"; /// let de = serde_yml::Deserializer::from_str(input); /// let value = Value::deserialize(de)?; /// println!("{:?}", value); /// Ok(()) /// } /// ``` /// /// Deserializing multi-doc YAML: /// /// ``` /// use serde::Deserialize; /// use serde_yml::Value; /// /// fn main() -> serde_yml::Result<()> { /// let input = "---\nk: 107\n...\n---\nj: 106\n"; /// /// for document in serde_yml::Deserializer::from_str(input) { /// let value = Value::deserialize(document)?; /// println!("{:?}", value); /// } /// /// Ok(()) /// } /// ``` #[derive(Debug)] pub struct Deserializer<'de> { /// Represents the progress of parsing a YAML document. pub progress: Progress<'de>, } /// Represents the progress of parsing a YAML document. pub enum Progress<'de> { /// Indicates that the YAML input is a string slice. /// /// The `&'de str` represents a borrowed string slice with a lifetime `'de`. Str(&'de str), /// Indicates that the YAML input is a byte slice. /// /// The `&'de [u8]` represents a borrowed byte slice with a lifetime `'de`. Slice(&'de [u8]), /// Indicates that the YAML input is provided through a `Read` trait object. /// /// The `Box` represents a boxed trait object that implements the `Read` trait /// and has a lifetime `'de`. This allows for reading the YAML input from various sources, /// such as files, network streams, or any other type that implements `Read`. Read(Box), /// Indicates that the YAML input is provided through an iterator of `Loader` instances. /// /// The `Loader<'de>` represents a YAML loader that iterates over the YAML documents. /// The `'de` lifetime indicates the lifetime of the borrowed data within the loader. Iterable(Loader<'de>), /// Indicates that the YAML input is a single `Document` instance. /// /// The `Document<'de>` represents a parsed YAML document. /// The `'de` lifetime indicates the lifetime of the borrowed data within the document. Document(Document<'de>), /// Indicates that an error occurred during parsing. /// /// The `Arc` represents a reference-counted pointer to the error implementation. /// It allows for sharing the error across multiple owners without duplication. Fail(Arc), } impl Debug for Progress<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Progress::Str(s) => write!(f, "Progress::Str({:?})", s), Progress::Slice(slice) => { write!(f, "Progress::Slice({:?})", slice) } Progress::Read(_) => { write!(f, "Progress::Read(Box)") } Progress::Iterable(loader) => { write!(f, "Progress::Iterable({:?})", loader) } Progress::Document(doc) => { write!(f, "Progress::Document({:?})", doc) } Progress::Fail(err) => { write!(f, "Progress::Fail({:?})", err) } } } } impl<'de> Deserializer<'de> { /// Deserializes an instance of type `T` from a string of YAML text. /// /// This function takes a string slice containing YAML data and attempts to parse and /// deserialize it into an instance of the type `T`. The type must implement the `Deserialize` /// trait from Serde. The function returns a result, which is either the deserialized /// type `T` or an error if the deserialization process fails. /// /// # Errors /// /// This function returns an error if the YAML text does not correctly represent the /// expected type `T`. Errors can arise from incorrect YAML syntax, type mismatches, /// missing required fields, and other deserialization issues. /// /// # Examples /// /// ``` /// use serde_yml::from_str; /// use serde::Deserialize; /// /// #[derive(Debug, Deserialize)] /// struct Config { /// name: String, /// age: u32, /// } /// /// let yaml_data = r#" /// name: John Doe /// age: 30 /// "#; /// let config: Config = from_str(yaml_data).unwrap(); /// println!("{:?}", config); // Config { name: "John Doe", age: 30 } /// ``` #[allow(clippy::should_implement_trait)] pub fn from_str(s: &'de str) -> Self { let progress = Progress::Str(s); Deserializer { progress } } /// Deserializes an instance of type `T` from bytes of YAML text. /// /// Similar to `from_str`, but instead of a string slice, it operates on a byte slice. This /// is useful when working with binary data or data read from non-text sources. /// /// # Errors /// /// Returns an error if the byte slice does not represent a valid YAML sequence or if it /// cannot be deserialized into type `T` due to type mismatches, missing fields, etc. /// /// # Examples /// /// ``` /// use serde_yml::from_slice; /// use serde::Deserialize; /// /// #[derive(Debug, Deserialize)] /// struct Item { /// name: String, /// quantity: u32, /// } /// /// let bytes = b"name: Widget\nquantity: 100"; /// let item: Item = from_slice(bytes).unwrap(); /// println!("{:?}", item); // Item { name: "Widget", quantity: 100 } /// pub fn from_slice(v: &'de [u8]) -> Self { let progress = Progress::Slice(v); Deserializer { progress } } /// Deserializes an instance of type `T` from an IO stream of YAML. /// /// This function is useful when you need to deserialize data directly from a stream, such as /// reading from a file or over the network. It accepts any type that implements the `io::Read` /// trait. As with `from_str`, the target type `T` must implement the `Deserialize` trait. /// /// # Errors /// /// Deserialization might fail due to IO errors (e.g., if the stream is not readable), YAML syntax /// errors, or if the data does not fit the expected structure of type `T`. In such cases, the /// function returns an error. /// /// # Examples /// /// ``` /// use serde_yml::from_reader; /// use serde::Deserialize; /// use std::io::Cursor; /// /// #[derive(Debug, Deserialize)] /// struct Config { /// name: String, /// age: u32, /// } /// /// // Simulate file reading with a cursor over a byte slice. /// let data = b"name: Jane Doe\nage: 25"; /// let cursor = Cursor::new(data); /// /// let config: Config = from_reader(cursor).unwrap(); /// println!("{:?}", config); // Config { name: "Jane Doe", age: 25 } /// ``` /// pub fn from_reader(rdr: R) -> Self where R: io::Read + 'de, { let progress = Progress::Read(Box::new(rdr)); Deserializer { progress } } fn de( self, f: impl for<'document> FnOnce( &mut DeserializerFromEvents<'de, 'document>, ) -> Result, ) -> Result { let mut pos = 0; let mut jumpcount = 0; match self.progress { Progress::Iterable(_) => { return Err(error::new(ErrorImpl::MoreThanOneDocument)) } Progress::Document(document) => { let t = f(&mut DeserializerFromEvents { document: &document, pos: &mut pos, jumpcount: &mut jumpcount, path: Path::Root, remaining_depth: 128, current_enum: None, })?; if let Some(parse_error) = document.error { return Err(error::shared(parse_error)); } return Ok(t); } _ => {} } let mut loader = Loader::new(self.progress)?; let document = match loader.next_document() { Some(document) => document, None => return Err(error::new(ErrorImpl::EndOfStream)), }; let t = f(&mut DeserializerFromEvents { document: &document, pos: &mut pos, jumpcount: &mut jumpcount, path: Path::Root, remaining_depth: 128, current_enum: None, })?; if let Some(parse_error) = document.error { return Err(error::shared(parse_error)); } if loader.next_document().is_none() { Ok(t) } else { Err(error::new(ErrorImpl::MoreThanOneDocument)) } } } impl Iterator for Deserializer<'_> { type Item = Self; fn next(&mut self) -> Option { match &mut self.progress { Progress::Iterable(loader) => { let document = loader.next_document()?; return Some(Deserializer { progress: Progress::Document(document), }); } Progress::Document(_) => return None, Progress::Fail(err) => { return Some(Deserializer { progress: Progress::Fail(Arc::clone(err)), }); } _ => {} } let dummy = Progress::Str(""); let input = mem::replace(&mut self.progress, dummy); match Loader::new(input) { Ok(loader) => { self.progress = Progress::Iterable(loader); self.next() } Err(err) => { let fail = err.shared(); self.progress = Progress::Fail(Arc::clone(&fail)); Some(Deserializer { progress: Progress::Fail(fail), }) } } } } impl<'de> de::Deserializer<'de> for Deserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_any(visitor)) } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_bool(visitor)) } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i8(visitor)) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i16(visitor)) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i32(visitor)) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i64(visitor)) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i128(visitor)) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u8(visitor)) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u16(visitor)) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u32(visitor)) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u64(visitor)) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u128(visitor)) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_f32(visitor)) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_f64(visitor)) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_char(visitor)) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_str(visitor)) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_string(visitor)) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_bytes(visitor)) } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_byte_buf(visitor)) } fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_option(visitor)) } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_unit(visitor)) } fn deserialize_unit_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_unit_struct(name, visitor)) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_newtype_struct(name, visitor)) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_seq(visitor)) } fn deserialize_tuple( self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_tuple(len, visitor)) } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| { state.deserialize_tuple_struct(name, len, visitor) }) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_map(visitor)) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_struct(name, fields, visitor)) } fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_enum(name, variants, visitor)) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_identifier(visitor)) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_ignored_any(visitor)) } } /// Represents the different events that can occur during YAML parsing. #[derive(Debug)] pub enum Event<'de> { /// Represents an alias event, which refers to a previously defined anchor. /// The `usize` value represents the index of the aliased event. Alias(usize), /// Represents a scalar event, which contains a scalar value. /// The `Scalar` type holds the scalar value and its associated properties. Scalar(Scalar<'de>), /// Represents the start of a sequence event. /// The `SequenceStart` type holds the properties of the sequence, such as its anchor and tag. SequenceStart(SequenceStart), /// Represents the end of a sequence event. SequenceEnd, /// Represents the start of a mapping event. /// The `MappingStart` type holds the properties of the mapping, such as its anchor and tag. MappingStart(MappingStart), /// Represents the end of a mapping event. MappingEnd, /// Represents a void event, which is an empty event. /// This event is used when there are no other events to be parsed. Void, } struct DeserializerFromEvents<'de, 'document> { document: &'document Document<'de>, pos: &'document mut usize, jumpcount: &'document mut usize, path: Path<'document>, remaining_depth: u8, current_enum: Option>, } #[derive(Copy, Clone)] /// Represents the current state of an enum during deserialization. #[derive(Debug)] pub struct CurrentEnum<'document> { /// The name of the enum variant. pub name: Option<&'static str>, /// The tag of the enum variant. pub tag: &'document str, } impl<'de, 'document> DeserializerFromEvents<'de, 'document> { fn peek_event(&self) -> Result<&'document Event<'de>> { self.peek_event_mark().map(|(event, _mark)| event) } fn peek_event_mark(&self) -> Result<(&'document Event<'de>, Mark)> { match self.document.events.get(*self.pos) { Some((event, mark)) => Ok((event, *mark)), None => Err(match &self.document.error { Some(parse_error) => { error::shared(Arc::clone(parse_error)) } None => error::new(ErrorImpl::EndOfStream), }), } } fn next_event(&mut self) -> Result<&'document Event<'de>> { self.next_event_mark().map(|(event, _mark)| event) } fn next_event_mark( &mut self, ) -> Result<(&'document Event<'de>, Mark)> { self.peek_event_mark().map(|(event, mark)| { *self.pos += 1; self.current_enum = None; (event, mark) }) } fn jump<'anchor>( &'anchor mut self, pos: &'anchor mut usize, ) -> Result> { *self.jumpcount += 1; if *self.jumpcount > self.document.events.len() * 100 { return Err(error::new(ErrorImpl::RepetitionLimitExceeded)); } match self.document.anchor_event_map.get(pos) { Some(found) => { *pos = *found; Ok(DeserializerFromEvents { document: self.document, pos, jumpcount: self.jumpcount, path: Path::Alias { parent: &self.path }, remaining_depth: self.remaining_depth, current_enum: None, }) } None => panic!("unresolved alias: {}", *pos), } } fn ignore_any(&mut self) -> Result<()> { enum Nest { Sequence, Mapping, } let mut stack = Vec::new(); #[allow(clippy::never_loop)] loop { match self.next_event()? { Event::Alias(_) | Event::Scalar(_) | Event::Void => {} Event::SequenceStart(_) => { stack.push(Nest::Sequence); } Event::MappingStart(_) => { stack.push(Nest::Mapping); } Event::SequenceEnd => match stack.pop() { Some(Nest::Sequence) => {} None | Some(Nest::Mapping) => { panic!("unexpected end of sequence"); } }, Event::MappingEnd => match stack.pop() { Some(Nest::Mapping) => {} None | Some(Nest::Sequence) => { panic!("unexpected end of mapping"); } }, } if stack.is_empty() { return Ok(()); } } } fn visit_sequence( &mut self, visitor: V, mark: Mark, ) -> Result where V: Visitor<'de>, { let (value, len) = self.recursion_check(mark, |de| { let mut seq = SeqAccess { empty: false, de, len: 0, }; let value = visitor.visit_seq(&mut seq)?; Ok((value, seq.len)) })?; self.end_sequence(len)?; Ok(value) } fn visit_mapping( &mut self, visitor: V, mark: Mark, ) -> Result where V: Visitor<'de>, { let (value, len) = self.recursion_check(mark, |de| { let mut map = MapAccess { empty: false, de, len: 0, key: None, }; let value = visitor.visit_map(&mut map)?; Ok((value, map.len)) })?; self.end_mapping(len)?; Ok(value) } fn end_sequence(&mut self, len: usize) -> Result<()> { let total = { let mut seq = SeqAccess { empty: false, de: self, len, }; while de::SeqAccess::next_element::(&mut seq)? .is_some() {} seq.len }; match self.next_event()? { Event::SequenceEnd | Event::Void => {} _ => panic!("expected a SequenceEnd event"), } if total == len { Ok(()) } else { struct ExpectedSeq(usize); impl Expected for ExpectedSeq { fn fmt( &self, formatter: &mut Formatter<'_>, ) -> fmt::Result { if self.0 == 1 { write!(formatter, "sequence of 1 element") } else { write!( formatter, "sequence of {} elements", self.0 ) } } } Err(de::Error::invalid_length(total, &ExpectedSeq(len))) } } fn end_mapping(&mut self, len: usize) -> Result<()> { let total = { let mut map = MapAccess { empty: false, de: self, len, key: None, }; while de::MapAccess::next_entry::( &mut map, )? .is_some() {} map.len }; match self.next_event()? { Event::MappingEnd | Event::Void => {} _ => panic!("expected a MappingEnd event"), } if total == len { Ok(()) } else { struct ExpectedMap(usize); impl Expected for ExpectedMap { fn fmt( &self, formatter: &mut Formatter<'_>, ) -> fmt::Result { if self.0 == 1 { write!(formatter, "map containing 1 entry") } else { write!( formatter, "map containing {} entries", self.0 ) } } } Err(de::Error::invalid_length(total, &ExpectedMap(len))) } } fn recursion_check Result, T>( &mut self, mark: Mark, f: F, ) -> Result { let previous_depth = self.remaining_depth; self.remaining_depth = match previous_depth.checked_sub(1) { Some(depth) => depth, None => { return Err(error::new( ErrorImpl::RecursionLimitExceeded(mark), )) } }; let result = f(self); self.remaining_depth = previous_depth; result } } struct SeqAccess<'de, 'document, 'seq> { empty: bool, de: &'seq mut DeserializerFromEvents<'de, 'document>, len: usize, } impl<'de> de::SeqAccess<'de> for SeqAccess<'de, '_, '_> { type Error = Error; fn next_element_seed( &mut self, seed: T, ) -> Result> where T: DeserializeSeed<'de>, { if self.empty { return Ok(None); } match self.de.peek_event()? { Event::SequenceEnd | Event::Void => Ok(None), _ => { let mut element_de = DeserializerFromEvents { document: self.de.document, pos: self.de.pos, jumpcount: self.de.jumpcount, path: Path::Seq { parent: &self.de.path, index: self.len, }, remaining_depth: self.de.remaining_depth, current_enum: None, }; self.len += 1; seed.deserialize(&mut element_de).map(Some) } } } } struct MapAccess<'de, 'document, 'map> { empty: bool, de: &'map mut DeserializerFromEvents<'de, 'document>, len: usize, key: Option<&'document [u8]>, } impl<'de> de::MapAccess<'de> for MapAccess<'de, '_, '_> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { if self.empty { return Ok(None); } match self.de.peek_event()? { Event::MappingEnd | Event::Void => Ok(None), Event::Scalar(scalar) => { self.len += 1; self.key = Some(&scalar.value); seed.deserialize(&mut *self.de).map(Some) } _ => { self.len += 1; self.key = None; seed.deserialize(&mut *self.de).map(Some) } } } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { let mut value_de = DeserializerFromEvents { document: self.de.document, pos: self.de.pos, jumpcount: self.de.jumpcount, path: if let Some(key) = self.key.and_then(|key| str::from_utf8(key).ok()) { Path::Map { parent: &self.de.path, key, } } else { Path::Unknown { parent: &self.de.path, } }, remaining_depth: self.de.remaining_depth, current_enum: None, }; seed.deserialize(&mut value_de) } } struct EnumAccess<'de, 'document, 'variant> { de: &'variant mut DeserializerFromEvents<'de, 'document>, name: Option<&'static str>, tag: &'document str, } impl<'de, 'variant> de::EnumAccess<'de> for EnumAccess<'de, '_, 'variant> { type Error = Error; type Variant = DeserializerFromEvents<'de, 'variant>; fn variant_seed( self, seed: V, ) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { let str_de = StrDeserializer::::new(self.tag); let variant = seed.deserialize(str_de)?; let visitor = DeserializerFromEvents { document: self.de.document, pos: self.de.pos, jumpcount: self.de.jumpcount, path: self.de.path, remaining_depth: self.de.remaining_depth, current_enum: Some(CurrentEnum { name: self.name, tag: self.tag, }), }; Ok((variant, visitor)) } } impl<'de> de::VariantAccess<'de> for DeserializerFromEvents<'de, '_> { type Error = Error; fn unit_variant(mut self) -> Result<()> { Deserialize::deserialize(&mut self) } fn newtype_variant_seed(mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { seed.deserialize(&mut self) } fn tuple_variant( mut self, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_seq(&mut self, visitor) } fn struct_variant( mut self, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_struct( &mut self, "", fields, visitor, ) } } struct UnitVariantAccess<'de, 'document, 'variant> { de: &'variant mut DeserializerFromEvents<'de, 'document>, } impl<'de> de::EnumAccess<'de> for UnitVariantAccess<'de, '_, '_> { type Error = Error; type Variant = Self; fn variant_seed( self, seed: V, ) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { Ok((seed.deserialize(&mut *self.de)?, self)) } } impl<'de> de::VariantAccess<'de> for UnitVariantAccess<'de, '_, '_> { type Error = Error; fn unit_variant(self) -> Result<()> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: DeserializeSeed<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"newtype variant", )) } fn tuple_variant( self, _len: usize, _visitor: V, ) -> Result where V: Visitor<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"tuple variant", )) } fn struct_variant( self, _fields: &'static [&'static str], _visitor: V, ) -> Result where V: Visitor<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"struct variant", )) } } fn visit_scalar<'de, V>( visitor: V, scalar: &Scalar<'de>, tagged_already: bool, ) -> Result where V: Visitor<'de>, { let v = match str::from_utf8(&scalar.value) { Ok(v) => v, Err(_) => { return Err(de::Error::invalid_type( Unexpected::Bytes(&scalar.value), &visitor, )) } }; if let (Some(tag), false) = (&scalar.tag, tagged_already) { if tag == Tag::BOOL { return match parse_bool(v) { Some(v) => visitor.visit_bool(v), None => Err(de::Error::invalid_value( Unexpected::Str(v), &"a boolean", )), }; } else if tag == Tag::INT { return match visit_int(visitor, v) { Ok(result) => result, Err(_) => Err(de::Error::invalid_value( Unexpected::Str(v), &"an integer", )), }; } else if tag == Tag::FLOAT { return match parse_f64(v) { Some(v) => visitor.visit_f64(v), None => Err(de::Error::invalid_value( Unexpected::Str(v), &"a float", )), }; } else if tag == Tag::NULL { return match parse_null(v.as_bytes()) { Some(()) => visitor.visit_unit(), None => Err(de::Error::invalid_value( Unexpected::Str(v), &"null", )), }; } else if let Ok(true) = tag.starts_with("!") { if scalar.style == ScalarStyle::Plain { return visit_untagged_scalar( visitor, v, scalar.repr, scalar.style, ); } } } else if scalar.style == ScalarStyle::Plain { return visit_untagged_scalar( visitor, v, scalar.repr, scalar.style, ); } if let Some(borrowed) = parse_borrowed_str(v, scalar.repr, scalar.style) { visitor.visit_borrowed_str(borrowed) } else { visitor.visit_str(v) } } fn parse_borrowed_str<'de>( utf8_value: &str, repr: Option<&'de [u8]>, style: ScalarStyle, ) -> Option<&'de str> { let borrowed_repr = repr?; let expected_offset = match style { ScalarStyle::Plain => 0, ScalarStyle::SingleQuoted | ScalarStyle::DoubleQuoted => 1, ScalarStyle::Literal | ScalarStyle::Folded => return None, }; let expected_end = borrowed_repr.len().checked_sub(expected_offset)?; let expected_start = expected_end.checked_sub(utf8_value.len())?; let borrowed_bytes = borrowed_repr.get(expected_start..expected_end)?; if borrowed_bytes == utf8_value.as_bytes() { return Some(unsafe { str::from_utf8_unchecked(borrowed_bytes) }); } None } fn parse_null(scalar: &[u8]) -> Option<()> { match scalar { b"null" | b"Null" | b"NULL" | b"~" => Some(()), _ => None, } } fn parse_bool(scalar: &str) -> Option { match scalar { "true" | "True" | "TRUE" => Some(true), "false" | "False" | "FALSE" => Some(false), _ => None, } } fn parse_unsigned_int( scalar: &str, from_str_radix: fn(&str, radix: u32) -> Result, ) -> Option { let unpositive = scalar.strip_prefix('+').unwrap_or(scalar); if let Some(rest) = unpositive.strip_prefix("0x") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 16) { return Some(int); } } if let Some(rest) = unpositive.strip_prefix("0o") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 8) { return Some(int); } } if let Some(rest) = unpositive.strip_prefix("0b") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 2) { return Some(int); } } if unpositive.starts_with(['+', '-']) { return None; } if digits_but_not_number(scalar) { return None; } from_str_radix(unpositive, 10).ok() } fn parse_signed_int( scalar: &str, from_str_radix: fn(&str, radix: u32) -> Result, ) -> Option { let unpositive = if let Some(unpositive) = scalar.strip_prefix('+') { if unpositive.starts_with(['+', '-']) { return None; } unpositive } else { scalar }; if let Some(rest) = unpositive.strip_prefix("0x") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 16) { return Some(int); } } if let Some(rest) = scalar.strip_prefix("-0x") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 16) { return Some(int); } } if let Some(rest) = unpositive.strip_prefix("0o") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 8) { return Some(int); } } if let Some(rest) = scalar.strip_prefix("-0o") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 8) { return Some(int); } } if let Some(rest) = unpositive.strip_prefix("0b") { if rest.starts_with(['+', '-']) { return None; } if let Ok(int) = from_str_radix(rest, 2) { return Some(int); } } if let Some(rest) = scalar.strip_prefix("-0b") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 2) { return Some(int); } } if digits_but_not_number(scalar) { return None; } from_str_radix(unpositive, 10).ok() } fn parse_negative_int( scalar: &str, from_str_radix: fn(&str, radix: u32) -> Result, ) -> Option { if let Some(rest) = scalar.strip_prefix("-0x") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 16) { return Some(int); } } if let Some(rest) = scalar.strip_prefix("-0o") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 8) { return Some(int); } } if let Some(rest) = scalar.strip_prefix("-0b") { let negative = format!("-{}", rest); if let Ok(int) = from_str_radix(&negative, 2) { return Some(int); } } if digits_but_not_number(scalar) { return None; } from_str_radix(scalar, 10).ok() } pub(crate) fn parse_f64(scalar: &str) -> Option { let unpositive = if let Some(unpositive) = scalar.strip_prefix('+') { if unpositive.starts_with(['+', '-']) { return None; } unpositive } else { scalar }; if let ".inf" | ".Inf" | ".INF" = unpositive { return Some(f64::INFINITY); } if let "-.inf" | "-.Inf" | "-.INF" = scalar { return Some(f64::NEG_INFINITY); } if let ".nan" | ".NaN" | ".NAN" = scalar { return Some(f64::NAN.copysign(1.0)); } if let Ok(float) = unpositive.parse::() { if float.is_finite() { return Some(float); } } None } pub(crate) fn digits_but_not_number(scalar: &str) -> bool { // Leading zero(s) followed by numeric characters is a string according to // the YAML 1.2 spec. https://yaml.org/spec/1.2/spec.html#id2761292 let scalar = scalar.strip_prefix(['-', '+']).unwrap_or(scalar); scalar.len() > 1 && scalar.starts_with('0') && scalar[1..].bytes().all(|b| b.is_ascii_digit()) } /// If a string looks like it could be parsed as some other type by some YAML /// parser on the round trip, or could otherwise be ambiguous, then we should /// serialize it with quotes to be safe. /// This avoids the norway problem https://hitchdev.com/strictyaml/why/implicit-typing-removed/ #[allow(clippy::needless_borrow)] #[allow(clippy::len_zero)] #[allow(clippy::bytes_nth)] pub(crate) fn ambiguous_string(scalar: &str) -> bool { let lower_scalar = scalar.to_lowercase(); parse_bool(&lower_scalar).is_some() || parse_null(&lower_scalar.as_bytes()).is_some() || lower_scalar.len() == 0 // Can unwrap because we just checked the length. || lower_scalar.bytes().nth(0).unwrap().is_ascii_digit() || lower_scalar.starts_with('-') || lower_scalar.starts_with('.') || lower_scalar.starts_with('+') // Things that we don't parse as bool but could be parsed as bool by // other YAML parsers. || lower_scalar == "y" || lower_scalar == "yes" || lower_scalar == "n" || lower_scalar == "no" || lower_scalar == "on" || lower_scalar == "off" || lower_scalar == "true" || lower_scalar == "false" || lower_scalar == "null" || lower_scalar == "nil" || lower_scalar == "~" || lower_scalar == "nan" } pub(crate) fn visit_int<'de, V>( visitor: V, v: &str, ) -> Result, V> where V: Visitor<'de>, { if let Some(int) = parse_unsigned_int(v, u64::from_str_radix) { return Ok(visitor.visit_u64(int)); } if let Some(int) = parse_negative_int(v, i64::from_str_radix) { return Ok(visitor.visit_i64(int)); } if let Some(int) = parse_unsigned_int(v, u128::from_str_radix) { return Ok(visitor.visit_u128(int)); } if let Some(int) = parse_negative_int(v, i128::from_str_radix) { return Ok(visitor.visit_i128(int)); } Err(visitor) } pub(crate) fn visit_untagged_scalar<'de, V>( visitor: V, v: &str, repr: Option<&'de [u8]>, style: ScalarStyle, ) -> Result where V: Visitor<'de>, { if v.is_empty() || parse_null(v.as_bytes()) == Some(()) { return visitor.visit_unit(); } if let Some(boolean) = parse_bool(v) { return visitor.visit_bool(boolean); } let visitor = match visit_int(visitor, v) { Ok(result) => return result, Err(visitor) => visitor, }; if !digits_but_not_number(v) { if let Some(float) = parse_f64(v) { return visitor.visit_f64(float); } } if let Some(borrowed) = parse_borrowed_str(v, repr, style) { visitor.visit_borrowed_str(borrowed) } else { visitor.visit_str(v) } } fn is_plain_or_tagged_literal_scalar( expected: &str, scalar: &Scalar<'_>, tagged_already: bool, ) -> bool { match (scalar.style, &scalar.tag, tagged_already) { (ScalarStyle::Plain, _, _) => true, (ScalarStyle::Literal, Some(tag), false) => tag == expected, _ => false, } } fn invalid_type(event: &Event<'_>, exp: &dyn Expected) -> Error { struct InvalidType<'a> { exp: &'a dyn Expected, } impl Visitor<'_> for InvalidType<'_> { type Value = (); fn expecting( &self, formatter: &mut Formatter<'_>, ) -> fmt::Result { self.exp.fmt(formatter) } } match event { Event::Alias(_) => unreachable!(), // If you expect this case to be unreachable, it's fine to leave. Event::Scalar(scalar) => { let get_type = InvalidType { exp }; visit_scalar(get_type, scalar, false).unwrap_err() } Event::SequenceStart(_) => { de::Error::invalid_type(Unexpected::Seq, exp) } Event::MappingStart(_) => { de::Error::invalid_type(Unexpected::Map, exp) } Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), Event::Void => error::new(ErrorImpl::EndOfStream), } } fn parse_tag(libyml_tag: &Option) -> Option<&str> { let mut bytes: &[u8] = libyml_tag.as_ref()?; if let (b'!', rest) = bytes.split_first()? { if !rest.is_empty() { bytes = rest; } str::from_utf8(bytes).ok() } else { None } } impl<'de> de::Deserializer<'de> for &mut DeserializerFromEvents<'de, '_> { type Error = Error; #[deny(clippy::never_loop)] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; fn enum_tag( tag: &Option, tagged_already: bool, ) -> Option<&str> { if tagged_already { return None; } parse_tag(tag) } #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self.jump(&mut pos)?.deserialize_any(visitor) } Event::Scalar(scalar) => { if let Some(tag) = enum_tag(&scalar.tag, tagged_already) { *self.pos -= 1; break visitor.visit_enum(EnumAccess { de: self, name: None, tag, }); } break visit_scalar( visitor, scalar, tagged_already, ); } Event::SequenceStart(sequence) => { if let Some(tag) = enum_tag(&sequence.tag, tagged_already) { *self.pos -= 1; break visitor.visit_enum(EnumAccess { de: self, name: None, tag, }); } break self.visit_sequence(visitor, mark); } Event::MappingStart(mapping) => { if let Some(tag) = enum_tag(&mapping.tag, tagged_already) { *self.pos -= 1; break visitor.visit_enum(EnumAccess { de: self, name: None, tag, }); } break self.visit_mapping(visitor, mark); } Event::SequenceEnd => { panic!("unexpected end of sequence") } Event::MappingEnd => { panic!("unexpected end of mapping") } Event::Void => break visitor.visit_none(), } } // The de::Error impl creates errors with unknown line and column. Fill // in the position here by looking at the current index in the input. .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self .jump(&mut pos)? .deserialize_bool(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::BOOL, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(boolean) = parse_bool(value) { break visitor.visit_bool(boolean); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_i64(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_i64(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_i64(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self.jump(&mut pos)?.deserialize_i64(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::INT, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(int) = parse_signed_int(value, i64::from_str_radix) { break visitor.visit_i64(int); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self .jump(&mut pos)? .deserialize_i128(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::INT, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(int) = parse_signed_int( value, i128::from_str_radix, ) { break visitor.visit_i128(int); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_u64(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_u64(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_u64(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self.jump(&mut pos)?.deserialize_u64(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::INT, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(int) = parse_unsigned_int( value, u64::from_str_radix, ) { break visitor.visit_u64(int); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self .jump(&mut pos)? .deserialize_u128(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::INT, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(int) = parse_unsigned_int( value, u128::from_str_radix, ) { break visitor.visit_u128(int); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_f64(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; #[allow(clippy::never_loop)] loop { match next { Event::Alias(mut pos) => { break self.jump(&mut pos)?.deserialize_f64(visitor) } Event::Scalar(scalar) if is_plain_or_tagged_literal_scalar( Tag::FLOAT, scalar, tagged_already, ) => { if let Ok(value) = str::from_utf8(&scalar.value) { if let Some(float) = parse_f64(value) { break visitor.visit_f64(float); } } } _ => {} } break Err(invalid_type(next, &visitor)); } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, mark) = self.next_event_mark()?; match next { Event::Scalar(scalar) => { if let Ok(v) = str::from_utf8(&scalar.value) { if let Some(borrowed) = parse_borrowed_str(v, scalar.repr, scalar.style) { visitor.visit_borrowed_str(borrowed) } else { visitor.visit_str(v) } } else { Err(invalid_type(next, &visitor)) } } Event::Alias(mut pos) => { self.jump(&mut pos)?.deserialize_str(visitor) } other => Err(invalid_type(other, &visitor)), } .map_err(|err: Error| error::fix_mark(err, mark, self.path)) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_bytes(self, _visitor: V) -> Result where V: Visitor<'de>, { Err(error::new(ErrorImpl::BytesUnsupported)) } fn deserialize_byte_buf(self, _visitor: V) -> Result where V: Visitor<'de>, { Err(error::new(ErrorImpl::BytesUnsupported)) } /// Parses `null` as None and any other values as `Some(...)`. fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { let is_some = match self.peek_event()? { Event::Alias(mut pos) => { *self.pos += 1; return self .jump(&mut pos)? .deserialize_option(visitor); } Event::Scalar(scalar) => { let tagged_already = self.current_enum.is_some(); if scalar.style != ScalarStyle::Plain { true } else if let (Some(tag), false) = (&scalar.tag, tagged_already) { if tag == Tag::NULL { if let Some(()) = parse_null(&scalar.value) { false } else if let Ok(v) = str::from_utf8(&scalar.value) { return Err(de::Error::invalid_value( Unexpected::Str(v), &"null", )); } else { return Err(de::Error::invalid_value( Unexpected::Bytes(&scalar.value), &"null", )); } } else { true } } else { !scalar.value.is_empty() && parse_null(&scalar.value).is_none() } } Event::SequenceStart(_) | Event::MappingStart(_) => true, Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), Event::Void => false, }; if is_some { visitor.visit_some(self) } else { *self.pos += 1; self.current_enum = None; visitor.visit_none() } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { let tagged_already = self.current_enum.is_some(); let (next, mark) = self.next_event_mark()?; match next { Event::Scalar(scalar) => { let is_null = if scalar.style != ScalarStyle::Plain { false } else if let (Some(tag), false) = (&scalar.tag, tagged_already) { tag == Tag::NULL && parse_null(&scalar.value).is_some() } else { scalar.value.is_empty() || parse_null(&scalar.value).is_some() }; if is_null { visitor.visit_unit() } else if let Ok(v) = str::from_utf8(&scalar.value) { Err(de::Error::invalid_value( Unexpected::Str(v), &"null", )) } else { Err(de::Error::invalid_value( Unexpected::Bytes(&scalar.value), &"null", )) } } Event::Alias(mut pos) => { self.jump(&mut pos)?.deserialize_unit(visitor) } Event::Void => visitor.visit_unit(), other => Err(invalid_type(other, &visitor)), } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_unit_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } /// Parses a newtype struct as the underlying value. fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { let (_event, mark) = self.peek_event_mark()?; self.recursion_check(mark, |de| { visitor.visit_newtype_struct(de) }) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, mark) = self.next_event_mark()?; match next { Event::Alias(mut pos) => { self.jump(&mut pos)?.deserialize_seq(visitor) } Event::SequenceStart(_) => { self.visit_sequence(visitor, mark) } other => { if match other { Event::Void => true, Event::Scalar(scalar) => { scalar.value.is_empty() && scalar.style == ScalarStyle::Plain } _ => false, } { visitor.visit_seq(SeqAccess { empty: true, de: self, len: 0, }) } else { Err(invalid_type(other, &visitor)) } } } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_tuple( self, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, mark) = self.next_event_mark()?; match next { Event::Alias(mut pos) => { self.jump(&mut pos)?.deserialize_map(visitor) } Event::MappingStart(_) => self.visit_mapping(visitor, mark), other => { if match other { Event::Void => true, Event::Scalar(scalar) => { scalar.value.is_empty() && scalar.style == ScalarStyle::Plain } _ => false, } { visitor.visit_map(MapAccess { empty: true, de: self, len: 0, key: None, }) } else { Err(invalid_type(other, &visitor)) } } } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_map(visitor) } /// Parses an enum as a single key:value pair where the key identifies the /// variant and the value gives the content. A String will also parse correctly /// to a unit enum value. fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let (next, mark) = self.peek_event_mark()?; #[allow(clippy::never_loop)] loop { if let Some(current_enum) = self.current_enum { if let Event::Scalar(scalar) = next { if !scalar.value.is_empty() { break visitor.visit_enum(UnitVariantAccess { de: self }); } } let message = if let Some(name) = current_enum.name { format!( "deserializing nested enum in {}::{} from YAML is not supported yet", name, current_enum.tag, ) } else { format!( "deserializing nested enum in !{} from YAML is not supported yet", current_enum.tag, ) }; break Err(error::new(ErrorImpl::Message(message, None))); } break match next { Event::Alias(mut pos) => { *self.pos += 1; self.jump(&mut pos)? .deserialize_enum(name, variants, visitor) } Event::Scalar(scalar) => { if let Some(tag) = parse_tag(&scalar.tag) { return visitor.visit_enum(EnumAccess { de: self, name: Some(name), tag, }); } visitor.visit_enum(UnitVariantAccess { de: self }) } Event::MappingStart(mapping) => { if let Some(tag) = parse_tag(&mapping.tag) { return visitor.visit_enum(EnumAccess { de: self, name: Some(name), tag, }); } let err = de::Error::invalid_type(Unexpected::Map, &"a YAML tag starting with '!'"); Err(error::fix_mark(err, mark, self.path)) } Event::SequenceStart(sequence) => { if let Some(tag) = parse_tag(&sequence.tag) { return visitor.visit_enum(EnumAccess { de: self, name: Some(name), tag, }); } let err = de::Error::invalid_type(Unexpected::Seq, &"a YAML tag starting with '!'"); Err(error::fix_mark(err, mark, self.path)) } Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), Event::Void => Err(error::new(ErrorImpl::EndOfStream)), }; } .map_err(|err| error::fix_mark(err, mark, self.path)) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.ignore_any()?; visitor.visit_unit() } } /// Deserialize an instance of type `T` from a string of YAML text. /// /// This function takes a string slice containing YAML data and attempts to parse and /// deserialize it into an instance of the type `T`. The type must implement the `Deserialize` /// trait from Serde. /// /// # Errors /// /// This conversion can fail if the structure of the YAML does not match the structure expected /// by `T`, for example if `T` is a struct type but the YAML contains something other than a /// mapping. It can also fail if the structure is correct but `T`'s implementation of /// `Deserialize` decides that something is wrong with the data, for example required struct /// fields are missing from the YAML mapping or some number is too big to fit in the expected /// primitive type. /// /// # Examples /// /// ``` /// use serde::Deserialize; /// /// #[derive(Debug, Deserialize)] /// struct Person { /// name: String, /// age: u32, /// } /// /// let yaml_str = r#" /// name: John Doe /// age: 30 /// "#; /// /// let person: Person = serde_yml::from_str(yaml_str).unwrap(); /// println!("{:?}", person); /// ``` pub fn from_str<'de, T>(s: &'de str) -> Result where T: Deserialize<'de>, { T::deserialize(Deserializer::from_str(s)) } /// Deserialize an instance of type `T` from an IO stream of YAML. /// /// This function reads YAML data from an IO stream and attempts to parse and deserialize it /// into an instance of the type `T`. The type must implement the `DeserializeOwned` trait /// from Serde, which means it must be able to be deserialized without any borrowed data. /// /// # Errors /// /// This conversion can fail if the structure of the YAML does not match the structure expected /// by `T`, for example if `T` is a struct type but the YAML contains something other than a /// mapping. It can also fail if the structure is correct but `T`'s implementation of /// `Deserialize` decides that something is wrong with the data, for example required struct /// fields are missing from the YAML mapping or some number is too big to fit in the expected /// primitive type. /// /// # Examples /// /// ``` /// use serde::Deserialize; /// use std::io::Cursor; /// /// #[derive(Debug, Deserialize)] /// struct Config { /// debug: bool, /// port: u16, /// } /// /// let yaml_data = br#" /// debug: true /// port: 8080 /// "#; /// /// let reader = Cursor::new(yaml_data); /// let config: Config = serde_yml::from_reader(reader).unwrap(); /// println!("{:?}", config); /// ``` pub fn from_reader(rdr: R) -> Result where R: io::Read, T: DeserializeOwned, { T::deserialize(Deserializer::from_reader(rdr)) } /// Deserialize an instance of type `T` from bytes of YAML text. /// /// This function takes a byte slice containing YAML data and attempts to parse and /// deserialize it into an instance of the type `T`. The type must implement the `Deserialize` /// trait from Serde. /// /// # Errors /// /// This conversion can fail if the structure of the YAML does not match the structure expected /// by `T`, for example if `T` is a struct type but the YAML contains something other than a /// mapping. It can also fail if the structure is correct but `T`'s implementation of /// `Deserialize` decides that something is wrong with the data, for example required struct /// fields are missing from the YAML mapping or some number is too big to fit in the expected /// primitive type. /// /// # Examples /// /// ``` /// use serde::Deserialize; /// /// #[derive(Debug, Deserialize)] /// struct Point { /// x: i32, /// y: i32, /// } /// /// let yaml_data = br#" /// x: 10 /// y: 20 /// "#; /// /// let point: Point = serde_yml::from_slice(yaml_data).unwrap(); /// println!("{:?}", point); /// ``` pub fn from_slice<'de, T>(v: &'de [u8]) -> Result where T: Deserialize<'de>, { T::deserialize(Deserializer::from_slice(v)) } serde_yml-0.0.12/src/lib.rs000064400000000000000000000151701046102023000135760ustar 00000000000000//!# Serde YML (a fork of Serde YAML) //! //![![Made With Love][made-with-rust]][11] [![Crates.io][crates-badge]][07] [![lib.rs][libs-badge]][12] [![Docs.rs][docs-badge]][08] [![Codecov][codecov-badge]][09] [![Build Status][build-badge]][10] [![GitHub][github-badge]][06] //! //![Serde YML][00] is a Rust library for using the [Serde][01] serialization framework with data in [YAML][05] file format. //! //! ## Features //! //! - Serialization and deserialization of Rust data structures to/from YAML format //! - Support for custom structs and enums using Serde's derive macros //! - Handling of YAML's `!tag` syntax for representing enum variants //! - Direct access to YAML values through the `Value` type and related types like `Mapping` and `Sequence` //! - Comprehensive error handling with `Error`, `Location`, and `Result` types //! - Serialization to YAML using `to_string` and `to_writer` functions //! - Deserialization from YAML using `from_str`, `from_slice`, and `from_reader` functions //! - Customizable serialization and deserialization behavior using Serde's `#[serde(with = ...)]` attribute //! - Support for serializing/deserializing enums using a YAML map with a single key-value pair through the `singleton_map` module //! - Recursive application of `singleton_map` serialization/deserialization to all enums within a data structure using the `singleton_map_recursive` module //! - Serialization and deserialization of optional enum fields using the `singleton_map_optional` module //! - Handling of nested enum structures with optional inner enums using the `singleton_map_recursive` module //! - Customization of serialization and deserialization logic for enums using the `singleton_map_with` module and custom helper functions //! //!## Installation //! //!Add this to your `Cargo.toml`: //! //!```toml //![dependencies] //!serde = "1.0" //!serde_yml = "0.0.12" //!``` //! //!## Usage //! //!Here's a quick example on how to use Serde YML to serialize and deserialize a struct to and from YAML: //! //!```rust //!use serde::{Serialize, Deserialize}; //! //!#[derive(Debug, PartialEq, Serialize, Deserialize)] //!struct Point { //! x: f64, //! y: f64, //!} //! //!fn main() -> Result<(), serde_yml::Error> { //! let point = Point { x: 1.0, y: 2.0 }; //! //! // Serialize to YAML //! let yaml = serde_yml::to_string(&point)?; //! assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); //! //! // Deserialize from YAML //! let deserialized_point: Point = serde_yml::from_str(&yaml)?; //! assert_eq!(point, deserialized_point); //! //! Ok(()) //!} //!``` //! //!## Documentation //! //!For full API documentation, please visit [https://doc.libyml.com/serde-yaml/][04] or [https://docs.rs/serde-yaml][08]. //! //!## Rust Version Compatibility //! //!Compiler support: requires rustc 1.56.0+ //! //! ## Examples //! //! Serde YML provides a set of comprehensive examples to demonstrate its usage and capabilities. You can find them in the `examples` directory of the project. //! //! To run the examples, clone the repository and execute the following command in your terminal from the project root directory: //! //! ```shell //! cargo run --example example //! ``` //! //! The examples cover various scenarios, including serializing and deserializing structs, enums, optional fields, custom structs, and more. //! //! [00]: https://serdeyml.com //! [01]: https://github.com/serde-rs/serde //! [02]: https://github.com/dtolnay/serde-yaml //! [03]: https://github.com/dtolnay //! [04]: https://doc.libyml.com/serde-yaml/ //! [05]: https://yaml.org/ //! [06]: https://github.com/sebastienrousseau/serde_yml //! [07]: https://crates.io/crates/serde_yml //! [08]: https://docs.rs/serde_yml //! [09]: https://codecov.io/gh/sebastienrousseau/serde_yml //! [10]: https://github.com/sebastienrousseau/serde-yml/actions?query=branch%3Amaster //! [11]: https://www.rust-lang.org/ //! [12]: https://lib.rs/crates/serde_yml //! [build-badge]: https://img.shields.io/github/actions/workflow/status/sebastienrousseau/serde_yml/release.yml?branch=master&style=for-the-badge&logo=github "Build Status" //! [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/serde_yml?style=for-the-badge&token=Q9KJ6XXL67&logo=codecov "Codecov" //! [crates-badge]: https://img.shields.io/crates/v/serde_yml.svg?style=for-the-badge&color=fc8d62&logo=rust "Crates.io" //! [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.12-orange.svg?style=for-the-badge "View on lib.rs" //! [docs-badge]: https://img.shields.io/badge/docs.rs-serde__yml-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs "Docs.rs" //! [github-badge]: https://img.shields.io/badge/github-sebastienrousseau/serde--yml-8da0cb?style=for-the-badge&labelColor=555555&logo=github "GitHub" //! [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' //! //! #![deny(missing_docs)] #![doc( html_favicon_url = "https://kura.pro/serde_yml/images/favicon.ico", html_logo_url = "https://kura.pro/serde_yml/images/logos/serde_yml.svg", html_root_url = "https://docs.rs/serde_yml" )] #![crate_name = "serde_yml"] #![crate_type = "lib"] // Re-export commonly used items from other modules pub use crate::de::{from_reader, from_slice, from_str, Deserializer}; // Deserialization functions pub use crate::modules::error::{Error, Location, Result}; // Error handling types pub use crate::ser::{to_string, to_writer, Serializer, State}; // Serialization functions #[doc(inline)] pub use crate::value::{ from_value, to_value, Index, Number, Sequence, Value, }; // Value manipulation functions #[doc(inline)] pub use crate::mapping::Mapping; // Re-export the Mapping type for YAML mappings /// The `de` module contains the library's YAML deserializer. pub mod de; /// The `libyml` module contains the library's YAML parser and emitter. pub mod libyml; /// The `loader` module contains the `Loader` type for YAML loading. pub mod loader; /// The `mapping` module contains the `Mapping` type for YAML mappings. pub mod mapping; /// The `modules` module contains the library's modules. pub mod modules; /// The `number` module contains the `Number` type for YAML numbers. pub mod number; /// The `ser` module contains the library's YAML serializer. pub mod ser; /// The `value` module contains the `Value` type for YAML values. pub mod value; /// The `with` module contains the `With` type for YAML values. pub mod with; // Prevent downstream code from implementing the Index trait. mod private { pub trait Sealed {} impl Sealed for usize {} impl Sealed for str {} impl Sealed for String {} impl Sealed for crate::Value {} impl Sealed for &T where T: ?Sized + Sealed {} } serde_yml-0.0.12/src/libyml/emitter.rs000064400000000000000000000274251046102023000157770ustar 00000000000000use crate::libyml::{self, util::Owned}; use ::libyml::api::ScalarEventData; use ::libyml::document::{ yaml_document_end_event_initialize, yaml_document_start_event_initialize, }; use ::libyml::YamlEventT; use ::libyml::YamlScalarStyleT::YamlLiteralScalarStyle; use ::libyml::{ yaml_emitter_delete, yaml_emitter_emit, yaml_emitter_flush, yaml_emitter_initialize, yaml_emitter_set_output, yaml_emitter_set_unicode, yaml_emitter_set_width, yaml_mapping_end_event_initialize, yaml_mapping_start_event_initialize, yaml_scalar_event_initialize, yaml_sequence_end_event_initialize, yaml_sequence_start_event_initialize, yaml_stream_end_event_initialize, yaml_stream_start_event_initialize, YamlAnyMappingStyle, YamlAnySequenceStyle, YamlEmitterT, YamlScalarStyleT, YamlSingleQuotedScalarStyle, YamlUtf8Encoding, }; use std::fmt::Debug; #[allow(clippy::unsafe_removed_from_name)] use std::{ ffi::c_void, io, mem::{self, MaybeUninit}, ptr::{self, addr_of_mut}, slice, }; /// Errors that can occur during YAML emission. #[derive(Debug)] pub enum Error { /// Errors related to libyml. Libyml(libyml::error::Error), /// I/O errors. Io(io::Error), } /// A YAML emitter. #[derive(Debug)] pub struct Emitter<'a> { pin: Owned>, } /// Represents a pinned emitter for YAML serialization. /// /// The `EmitterPinned` struct contains the necessary state and resources /// for emitting YAML documents. It is pinned to a specific lifetime `'a` /// to ensure that the `write` field remains valid throughout the lifetime /// of the emitter. /// /// # Fields /// /// - `sys`: An instance of `YamlEmitterT` representing the underlying /// emitter system. /// - `write`: A boxed trait object implementing the `io::Write` trait, /// used for writing the emitted YAML data. It is pinned to the lifetime /// `'a` to ensure it remains valid for the duration of the emitter's /// lifetime. /// - `write_error`: An optional `io::Error` used to store any errors that /// occur during the writing process. /// /// # Lifetime /// /// The `EmitterPinned` struct is parameterized by a lifetime `'a`, which /// represents the lifetime of the `write` field. This ensures that the /// `write` field remains valid for the entire lifetime of the `EmitterPinned` /// instance. pub struct EmitterPinned<'a> { sys: YamlEmitterT, write: Box, write_error: Option, } impl Debug for EmitterPinned<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EmitterPinned") .field("sys", &self.sys) .field("write_error", &self.write_error) .finish() } } /// YAML event types. #[derive(Debug)] pub enum Event<'a> { /// Start of a YAML stream. StreamStart, /// End of a YAML stream. StreamEnd, /// Start of a YAML document. DocumentStart, /// End of a YAML document. DocumentEnd, /// Scalar value. Scalar(Scalar<'a>), /// Start of a sequence. SequenceStart(Sequence), /// End of a sequence. SequenceEnd, /// Start of a mapping. MappingStart(Mapping), /// End of a mapping. MappingEnd, } /// Represents a scalar value in YAML. #[derive(Debug)] pub struct Scalar<'a> { /// Optional tag for the scalar. pub tag: Option, /// Value of the scalar. pub value: &'a str, /// Style of the scalar. pub style: ScalarStyle, } /// Styles for YAML scalars. #[derive(Clone, Copy, Debug)] pub enum ScalarStyle { /// Any scalar style. Any, /// Double quoted scalar style. DoubleQuoted, /// Folded scalar style. Folded, /// Plain scalar style. Plain, /// Single quoted scalar style. SingleQuoted, /// Literal scalar style. Literal, } /// Represents a YAML sequence. #[derive(Debug)] pub struct Sequence { /// Optional tag for the sequence. pub tag: Option, } /// Represents a YAML mapping. #[derive(Debug)] pub struct Mapping { /// Optional tag for the mapping. pub tag: Option, } impl<'a> Emitter<'a> { /// Creates a new YAML emitter. pub fn new(write: Box) -> Emitter<'a> { let owned = Owned::>::new_uninit(); let pin = unsafe { let emitter = addr_of_mut!((*owned.ptr).sys); if yaml_emitter_initialize(emitter).fail { panic!( "malloc error: {}", libyml::Error::emit_error(emitter) ); } yaml_emitter_set_unicode(emitter, true); yaml_emitter_set_width(emitter, -1); addr_of_mut!((*owned.ptr).write).write(write); addr_of_mut!((*owned.ptr).write_error).write(None); yaml_emitter_set_output( emitter, write_handler, owned.ptr.cast(), ); Owned::assume_init(owned) }; Emitter { pin } } /// Emits a YAML event. pub fn emit(&mut self, event: Event<'_>) -> Result<(), Error> { let mut sys_event = MaybeUninit::::uninit(); let sys_event = sys_event.as_mut_ptr(); unsafe { let emitter = addr_of_mut!((*self.pin.ptr).sys); let initialize_status = match event { Event::StreamStart => { yaml_stream_start_event_initialize( sys_event, YamlUtf8Encoding, ) } Event::StreamEnd => { yaml_stream_end_event_initialize(sys_event) } Event::DocumentStart => { let version_directive = ptr::null_mut(); let tag_directives_start = ptr::null_mut(); let tag_directives_end = ptr::null_mut(); let implicit = true; yaml_document_start_event_initialize( sys_event, version_directive, tag_directives_start, tag_directives_end, implicit, ) } Event::DocumentEnd => { let implicit = true; yaml_document_end_event_initialize( sys_event, implicit, ) } Event::Scalar(mut scalar) => { let tag_ptr = scalar.tag.as_mut().map_or_else( ptr::null, |tag| { tag.push('\0'); tag.as_ptr() }, ); let value_ptr = scalar.value.as_ptr(); let length = scalar.value.len() as i32; let plain_implicit = tag_ptr.is_null(); let quoted_implicit = tag_ptr.is_null(); let style = match scalar.style { ScalarStyle::Any => { YamlScalarStyleT::YamlAnyScalarStyle } ScalarStyle::DoubleQuoted => { YamlScalarStyleT::YamlDoubleQuotedScalarStyle } ScalarStyle::Folded => { YamlScalarStyleT::YamlFoldedScalarStyle } ScalarStyle::Plain => { YamlScalarStyleT::YamlPlainScalarStyle } ScalarStyle::SingleQuoted => { YamlSingleQuotedScalarStyle } ScalarStyle::Literal => YamlLiteralScalarStyle, }; let event_data = ScalarEventData { anchor: ptr::null(), tag: tag_ptr, value: value_ptr, length, plain_implicit, quoted_implicit, style, _marker: core::marker::PhantomData, }; yaml_scalar_event_initialize(sys_event, event_data) } Event::SequenceStart(mut sequence) => { let tag_ptr = sequence.tag.as_mut().map_or_else( ptr::null, |tag| { tag.push('\0'); tag.as_ptr() }, ); let implicit = tag_ptr.is_null(); let style = YamlAnySequenceStyle; yaml_sequence_start_event_initialize( sys_event, ptr::null(), tag_ptr, implicit, style, ) } Event::SequenceEnd => { yaml_sequence_end_event_initialize(sys_event) } Event::MappingStart(mut mapping) => { let tag_ptr = mapping.tag.as_mut().map_or_else( ptr::null, |tag| { tag.push('\0'); tag.as_ptr() }, ); let implicit = tag_ptr.is_null(); let style = YamlAnyMappingStyle; yaml_mapping_start_event_initialize( sys_event, ptr::null(), tag_ptr, implicit, style, ) } Event::MappingEnd => { yaml_mapping_end_event_initialize(sys_event) } }; if initialize_status.fail { return Err(Error::Libyml(libyml::Error::emit_error( emitter, ))); } if yaml_emitter_emit(emitter, sys_event).fail { return Err(self.error()); } } Ok(()) } /// Flushes the YAML emitter. pub fn flush(&mut self) -> Result<(), Error> { unsafe { let emitter = addr_of_mut!((*self.pin.ptr).sys); if yaml_emitter_flush(emitter).fail { return Err(self.error()); } } Ok(()) } /// Retrieves the inner writer from the YAML emitter. #[allow(unused_mut)] 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. 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::Libyml(unsafe { libyml::Error::emit_error(&emitter.sys) }) } } } /// Writes data to a buffer using a provided callback function. unsafe fn write_handler( data: *mut c_void, buffer: *mut u8, size: u64, ) -> i32 { let data = data.cast::>(); match io::Write::write_all(unsafe { &mut *(*data).write }, unsafe { slice::from_raw_parts(buffer, size as usize) }) { Ok(()) => 1, Err(err) => { unsafe { (*data).write_error = Some(err); } 0 } } } impl Drop for EmitterPinned<'_> { /// Drops the YAML emitter, deallocating resources. fn drop(&mut self) { unsafe { yaml_emitter_delete(&mut self.sys) } } } serde_yml-0.0.12/src/libyml/error.rs000064400000000000000000000225431046102023000154530ustar 00000000000000use crate::libyml::safe_cstr::CStr; #[allow(clippy::unsafe_removed_from_name)] use libyml as sys; use std::{ fmt::{self, Debug, Display}, mem::MaybeUninit, ptr::NonNull, }; /// A type alias for a `Result` with an `Error` as the error type. pub type Result = std::result::Result; /// Represents an error that occurred during YAML processing. #[derive(Clone, Copy)] pub struct Error { /// The kind of error that occurred. /// /// This field uses the `yaml_error_type_t` type from the `libyml` crate, /// which represents different types of errors. 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. pub problem: CStr<'static>, /// The offset of the problem that caused the error. 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. 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. 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. pub context_mark: Mark, } impl Error { /// Constructs an `Error` from a `YamlParserT` pointer. /// /// # Safety /// /// This function is unsafe because it dereferences raw pointers and assumes /// the validity of the `YamlParserT` pointer. pub unsafe fn parse_error(parser: *const sys::YamlParserT) -> Self { Error { kind: unsafe { (*parser).error }, problem: match NonNull::new(unsafe { (*parser).problem as *mut _ }) { Some(problem) => CStr::from_ptr(problem), None => CStr::from_bytes_with_nul( b"libyml parser failed but there is no error\0", ) .expect("Error creating CStr from bytes"), }, problem_offset: unsafe { (*parser).problem_offset }, problem_mark: Mark { sys: unsafe { (*parser).problem_mark }, }, #[allow(clippy::manual_map)] context: match NonNull::new(unsafe { (*parser).context as *mut _ }) { Some(context) => Some(CStr::from_ptr(context)), None => None, }, context_mark: Mark { sys: unsafe { (*parser).context_mark }, }, } } /// Constructs an `Error` from a `YamlEmitterT` pointer. /// /// # Safety /// /// This function is unsafe because it dereferences raw pointers and assumes /// the validity of the `YamlEmitterT` pointer. pub unsafe fn emit_error( emitter: *const sys::YamlEmitterT, ) -> Self { Error { kind: unsafe { (*emitter).error }, problem: match NonNull::new(unsafe { (*emitter).problem as *mut _ }) { Some(problem) => CStr::from_ptr(problem), None => CStr::from_bytes_with_nul( b"libyml emitter failed but there is no error\0", ) .expect("Error creating CStr from bytes"), }, problem_offset: 0, problem_mark: Mark { sys: unsafe { MaybeUninit::::zeroed() .assume_init() }, }, context: None, context_mark: Mark { sys: unsafe { MaybeUninit::::zeroed() .assume_init() }, }, } } /// Returns the mark indicating the position of the problem that caused the error. pub fn mark(&self) -> Mark { self.problem_mark } } impl Display for Error { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "{}", self.problem)?; if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { write!(formatter, " at {}", self.problem_mark)?; } else if self.problem_offset != 0 { write!(formatter, " at position {}", self.problem_offset)?; } if let Some(context) = &self.context { write!(formatter, ", {}", context)?; if (self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0) && (self.context_mark.sys.line != self.problem_mark.sys.line || self.context_mark.sys.column != self.problem_mark.sys.column) { write!(formatter, " at {}", self.context_mark)?; } } Ok(()) } } impl Debug for Error { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let mut formatter = formatter.debug_struct("Error"); if let Some(kind) = match self.kind { sys::YamlMemoryError => Some("MEMORY"), sys::YamlReaderError => Some("READER"), sys::YamlScannerError => Some("SCANNER"), sys::YamlParserError => Some("PARSER"), sys::YamlComposerError => Some("COMPOSER"), sys::YamlWriterError => Some("WRITER"), sys::YamlEmitterError => Some("EMITTER"), _ => None, } { formatter.field("kind", &format_args!("{}", kind)); } formatter.field("problem", &self.problem); if self.problem_mark.sys.line != 0 || self.problem_mark.sys.column != 0 { formatter.field("problem_mark", &self.problem_mark); } else if self.problem_offset != 0 { formatter.field("problem_offset", &self.problem_offset); } if let Some(context) = &self.context { formatter.field("context", context); if self.context_mark.sys.line != 0 || self.context_mark.sys.column != 0 { formatter.field("context_mark", &self.context_mark); } } formatter.finish() } } /// Represents a mark in a YAML document. /// A mark indicates a specific position or location within the document. #[derive(Copy, Clone)] pub struct Mark { /// The underlying system representation of the 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 sys: sys::YamlMarkT, } impl Mark { /// Retrieves the index of the mark. /// /// The index represents the position of the mark within the YAML input. /// /// # Returns /// /// Returns the index of the mark as a `u64`. pub fn index(&self) -> u64 { self.sys.index } /// Retrieves the line number of the mark. /// /// The line number indicates the line in the YAML input where the mark is located. /// /// # Returns /// /// Returns the line number of the mark as a `u64`. pub fn line(&self) -> u64 { self.sys.line } /// Retrieves the column number of the mark. /// /// The column number indicates the column within the line where the mark is located. /// /// # Returns /// /// Returns the column number of the mark as a `u64`. pub fn column(&self) -> u64 { self.sys.column } } impl Display for Mark { /// Formats the mark for display purposes. /// /// If the line and column numbers are non-zero, the mark is formatted as "line X column Y". /// Otherwise, the mark is formatted as "position Z", where Z is the index. /// /// # Arguments /// /// * `formatter` - The formatter to write the display output to. /// /// # Returns /// /// Returns `Ok(())` if the formatting was successful, or an error otherwise. fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { if self.sys.line != 0 || self.sys.column != 0 { write!( formatter, "line {} column {}", self.sys.line + 1, self.sys.column + 1, ) } else { write!(formatter, "position {}", self.sys.index) } } } impl Debug for Mark { /// Formats the mark for debugging purposes. /// /// The mark is formatted as a debug struct with either the line and column numbers /// or the index, depending on their values. /// /// # Arguments /// /// * `formatter` - The formatter to write the debug output to. /// /// # Returns /// /// Returns `Ok(())` if the formatting was successful, or an error otherwise. fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let mut formatter = formatter.debug_struct("Mark"); if self.sys.line != 0 || self.sys.column != 0 { formatter.field("line", &(self.sys.line + 1)); formatter.field("column", &(self.sys.column + 1)); } else { formatter.field("index", &self.sys.index); } formatter.finish() } } serde_yml-0.0.12/src/libyml/mod.rs000064400000000000000000000003641046102023000150760ustar 00000000000000/// YAML emitter. pub mod emitter; /// Error handling. pub mod error; /// YAML parser. pub mod parser; /// C string handling. pub mod safe_cstr; /// Tag directive handling. pub mod tag; /// Utility types. pub mod util; use self::error::Error; serde_yml-0.0.12/src/libyml/parser.rs000064400000000000000000000274651046102023000156260ustar 00000000000000use crate::libyml::{ error::{Error, Mark, Result}, safe_cstr::{self, CStr}, tag::Tag, util::Owned, }; #[allow(clippy::unsafe_removed_from_name)] use libyml as sys; use std::{ borrow::Cow, fmt::{self, Debug}, mem::MaybeUninit, ptr::{addr_of_mut, NonNull}, slice, }; /// Represents a YAML parser. /// /// The `Parser` struct is responsible for parsing YAML input and generating a sequence /// of YAML events. It wraps the underlying `libyml` parser and provides a safe and /// convenient interface for parsing YAML documents. /// /// The `'input` lifetime parameter indicates the lifetime of the input data being parsed. /// It ensures that the `Parser` does not outlive the input data. #[derive(Debug)] pub struct Parser<'input> { /// The pinned parser state. /// /// The `Owned>` type represents an owned instance of the /// `ParserPinned` struct. The `Owned` type is used to provide pinning and /// allows the `Parser` to be safely moved around. /// /// The `ParserPinned` struct contains the underlying `libyml` parser state /// and the input data being parsed. /// /// Pinning is used to ensure that the `Parser` remains at a fixed memory /// location, which is required for safe interaction with the `libyml` library. pub pin: Owned>, } /// Represents a pinned parser for YAML deserialization. /// /// The `ParserPinned` struct contains the necessary state and resources /// 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, Clone)] pub struct ParserPinned<'input> { /// The underlying `YamlParserT` struct from the `libyml` library. pub sys: sys::YamlParserT, /// The input data being parsed. pub input: Cow<'input, [u8]>, } /// Represents a YAML event encountered during parsing. #[derive(Debug)] pub enum Event<'input> { /// Indicates the start of a YAML stream. StreamStart, /// Indicates the end of a YAML stream. StreamEnd, /// Indicates the start of a YAML document. DocumentStart, /// Indicates the end of a YAML document. DocumentEnd, /// Indicates an alias to an anchor in a YAML document. Alias(Anchor), /// Represents a scalar value in a YAML document. Scalar(Scalar<'input>), /// Indicates the start of a sequence in a YAML document. SequenceStart(SequenceStart), /// Indicates the end of a sequence in a YAML document. SequenceEnd, /// Indicates the start of a mapping in a YAML document. MappingStart(MappingStart), /// Indicates the end of a mapping in a YAML document. MappingEnd, } /// Represents a scalar value in a YAML document. pub struct Scalar<'input> { /// The anchor associated with the scalar value. pub anchor: Option, /// The tag associated with the scalar value. pub tag: Option, /// The value of the scalar as a byte slice. pub value: Box<[u8]>, /// The style of the scalar value. pub style: ScalarStyle, /// The representation of the scalar value as a byte slice. pub repr: Option<&'input [u8]>, } /// Represents the start of a sequence in a YAML document. #[derive(Debug)] pub struct SequenceStart { /// The anchor associated with the sequence. pub anchor: Option, /// The tag associated with the sequence. pub tag: Option, } /// Represents the start of a mapping in a YAML document. #[derive(Debug)] pub struct MappingStart { /// The anchor associated with the mapping. pub anchor: Option, /// The tag associated with the mapping. pub tag: Option, } /// Represents an anchor in a YAML document. #[derive(Ord, PartialOrd, Eq, PartialEq)] pub struct Anchor(Box<[u8]>); /// Represents the style of a scalar value in a YAML document. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum ScalarStyle { /// Indicates a plain scalar value. Plain, /// Indicates a single-quoted scalar value. SingleQuoted, /// Indicates a double-quoted scalar value. DoubleQuoted, /// Indicates a literal scalar value. Literal, /// Indicates a folded scalar value. Folded, } impl<'input> Parser<'input> { /// Creates a new `Parser` instance with the given input data. /// /// The `input` parameter is of type `Cow<'input, [u8]>`, which allows the parser /// to accept both borrowed slices and owned vectors of bytes as input. /// /// # Panics /// /// This function panics if there is an error initializing the underlying `libyml` parser. pub fn new(input: Cow<'input, [u8]>) -> Parser<'input> { let owned = Owned::>::new_uninit(); let pin = unsafe { let parser = addr_of_mut!((*owned.ptr).sys); if sys::yaml_parser_initialize(parser).fail { panic!( "Failed to initialize YAML parser: {}", Error::parse_error(parser) ); } sys::yaml_parser_set_encoding( parser, sys::YamlUtf8Encoding, ); sys::yaml_parser_set_input_string( parser, input.as_ptr(), input.len() as u64, ); addr_of_mut!((*owned.ptr).input).write(input); Owned::assume_init(owned) }; Parser { pin } } /// Parses the next YAML event from the input. /// /// Returns a `Result` containing the parsed `Event` and its corresponding `Mark` on success, /// or an `Error` if parsing fails. pub fn parse_next_event( &mut self, ) -> Result<(Event<'input>, Mark)> { let mut event = MaybeUninit::::uninit(); unsafe { let parser = addr_of_mut!((*self.pin.ptr).sys); if (*parser).error != sys::YamlNoError { return Err(Error::parse_error(parser)); } let event = event.as_mut_ptr(); 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, }; sys::yaml_event_delete(event); 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]>, ) -> Event<'input> { match sys.type_ { sys::YamlStreamStartEvent => Event::StreamStart, sys::YamlStreamEndEvent => Event::StreamEnd, sys::YamlDocumentStartEvent => Event::DocumentStart, sys::YamlDocumentEndEvent => Event::DocumentEnd, sys::YamlAliasEvent => Event::Alias( optional_anchor(sys.data.alias.anchor).unwrap(), ), sys::YamlScalarEvent => { let value_slice = slice::from_raw_parts( sys.data.scalar.value, sys.data.scalar.length as usize, ); let repr = optional_repr(sys, input); Event::Scalar(Scalar { anchor: optional_anchor(sys.data.scalar.anchor), tag: optional_tag(sys.data.scalar.tag), value: Box::from(value_slice), style: match sys.data.scalar.style { sys::YamlScalarStyleT::YamlPlainScalarStyle => ScalarStyle::Plain, sys::YamlScalarStyleT::YamlSingleQuotedScalarStyle => ScalarStyle::SingleQuoted, sys::YamlScalarStyleT::YamlDoubleQuotedScalarStyle => ScalarStyle::DoubleQuoted, sys::YamlScalarStyleT::YamlLiteralScalarStyle => ScalarStyle::Literal, sys::YamlScalarStyleT::YamlFoldedScalarStyle => ScalarStyle::Folded, _ => unreachable!(), }, repr, }) } sys::YamlSequenceStartEvent => { Event::SequenceStart(SequenceStart { anchor: optional_anchor(sys.data.sequence_start.anchor), tag: optional_tag(sys.data.sequence_start.tag), }) } sys::YamlSequenceEndEvent => Event::SequenceEnd, sys::YamlMappingStartEvent => { Event::MappingStart(MappingStart { anchor: optional_anchor(sys.data.mapping_start.anchor), tag: optional_tag(sys.data.mapping_start.tag), }) } sys::YamlMappingEndEvent => Event::MappingEnd, sys::YamlNoEvent => unreachable!(), _ => unreachable!(), } } unsafe fn optional_anchor(anchor: *const u8) -> Option { if anchor.is_null() { return None; } let ptr = NonNull::new(anchor as *mut i8)?; let cstr = CStr::from_ptr(ptr); Some(Anchor(Box::from(cstr.to_bytes()))) } unsafe fn optional_tag(tag: *const u8) -> Option { if tag.is_null() { return None; } let ptr = NonNull::new(tag as *mut i8)?; let cstr = CStr::from_ptr(ptr); Some(Tag(Box::from(cstr.to_bytes()))) } unsafe fn optional_repr<'input>( sys: &sys::YamlEventT, input: &'input Cow<'input, [u8]>, ) -> Option<&'input [u8]> { let start = sys.start_mark.index as usize; let end = sys.end_mark.index as usize; Some(&input[start..end]) } impl Debug for Scalar<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let Scalar { anchor, tag, value, style, repr: _, } = self; struct LossySlice<'a>(&'a [u8]); impl Debug for LossySlice<'_> { fn fmt( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { safe_cstr::debug_lossy(self.0, formatter) } } formatter .debug_struct("Scalar") .field("anchor", anchor) .field("tag", tag) .field("value", &LossySlice(value)) .field("style", style) .finish() } } impl Debug for Anchor { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { safe_cstr::debug_lossy(&self.0, formatter) } } impl Drop for ParserPinned<'_> { fn drop(&mut self) { unsafe { sys::yaml_parser_delete(&mut self.sys) } } } serde_yml-0.0.12/src/libyml/safe_cstr.rs000064400000000000000000000153351046102023000162740ustar 00000000000000use std::{ fmt::{self, Debug, Display, Write as _}, marker::PhantomData, ptr::NonNull, slice, str, }; #[derive(Copy, Clone, Debug, PartialEq, Eq)] /// A custom error type for CStr operations. /// /// This struct represents an error that occurs during CStr operations. /// /// # Implementations /// /// This struct implements the `Display` and `std::error::Error` traits, which allows it to be printed and used as an error type. /// /// pub struct CStrError; impl Display for CStrError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "CStr error occurred") } } impl std::error::Error for CStrError {} #[derive(Copy, Clone)] /// Struct representing a C string. pub struct CStr<'a> { ptr: NonNull, marker: PhantomData<&'a [u8]>, } unsafe impl Send for CStr<'_> {} unsafe impl Sync for CStr<'_> {} impl<'a> CStr<'a> { /// Creates a new `CStr` instance from a static byte slice that is null-terminated. /// /// # Arguments /// /// * `bytes` - A static byte slice that must be null-terminated. /// /// # Returns /// /// A new `CStr` instance representing the input byte slice. /// /// # Errors /// /// This method will return a `CStrError` if the input `bytes` slice does not have a null terminator. pub fn from_bytes_with_nul( bytes: &'static [u8], ) -> Result { if bytes.is_empty() { return Err(CStrError); } if bytes.last() != Some(&b'\0') { return Err(CStrError); } let ptr = NonNull::from(bytes).cast(); Ok(Self::from_ptr(ptr)) } /// Creates a new `CStr` instance from a `NonNull` raw pointer. /// /// # Arguments /// /// * `ptr` - A `NonNull` raw pointer to the null-terminated C-style string. /// /// # Returns /// /// A new `CStr` instance representing the input pointer. pub fn from_ptr(ptr: NonNull) -> Self { CStr { // Cast the input pointer to a `NonNull` pointer ptr: ptr.cast(), // Create a `PhantomData` marker to maintain the lifetime 'a marker: PhantomData, } } /// Calculates the length of the C-style string represented by the `CStr` instance. /// /// # Returns /// /// The length of the C-style string, not including the null terminator. pub fn len(self) -> usize { let start = self.ptr.as_ptr(); let mut end = start; // Iterate over the C-style string until the null terminator is found while unsafe { *end != 0 } { end = unsafe { end.add(1) }; } // Calculate the length of the C-style string, but only if the input is not empty if end != start { unsafe { end.offset_from(start) as usize } } else { 0 } } /// Checks if the C-style string represented by the `CStr` instance is empty. /// /// # Returns /// /// `true` if the C-style string is empty, `false` otherwise. pub fn is_empty(self) -> bool { self.len() == 0 } /// Retrieves a reference to the underlying byte slice of the `CStr` instance. /// /// # Returns /// /// A borrowed reference to the byte slice represented by the `CStr` instance. pub fn to_bytes(self) -> &'a [u8] { let len = self.len(); unsafe { slice::from_raw_parts(self.ptr.as_ptr(), len) } } } impl Display for CStr<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let ptr = self.ptr.as_ptr(); let len = self.len(); let bytes = unsafe { slice::from_raw_parts(ptr, len) }; display_lossy(bytes, formatter) } } impl Debug for CStr<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let ptr = self.ptr.as_ptr(); let len = self.len(); let bytes = unsafe { slice::from_raw_parts(ptr, len) }; debug_lossy(bytes, formatter) } } fn display_lossy( mut bytes: &[u8], formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { loop { match str::from_utf8(bytes) { Ok(valid) => return formatter.write_str(valid), Err(utf8_error) => { let valid_up_to = utf8_error.valid_up_to(); let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) }; formatter.write_str(valid)?; formatter.write_char(char::REPLACEMENT_CHARACTER)?; if let Some(error_len) = utf8_error.error_len() { bytes = &bytes[valid_up_to + error_len..]; } else { return Ok(()); } } } } } /// Debugs a C string by printing it in a format that can be used in debugging output. /// /// # Arguments /// /// * `bytes` - A reference to the byte slice that represents the C string. /// * `formatter` - A mutable reference to the formatter where the debugged string will be written. /// /// # Returns /// /// A `Result` indicating whether the debugging was successful. /// /// # Panics /// /// This method will panic if the input `bytes` slice does not have a null terminator. pub fn debug_lossy( mut bytes: &[u8], formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_char('"')?; while !bytes.is_empty() { let from_utf8_result = str::from_utf8(bytes); let valid = match from_utf8_result { Ok(valid) => valid, Err(utf8_error) => { let valid_up_to = utf8_error.valid_up_to(); unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) } } }; let mut written = 0; for (i, ch) in valid.char_indices() { let esc = ch.escape_debug(); if esc.len() != 1 && ch != '\'' { formatter.write_str(&valid[written..i])?; for ch in esc { formatter.write_char(ch)?; } written = i + ch.len_utf8(); } } formatter.write_str(&valid[written..])?; match from_utf8_result { Ok(_valid) => break, Err(utf8_error) => { let end_of_broken = if let Some(error_len) = utf8_error.error_len() { valid.len() + error_len } else { bytes.len() }; for b in &bytes[valid.len()..end_of_broken] { write!(formatter, "\\x{:02x}", b)?; } bytes = &bytes[end_of_broken..]; } } } formatter.write_char('"') } serde_yml-0.0.12/src/libyml/tag.rs000064400000000000000000000101331046102023000150650ustar 00000000000000use crate::libyml::safe_cstr; use memchr::memchr; use std::{ fmt::{self, Debug, Display}, ops::Deref, }; /// Custom error type for Tag operations. #[derive(Clone, Copy, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct TagFormatError; impl Display for TagFormatError { /// Formats the error message for display. /// /// # Arguments /// /// * `f` - The formatter to write the error message to. /// /// # Returns /// /// Returns `fmt::Result` indicating the success or failure of the operation. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Error occurred while formatting tag") } } impl std::error::Error for TagFormatError {} /// Represents a tag in a YAML document. /// A tag specifies the data type or semantic meaning of a value. #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)] pub struct Tag(pub(in crate::libyml) Box<[u8]>); impl Tag { /// The null tag, representing a null value. pub const NULL: &'static str = "tag:yaml.org,2002:null"; /// The bool tag, representing a boolean value. pub const BOOL: &'static str = "tag:yaml.org,2002:bool"; /// The int tag, representing an integer value. pub const INT: &'static str = "tag:yaml.org,2002:int"; /// The float tag, representing a floating-point value. pub const FLOAT: &'static str = "tag:yaml.org,2002:float"; /// Checks if the tag starts with the given prefix. /// /// # Arguments /// /// * `prefix` - The prefix to check against. /// /// # Returns /// /// Returns `Ok(true)` if the tag starts with the given prefix, `Ok(false)` otherwise. /// Returns an error if the prefix is longer than the tag. /// /// # Errors /// /// Returns `TagFormatError` if the prefix length is greater than the tag length. pub fn starts_with( &self, prefix: &str, ) -> Result { if prefix.len() > self.0.len() { Err(TagFormatError) } else { let prefix_bytes = prefix.as_bytes(); let tag_bytes = &self.0[..prefix_bytes.len()]; Ok(tag_bytes == prefix_bytes) } } /// Creates a new `Tag` instance from a `&str` input. /// /// # Arguments /// /// * `tag_str` - The string representing the tag. /// /// # Returns /// /// Returns a `Tag` instance representing the specified tag string. pub fn new(tag_str: &str) -> Tag { Tag(Box::from(tag_str.as_bytes())) } } impl PartialEq for Tag { /// Checks if the tag is equal to the given string. /// /// # Arguments /// /// * `other` - The string to compare against. /// /// # Returns /// /// Returns `true` if the tag is equal to the given string, `false` otherwise. fn eq(&self, other: &str) -> bool { self.0 == other.as_bytes().into() } } impl PartialEq<&str> for Tag { /// Checks if the tag is equal to the given string slice. /// /// # Arguments /// /// * `other` - The string slice to compare against. /// /// # Returns /// /// Returns `true` if the tag is equal to the given string slice, `false` otherwise. fn eq(&self, other: &&str) -> bool { self.0 == other.as_bytes().into() } } impl Deref for Tag { type Target = [u8]; /// Dereferences the tag to its underlying byte slice. /// /// # Returns /// /// Returns a reference to the underlying byte slice of the tag. fn deref(&self) -> &Self::Target { &self.0 } } impl Debug for Tag { /// Formats the tag for debugging purposes. /// /// # Arguments /// /// * `formatter` - The formatter to write the debug output to. /// /// # Returns /// /// Returns `Ok(())` if the formatting was successful, or an error otherwise. fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(null_pos) = memchr(b'\0', &self.0) { safe_cstr::debug_lossy(&self.0[..null_pos], formatter) } else { safe_cstr::debug_lossy(&self.0, formatter) } } } serde_yml-0.0.12/src/libyml/util.rs000064400000000000000000000061621046102023000152760ustar 00000000000000use std::{ marker::PhantomData, mem::{self, MaybeUninit}, ops::Deref, ptr::{addr_of, NonNull}, }; /// A struct representing ownership of a pointer to a value of type `T`. /// `Init` represents the initialization state of the value. #[derive(Debug)] pub struct Owned { ptr: NonNull, marker: PhantomData>, } impl Owned { /// Creates a new uninitialized `Owned` instance. /// /// # Safety /// The created instance contains uninitialized memory, and should be properly /// initialized before use. pub fn new_uninit() -> Owned, T> { // Allocate memory for `T` but leave it uninitialized. let boxed = Box::new(MaybeUninit::::uninit()); Owned { ptr: unsafe { // Convert the Box pointer to a raw pointer and wrap it in `NonNull`. NonNull::new_unchecked(Box::into_raw(boxed)) }, marker: PhantomData, } } /// Converts an uninitialized `Owned` instance to an initialized one. /// /// # Safety /// The caller must ensure that `definitely_init` is properly initialized. pub unsafe fn assume_init( definitely_init: Owned, T>, ) -> Owned { let ptr = definitely_init.ptr; mem::forget(definitely_init); Owned { ptr: ptr.cast(), marker: PhantomData, } } } /// A transparent wrapper around a mutable pointer of type `T`. #[repr(transparent)] #[derive(Debug)] pub struct InitPtr { /// The mutable pointer. pub ptr: *mut T, } impl Deref for Owned { type Target = InitPtr; /// Returns a reference to the `InitPtr` wrapped by `Owned`. fn deref(&self) -> &Self::Target { unsafe { &*addr_of!(self.ptr).cast::>() } } } impl Drop for Owned { /// Deallocates the memory held by `Owned` when it goes out of scope. fn drop(&mut self) { let _ = unsafe { Box::from_raw(self.ptr.as_ptr()) }; } } #[cfg(test)] mod tests { use super::*; #[test] fn test_new_uninit() { let uninit_owned: Owned, i32> = Owned::new_uninit(); assert_eq!( uninit_owned.ptr.as_ptr(), uninit_owned.ptr.as_ptr() ); } #[test] fn test_assume_init() { let uninit_owned: Owned, i32> = Owned::new_uninit(); let init_owned: Owned = unsafe { Owned::assume_init(uninit_owned) }; assert_eq!(init_owned.ptr.as_ptr(), init_owned.ptr.as_ptr()); } #[test] fn test_deref() { let uninit_owned: Owned, i32> = Owned::new_uninit(); let init_ptr = uninit_owned.ptr.as_ptr(); assert_eq!( uninit_owned.deref().ptr as *mut MaybeUninit, init_ptr ); } #[test] fn test_drop() { let uninit_owned: Owned, i32> = Owned::new_uninit(); drop(uninit_owned); // This test will pass if it does not panic } } serde_yml-0.0.12/src/loader.rs000064400000000000000000000174041046102023000143000ustar 00000000000000use crate::{ de::{Event, Progress}, libyml::{ error::Mark, parser::{Event as YamlEvent, Parser}, }, modules::error::{self, Error, ErrorImpl, Result}, }; use std::{borrow::Cow, collections::BTreeMap, io::Read, sync::Arc}; /// Represents a YAML loader. #[derive(Debug)] pub struct Loader<'input> { /// The YAML parser used to parse the input. /// /// The `Parser` type is defined in the `libyml` module and represents /// a low-level YAML parser. /// /// The `'input` lifetime parameter indicates the lifetime of the input data /// being parsed. It ensures that the `Loader` does not outlive the input data. pub parser: Option>, /// The count of documents parsed by the loader. /// /// This field keeps track of the number of YAML documents encountered during parsing. pub parsed_document_count: usize, } /// Represents a YAML document. #[derive(Debug)] pub struct Document<'input> { /// The parsed events of the document. /// /// This field contains a vector of `(Event<'input>, Mark)` tuples, where: /// - `Event<'input>` represents a parsed YAML event, such as a scalar, sequence, or mapping. /// The `'input` lifetime parameter indicates the lifetime of the input data associated /// with the event. /// - `Mark` represents the position in the input where the event was encountered. pub events: Vec<(Event<'input>, Mark)>, /// Any error encountered during parsing. /// /// This field is an optional `Arc`, where: /// - `Arc` is a reference-counted smart pointer that allows multiple ownership of the error. /// - `ErrorImpl` is the underlying error type that holds the details of the parsing error. /// /// If an error occurs during parsing, this field will contain `Some(error)`. Otherwise, it /// will be `None`. pub error: Option>, /// Map from alias id to index in events. /// /// This field is a `BTreeMap` that maps alias ids to their corresponding index in the /// `events` vector. /// /// In YAML, an alias is a reference to a previously defined anchor. When an alias is /// encountered during parsing, its id is used to look up the index of the corresponding /// event in the `events` vector. pub anchor_event_map: BTreeMap, } impl<'input> Loader<'input> { /// Constructs a new `Loader` instance from the given progress. /// /// # Arguments /// /// * `progress` - The progress representing the YAML input. /// /// # Errors /// /// Returns an error if there is an issue reading the input. /// /// # Examples /// /// ``` /// use serde_yml::loader::Loader; /// use serde_yml::de::Progress; /// /// let input = "---\nkey: value"; /// let progress = Progress::Str(input); /// let loader_result = Loader::new(progress); /// /// assert!(loader_result.is_ok()); /// ``` pub fn new(progress: Progress<'input>) -> Result { let input = match progress { Progress::Str(s) => Cow::Borrowed(s.as_bytes()), Progress::Slice(bytes) => Cow::Borrowed(bytes), Progress::Read(mut rdr) => { let mut buffer = Vec::new(); if let Err(io_error) = rdr.read_to_end(&mut buffer) { return Err(error::new(ErrorImpl::IoError( io_error, ))); } Cow::Owned(buffer) } Progress::Iterable(_) | Progress::Document(_) => { unreachable!() } Progress::Fail(err) => return Err(error::shared(err)), }; Ok(Loader { parser: Some(Parser::new(input)), parsed_document_count: 0, }) } /// Advances the loader to the next document and returns it. /// /// # Returns /// /// Returns `Some(Document)` if a document is successfully parsed, or `None` if there are no more documents. /// /// # Examples /// /// ``` /// use serde_yml::loader::{Loader, Document}; /// use serde_yml::de::Progress; /// /// let input = "---\nkey: value"; /// let progress = Progress::Str(input); /// let mut loader = Loader::new(progress).unwrap(); /// let document = loader.next_document().unwrap(); /// /// assert_eq!(document.events.len(), 4); /// ``` pub fn next_document(&mut self) -> Option> { let parser = match &mut self.parser { Some(parser) => parser, None => return None, }; let first = self.parsed_document_count == 0; self.parsed_document_count += 1; let mut anchors = BTreeMap::new(); let mut document = Document { events: Vec::new(), error: None, anchor_event_map: BTreeMap::new(), }; loop { let (event, mark) = match parser.parse_next_event() { Ok((event, mark)) => (event, mark), Err(err) => { document.error = Some(Error::from(err).shared()); return Some(document); } }; let event = match event { YamlEvent::StreamStart => continue, YamlEvent::StreamEnd => { self.parser = None; return if first { if document.events.is_empty() { document.events.push((Event::Void, mark)); } Some(document) } else { None }; } YamlEvent::DocumentStart => continue, YamlEvent::DocumentEnd => return Some(document), YamlEvent::Alias(alias) => match anchors.get(&alias) { Some(id) => Event::Alias(*id), None => { document.error = Some( error::new(ErrorImpl::UnknownAnchor(mark)) .shared(), ); return Some(document); } }, YamlEvent::Scalar(mut scalar) => { if let Some(anchor) = scalar.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document .anchor_event_map .insert(id, document.events.len()); } Event::Scalar(scalar) } YamlEvent::SequenceStart(mut sequence_start) => { if let Some(anchor) = sequence_start.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document .anchor_event_map .insert(id, document.events.len()); } Event::SequenceStart(sequence_start) } YamlEvent::SequenceEnd => Event::SequenceEnd, YamlEvent::MappingStart(mut mapping_start) => { if let Some(anchor) = mapping_start.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document .anchor_event_map .insert(id, document.events.len()); } Event::MappingStart(mapping_start) } YamlEvent::MappingEnd => Event::MappingEnd, }; document.events.push((event, mark)); } } } serde_yml-0.0.12/src/mapping.rs000064400000000000000000000772141046102023000144720ustar 00000000000000//! A YAML mapping and its iterator types. use crate::{private, Value}; use indexmap::IndexMap; use serde::{Deserialize, Deserializer, Serialize}; use std::{ cmp::Ordering, collections::hash_map::DefaultHasher, fmt::{self, Display}, hash::{Hash, Hasher}, mem, }; /// A YAML mapping in which the keys and values are both `serde_yml::Value`. #[derive(Clone, Default, Eq, PartialEq)] pub struct Mapping { /// The underlying map. pub map: IndexMap, } impl Mapping { /// Creates an empty YAML mapping. #[inline] pub fn new() -> Self { Self::default() } /// Creates an empty YAML mapping with the given initial capacity. /// /// The mapping will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the mapping will not allocate. #[inline] pub fn with_capacity(capacity: usize) -> Self { Mapping { map: IndexMap::with_capacity(capacity), } } /// Reserves capacity for at least `additional` more elements to be inserted /// into the mapping. The mapping may reserve more space to avoid frequent /// reallocations. /// /// # Panics /// /// Panics if the new allocation size overflows `usize`. #[inline] pub fn reserve(&mut self, additional: usize) { self.map.reserve(additional); } /// Shrinks the capacity of the mapping as much as possible. /// /// It will drop down as much as possible while maintaining the internal rules /// and possibly leaving some space in accordance with the resize policy. #[inline] pub fn shrink_to_fit(&mut self) { self.map.shrink_to_fit(); } /// Inserts a key-value pair into the mapping. /// /// If the mapping did not have this key present, `None` is returned. /// /// If the mapping did have this key present, the value is updated, and the old /// value is returned. #[inline] pub fn insert(&mut self, k: Value, v: Value) -> Option { self.map.insert(k, v) } /// Returns `true` if the mapping contains a value for the specified key. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. #[inline] pub fn contains_key(&self, index: I) -> bool { index.is_key_into(self) } /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. #[inline] pub fn get(&self, index: I) -> Option<&Value> { index.index_into(self) } /// Returns a mutable reference to the value corresponding to the key. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. #[inline] pub fn get_mut( &mut self, index: I, ) -> Option<&mut Value> { index.index_into_mut(self) } /// Gets the given key's corresponding entry in the mapping for in-place manipulation. #[inline] pub fn entry(&mut self, k: Value) -> Entry<'_> { match self.map.entry(k) { indexmap::map::Entry::Occupied(occupied) => { Entry::Occupied(OccupiedEntry { occupied }) } indexmap::map::Entry::Vacant(vacant) => { Entry::Vacant(VacantEntry { vacant }) } } } /// Removes a key from the mapping, returning the value at the key if the key /// was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// This is equivalent to calling `swap_remove` and ignores the order of the /// elements. #[inline] pub fn remove(&mut self, index: I) -> Option { self.swap_remove(index) } /// Removes a key from the mapping, returning the stored key and value if the /// key was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// This is equivalent to calling `swap_remove_entry` and ignores the order of the /// elements. #[inline] pub fn remove_entry( &mut self, index: I, ) -> Option<(Value, Value)> { self.swap_remove_entry(index) } /// Removes a key from the mapping, returning the value at the key if the key /// was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// The element is removed by swapping it with the last element of the mapping /// and popping it off. This perturbs the position of the last element. #[inline] pub fn swap_remove(&mut self, index: I) -> Option { index.swap_remove_from(self) } /// Removes a key from the mapping, returning the stored key and value if the /// key was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// The element is removed by swapping it with the last element of the mapping /// and popping it off. This perturbs the position of the last element. #[inline] pub fn swap_remove_entry( &mut self, index: I, ) -> Option<(Value, Value)> { index.swap_remove_entry_from(self) } /// Removes a key from the mapping, returning the value at the key if the key /// was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// The element is removed by shifting all of the elements that follow it, /// preserving their relative order. This perturbs the index of all of those /// elements. #[inline] pub fn shift_remove( &mut self, index: I, ) -> Option { index.shift_remove_from(self) } /// Removes a key from the mapping, returning the stored key and value if the /// key was previously in the mapping. /// /// The key may be any borrowed form of the mapping's key type, but the ordering /// on the borrowed form *must* match the key type's ordering. /// /// The element is removed by shifting all of the elements that follow it, /// preserving their relative order. This perturbs the index of all of those /// elements. #[inline] pub fn shift_remove_entry( &mut self, index: I, ) -> Option<(Value, Value)> { index.shift_remove_entry_from(self) } /// Retains only the elements specified by the predicate. /// /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. #[inline] pub fn retain(&mut self, keep: F) where F: FnMut(&Value, &mut Value) -> bool, { self.map.retain(keep); } /// Returns the number of elements the mapping can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { self.map.capacity() } /// Returns the number of elements in the mapping. #[inline] pub fn len(&self) -> usize { self.map.len() } /// Returns `true` if the mapping contains no elements. #[inline] pub fn is_empty(&self) -> bool { self.map.is_empty() } /// Clears the mapping, removing all key-value pairs. #[inline] pub fn clear(&mut self) { self.map.clear(); } /// Returns an iterator over the key-value pairs of the mapping, in their order. /// /// The iterator element type is `(&'a Value, &'a Value)`. #[inline] pub fn iter(&self) -> Iter<'_> { Iter { iter: self.map.iter(), } } /// Returns a mutable iterator over the key-value pairs of the mapping, in their order. /// /// The iterator element type is `(&'a Value, &'a mut Value)`. #[inline] pub fn iter_mut(&mut self) -> IterMut<'_> { IterMut { iter: self.map.iter_mut(), } } /// Returns an iterator over the keys of the mapping, in their order. /// /// The iterator element type is `&'a Value`. pub fn keys(&self) -> Keys<'_> { Keys { iter: self.map.keys(), } } /// Returns an owning iterator over the keys of the mapping, in their order. /// /// The iterator element type is `Value`. pub fn into_keys(self) -> IntoKeys { IntoKeys { iter: self.map.into_keys(), } } /// Returns an iterator over the values of the mapping, in their order. /// /// The iterator element type is `&'a Value`. pub fn values(&self) -> Values<'_> { Values { iter: self.map.values(), } } /// Returns a mutable iterator over the values of the mapping, in their order. /// /// The iterator element type is `&'a mut Value`. pub fn values_mut(&mut self) -> ValuesMut<'_> { ValuesMut { iter: self.map.values_mut(), } } /// Returns an owning iterator over the values of the mapping, in their order. /// /// The iterator element type is `Value`. pub fn into_values(self) -> IntoValues { IntoValues { iter: self.map.into_values(), } } } /// A trait for types that can be used to index into a `serde_yml::Mapping`. /// /// The `get`, `get_mut`, `contains_key`, `remove`, `remove_entry`, `shift_remove` /// and `shift_remove_entry` methods of `Mapping` use this trait to provide a uniform /// interface for indexing with different key types. /// /// This trait is sealed and cannot be implemented for types outside of `serde_yml`. pub trait Index: private::Sealed { /// Returns `true` if the given key is present in the mapping. #[doc(hidden)] fn is_key_into(&self, v: &Mapping) -> bool; /// Returns a reference to the value corresponding to the key in the mapping. #[doc(hidden)] fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value>; /// Returns a mutable reference to the value corresponding to the key in the mapping. #[doc(hidden)] fn index_into_mut<'a>( &self, v: &'a mut Mapping, ) -> Option<&'a mut Value>; /// Removes the key-value pair corresponding to the key from the mapping and returns the value. /// /// The element is removed by swapping it with the last element of the mapping /// and popping it off. This perturbs the position of the last element. #[doc(hidden)] fn swap_remove_from(&self, v: &mut Mapping) -> Option; /// Removes the key-value pair corresponding to the key from the mapping and returns the key and value. /// /// The element is removed by swapping it with the last element of the mapping /// and popping it off. This perturbs the position of the last element. #[doc(hidden)] fn swap_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)>; /// Removes the key-value pair corresponding to the key from the mapping and returns the value. /// /// The element is removed by shifting all of the elements that follow it, /// preserving their relative order. This perturbs the index of all of those /// elements. #[doc(hidden)] fn shift_remove_from(&self, v: &mut Mapping) -> Option; /// Removes the key-value pair corresponding to the key from the mapping and returns the key and value. /// /// The element is removed by shifting all of the elements that follow it, /// preserving their relative order. This perturbs the index of all of those /// elements. #[doc(hidden)] fn shift_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)>; } /// A newtype wrapper for `&str` that implements `indexmap::Equivalent` /// to allow indexing into a `Mapping` with string slices. struct HashLikeValue<'a>(&'a str); impl indexmap::Equivalent for HashLikeValue<'_> { fn equivalent(&self, key: &Value) -> bool { match key { Value::String(string) => self.0 == string, _ => false, } } } // NOTE: This impl must be consistent with Value's Hash impl. impl Hash for HashLikeValue<'_> { fn hash(&self, state: &mut H) { const STRING: Value = Value::String(String::new()); mem::discriminant(&STRING).hash(state); self.0.hash(state); } } /// Implements the `Index` trait for `Value`, allowing any `Value` to be used /// as a key for indexing into a `Mapping`. impl Index for Value { fn is_key_into(&self, v: &Mapping) -> bool { v.map.contains_key(self) } fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { v.map.get(self) } fn index_into_mut<'a>( &self, v: &'a mut Mapping, ) -> Option<&'a mut Value> { v.map.get_mut(self) } fn swap_remove_from(&self, v: &mut Mapping) -> Option { v.map.swap_remove(self) } fn swap_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { v.map.swap_remove_entry(self) } fn shift_remove_from(&self, v: &mut Mapping) -> Option { v.map.shift_remove(self) } fn shift_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { v.map.shift_remove_entry(self) } } /// Implements the `Index` trait for `&str`, allowing string slices to be used /// as keys for indexing into a `Mapping`. impl Index for str { fn is_key_into(&self, v: &Mapping) -> bool { v.map.contains_key(&HashLikeValue(self)) } fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { v.map.get(&HashLikeValue(self)) } fn index_into_mut<'a>( &self, v: &'a mut Mapping, ) -> Option<&'a mut Value> { v.map.get_mut(&HashLikeValue(self)) } fn swap_remove_from(&self, v: &mut Mapping) -> Option { v.map.swap_remove(&HashLikeValue(self)) } fn swap_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { v.map.swap_remove_entry(&HashLikeValue(self)) } fn shift_remove_from(&self, v: &mut Mapping) -> Option { v.map.shift_remove(&HashLikeValue(self)) } fn shift_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { v.map.shift_remove_entry(&HashLikeValue(self)) } } /// Implements the `Index` trait for `String`, allowing owned strings to be used as keys for indexing into a `Mapping`. impl Index for String { fn is_key_into(&self, v: &Mapping) -> bool { self.as_str().is_key_into(v) } fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { self.as_str().index_into(v) } fn index_into_mut<'a>( &self, v: &'a mut Mapping, ) -> Option<&'a mut Value> { self.as_str().index_into_mut(v) } fn swap_remove_from(&self, v: &mut Mapping) -> Option { self.as_str().swap_remove_from(v) } fn swap_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { self.as_str().swap_remove_entry_from(v) } fn shift_remove_from(&self, v: &mut Mapping) -> Option { self.as_str().shift_remove_from(v) } fn shift_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { self.as_str().shift_remove_entry_from(v) } } /// Implements the `Index` trait for `&String`, allowing string references to be used as keys for indexing into a `Mapping`. impl Index for &T where T: ?Sized + Index, { fn is_key_into(&self, v: &Mapping) -> bool { (**self).is_key_into(v) } fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> { (**self).index_into(v) } fn index_into_mut<'a>( &self, v: &'a mut Mapping, ) -> Option<&'a mut Value> { (**self).index_into_mut(v) } fn swap_remove_from(&self, v: &mut Mapping) -> Option { (**self).swap_remove_from(v) } fn swap_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { (**self).swap_remove_entry_from(v) } fn shift_remove_from(&self, v: &mut Mapping) -> Option { (**self).shift_remove_from(v) } fn shift_remove_entry_from( &self, v: &mut Mapping, ) -> Option<(Value, Value)> { (**self).shift_remove_entry_from(v) } } #[allow(clippy::derived_hash_with_manual_eq)] /// `Mapping` is hashable if its keys and values are hashable. impl Hash for Mapping { fn hash(&self, state: &mut H) { // Hash the kv pairs in a way that is not sensitive to their order. let mut xor = 0; for (k, v) in self { let mut hasher = DefaultHasher::new(); k.hash(&mut hasher); v.hash(&mut hasher); xor ^= hasher.finish(); } xor.hash(state); } } /// `Mapping` is ordered if its keys and values are ordered. impl PartialOrd for Mapping { fn partial_cmp(&self, other: &Self) -> Option { let mut self_entries = Vec::from_iter(self); let mut other_entries = Vec::from_iter(other); // Sort in an arbitrary order that is consistent with Value's PartialOrd // impl. fn total_cmp(a: &Value, b: &Value) -> Ordering { match (a, b) { (Value::Null, Value::Null) => Ordering::Equal, (Value::Null, _) => Ordering::Less, (_, Value::Null) => Ordering::Greater, (Value::Bool(a), Value::Bool(b)) => a.cmp(b), (Value::Bool(_), _) => Ordering::Less, (_, Value::Bool(_)) => Ordering::Greater, (Value::Number(a), Value::Number(b)) => a.total_cmp(b), (Value::Number(_), _) => Ordering::Less, (_, Value::Number(_)) => Ordering::Greater, (Value::String(a), Value::String(b)) => a.cmp(b), (Value::String(_), _) => Ordering::Less, (_, Value::String(_)) => Ordering::Greater, (Value::Sequence(a), Value::Sequence(b)) => { iter_cmp_by(a, b, total_cmp) } (Value::Sequence(_), _) => Ordering::Less, (_, Value::Sequence(_)) => Ordering::Greater, (Value::Mapping(a), Value::Mapping(b)) => { iter_cmp_by(a, b, |(ak, av), (bk, bv)| { total_cmp(ak, bk) .then_with(|| total_cmp(av, bv)) }) } (Value::Mapping(_), _) => Ordering::Less, (_, Value::Mapping(_)) => Ordering::Greater, (Value::Tagged(a), Value::Tagged(b)) => a .tag .cmp(&b.tag) .then_with(|| total_cmp(&a.value, &b.value)), } } fn iter_cmp_by(this: I, other: I, mut cmp: F) -> Ordering where I: IntoIterator, F: FnMut(I::Item, I::Item) -> Ordering, { let mut this = this.into_iter(); let mut other = other.into_iter(); loop { let x = match this.next() { None => { if other.next().is_none() { return Ordering::Equal; } else { return Ordering::Less; } } Some(val) => val, }; let y = match other.next() { None => return Ordering::Greater, Some(val) => val, }; match cmp(x, y) { Ordering::Equal => {} non_eq => return non_eq, } } } // While sorting by map key, we get to assume that no two keys are // equal, otherwise they wouldn't both be in the map. This is not a safe // assumption outside of this situation. let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b); self_entries.sort_by(total_cmp); other_entries.sort_by(total_cmp); self_entries.partial_cmp(&other_entries) } } /// `Mapping` is ordered if its keys and values are ordered. impl std::ops::Index for Mapping where I: Index, { type Output = Value; #[inline] #[track_caller] fn index(&self, index: I) -> &Value { index.index_into(self).unwrap() } } /// `Mapping` is ordered if its keys and values are ordered. impl std::ops::IndexMut for Mapping where I: Index, { #[inline] #[track_caller] fn index_mut(&mut self, index: I) -> &mut Value { index.index_into_mut(self).unwrap() } } impl Extend<(Value, Value)> for Mapping { #[inline] fn extend>( &mut self, iter: I, ) { self.map.extend(iter); } } impl FromIterator<(Value, Value)> for Mapping { #[inline] fn from_iter>( iter: I, ) -> Self { Mapping { map: IndexMap::from_iter(iter), } } } macro_rules! delegate_iterator { (($name:ident $($generics:tt)*) => $item:ty) => { #[allow(single_use_lifetimes)] impl $($generics)* Iterator for $name $($generics)* { type Item = $item; #[inline] fn next(&mut self) -> Option { self.iter.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } #[allow(single_use_lifetimes)] impl $($generics)* ExactSizeIterator for $name $($generics)* { #[inline] fn len(&self) -> usize { self.iter.len() } } } } /// Iterator over `&serde_yml::Mapping`. #[derive(Debug)] pub struct Iter<'a> { iter: indexmap::map::Iter<'a, Value, Value>, } delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value)); impl<'a> IntoIterator for &'a Mapping { type Item = (&'a Value, &'a Value); type IntoIter = Iter<'a>; #[inline] fn into_iter(self) -> Self::IntoIter { Iter { iter: self.map.iter(), } } } /// Iterator over `&mut serde_yml::Mapping`. #[derive(Debug)] pub struct IterMut<'a> { iter: indexmap::map::IterMut<'a, Value, Value>, } delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value)); impl<'a> IntoIterator for &'a mut Mapping { type Item = (&'a Value, &'a mut Value); type IntoIter = IterMut<'a>; #[inline] fn into_iter(self) -> Self::IntoIter { IterMut { iter: self.map.iter_mut(), } } } /// Iterator over `serde_yml::Mapping` by value. #[derive(Debug)] pub struct IntoIter { iter: indexmap::map::IntoIter, } delegate_iterator!((IntoIter) => (Value, Value)); impl IntoIterator for Mapping { type Item = (Value, Value); type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { iter: self.map.into_iter(), } } } /// Iterator of the keys of a `&serde_yml::Mapping`. #[derive(Debug)] pub struct Keys<'a> { iter: indexmap::map::Keys<'a, Value, Value>, } delegate_iterator!((Keys<'a>) => &'a Value); /// Iterator of the keys of a `serde_yml::Mapping`. #[derive(Debug)] pub struct IntoKeys { iter: indexmap::map::IntoKeys, } delegate_iterator!((IntoKeys) => Value); /// Iterator of the values of a `&serde_yml::Mapping`. #[derive(Debug)] pub struct Values<'a> { iter: indexmap::map::Values<'a, Value, Value>, } delegate_iterator!((Values<'a>) => &'a Value); /// Iterator of the values of a `&mut serde_yml::Mapping`. #[derive(Debug)] pub struct ValuesMut<'a> { iter: indexmap::map::ValuesMut<'a, Value, Value>, } delegate_iterator!((ValuesMut<'a>) => &'a mut Value); /// Iterator of the values of a `serde_yml::Mapping`. #[derive(Debug)] pub struct IntoValues { iter: indexmap::map::IntoValues, } delegate_iterator!((IntoValues) => Value); /// Entry for an existing key-value pair or a vacant location to insert one. #[derive(Debug)] pub enum Entry<'a> { /// Existing slot with equivalent key. Occupied(OccupiedEntry<'a>), /// Vacant slot (no equivalent key in the map). Vacant(VacantEntry<'a>), } /// A view into an occupied entry in a [`Mapping`]. It is part of the [`Entry`] /// enum. #[derive(Debug)] pub struct OccupiedEntry<'a> { occupied: indexmap::map::OccupiedEntry<'a, Value, Value>, } /// A view into a vacant entry in a [`Mapping`]. It is part of the [`Entry`] /// enum. #[derive(Debug)] pub struct VacantEntry<'a> { vacant: indexmap::map::VacantEntry<'a, Value, Value>, } impl<'a> Entry<'a> { /// Returns a reference to this entry's key. pub fn key(&self) -> &Value { match self { Entry::Vacant(e) => e.key(), Entry::Occupied(e) => e.key(), } } /// Ensures a value is in the entry by inserting the default if empty, and /// returns a mutable reference to the value in the entry. pub fn or_insert(self, default: Value) -> &'a mut Value { match self { Entry::Vacant(entry) => entry.insert(default), Entry::Occupied(entry) => entry.into_mut(), } } /// Ensures a value is in the entry by inserting the result of the default /// function if empty, and returns a mutable reference to the value in the /// entry. pub fn or_insert_with(self, default: F) -> &'a mut Value where F: FnOnce() -> Value, { match self { Entry::Vacant(entry) => entry.insert(default()), Entry::Occupied(entry) => entry.into_mut(), } } /// Provides in-place mutable access to an occupied entry before any /// potential inserts into the map. pub fn and_modify(self, f: F) -> Self where F: FnOnce(&mut Value), { match self { Entry::Occupied(mut entry) => { f(entry.get_mut()); Entry::Occupied(entry) } Entry::Vacant(entry) => Entry::Vacant(entry), } } } impl<'a> OccupiedEntry<'a> { /// Gets a reference to the key in the entry. #[inline] pub fn key(&self) -> &Value { self.occupied.key() } /// Gets a reference to the value in the entry. #[inline] pub fn get(&self) -> &Value { self.occupied.get() } /// Gets a mutable reference to the value in the entry. #[inline] pub fn get_mut(&mut self) -> &mut Value { self.occupied.get_mut() } /// Converts the entry into a mutable reference to its value. #[inline] pub fn into_mut(self) -> &'a mut Value { self.occupied.into_mut() } /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns /// the entry's old value. #[inline] pub fn insert(&mut self, value: Value) -> Value { self.occupied.insert(value) } /// Takes the value of the entry out of the map, and returns it. #[inline] pub fn remove(self) -> Value { self.occupied.swap_remove() } /// Remove and return the key, value pair stored in the map for this entry. #[inline] pub fn remove_entry(self) -> (Value, Value) { self.occupied.swap_remove_entry() } } impl<'a> VacantEntry<'a> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. #[inline] pub fn key(&self) -> &Value { self.vacant.key() } /// Takes ownership of the key, leaving the entry vacant. #[inline] pub fn into_key(self) -> Value { self.vacant.into_key() } /// Sets the value of the entry with the VacantEntry's key, and returns a /// mutable reference to it. #[inline] pub fn insert(self, value: Value) -> &'a mut Value { self.vacant.insert(value) } } /// `Mapping` implements `Serialize` using the `serde` crate. impl Serialize for Mapping { #[inline] fn serialize( &self, serializer: S, ) -> Result { use serde::ser::SerializeMap; let mut map_serializer = serializer.serialize_map(Some(self.len()))?; for (k, v) in self { map_serializer.serialize_entry(k, v)?; } map_serializer.end() } } /// `Mapping` implements `Deserialize` using the `serde` crate. impl<'de> Deserialize<'de> for Mapping { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { type Value = Mapping; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_str("a YAML mapping") } #[inline] fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(Mapping::new()) } #[inline] fn visit_map( self, mut data: A, ) -> Result where A: serde::de::MapAccess<'de>, { let mut mapping = Mapping::new(); while let Some(key) = data.next_key()? { match mapping.entry(key) { Entry::Occupied(entry) => { return Err(serde::de::Error::custom( DuplicateKeyError { entry }, )); } Entry::Vacant(entry) => { let value = data.next_value()?; entry.insert(value); } } } Ok(mapping) } } deserializer.deserialize_map(Visitor) } } #[derive(Debug)] /// Error returned when a duplicate key is encountered while deserializing a /// `serde_yml::Mapping`. /// /// This error contains the key-value pair that caused the conflict. pub struct DuplicateKeyError<'a> { /// The key-value pair that caused the conflict. pub entry: OccupiedEntry<'a>, } /// `DuplicateKeyError` implements `Display` to provide a human-readable error impl Display for DuplicateKeyError<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("duplicate entry ")?; match self.entry.key() { Value::Null => formatter.write_str("with null key"), Value::Bool(boolean) => { write!(formatter, "with key `{}`", boolean) } Value::Number(number) => { write!(formatter, "with key {}", number) } Value::String(string) => { write!(formatter, "with key {:?}", string) } Value::Sequence(_) | Value::Mapping(_) | Value::Tagged(_) => formatter.write_str("in YAML map"), } } } serde_yml-0.0.12/src/modules/error.rs000064400000000000000000000323561046102023000156360ustar 00000000000000use crate::{ libyml::{emitter, error as libyml}, modules::path::Path, }; use serde::{de, ser}; use std::{ error::Error as StdError, fmt::{self, Debug, Display}, io, result, string, sync::Arc, }; /// Represents a position in the YAML input. #[derive(Debug)] pub struct Pos { /// The mark representing the position. mark: libyml::Mark, /// The path to the position. path: String, } /// The input location where an error occurred. #[derive(Clone, Copy, Debug)] pub struct Location { /// The byte index of the error. index: usize, /// The line of the error. line: usize, /// The column of the error. column: usize, } impl Location { /// Returns the byte index where the error occurred. pub fn index(&self) -> usize { self.index } /// Returns the line number where the error occurred. pub fn line(&self) -> usize { self.line } /// Returns the column number where the error occurred. pub fn column(&self) -> usize { self.column } // This function is intended for internal use only to maintain decoupling with the yaml crate. #[doc(hidden)] fn from_mark(mark: libyml::Mark) -> Self { Location { index: mark.index() as usize, // `line` and `column` returned from libyml are 0-indexed but all error messages add +1 to this value. line: mark.line() as usize + 1, column: mark.column() as usize + 1, } } } /// An error that occurred during YAML serialization or deserialization. /// /// This struct wraps an internal error representation, `ErrorImpl`, and provides methods for /// accessing the error's location and a shared reference to the internal error. pub struct Error(Box); /// Alias for a `Result` with the error type `serde_yml::Error`. pub type Result = result::Result; /// The internal representation of an error. /// /// This enum represents various errors that can occur during YAML serialization or deserialization, /// including I/O errors, UTF-8 conversion errors, and errors originating from the `libyml` library. #[derive(Debug)] pub enum ErrorImpl { /// A generic error message with an optional position. Message(String, Option), /// An error originating from the `libyml` library. 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. FromUtf8(string::FromUtf8Error), /// An error indicating that the end of the YAML stream was reached unexpectedly. EndOfStream, /// An error indicating that more than one YAML document was encountered. MoreThanOneDocument, /// An error indicating that the recursion limit was exceeded. RecursionLimitExceeded(libyml::Mark), /// An error indicating that the repetition limit was exceeded. RepetitionLimitExceeded, /// An error indicating that byte-based YAML is unsupported. BytesUnsupported, /// An error indicating that an unknown anchor was encountered. UnknownAnchor(libyml::Mark), /// An error indicating that serializing a nested enum is not supported. SerializeNestedEnum, /// An error indicating that a scalar value was encountered in a merge operation. ScalarInMerge, /// An error indicating that a tagged value was encountered in a merge operation. TaggedInMerge, /// An error indicating that a scalar value was encountered in a merge element. ScalarInMergeElement, /// An error indicating that a sequence was encountered in a merge element. SequenceInMergeElement, /// An error indicating that an empty tag was encountered. EmptyTag, /// An error indicating that parsing a number failed. FailedToParseNumber, /// A shared error implementation. Shared(Arc), } impl Display for ErrorImpl { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorImpl::Message(msg, _) => write!(f, "Error: {}", msg), 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"), ErrorImpl::MoreThanOneDocument => write!(f, "Multiple YAML Documents Error: Deserializing from YAML containing more than one document is not supported"), ErrorImpl::RecursionLimitExceeded(_) => write!(f, "Recursion Limit Exceeded: The recursive depth limit was exceeded while parsing the YAML"), ErrorImpl::RepetitionLimitExceeded => write!(f, "Repetition Limit Exceeded: The repetition limit was exceeded while parsing the YAML"), ErrorImpl::BytesUnsupported => write!(f, "Unsupported Bytes Error: Serialization and deserialization of bytes in YAML is not implemented"), ErrorImpl::UnknownAnchor(_) => write!(f, "Unknown Anchor Error: An unknown anchor was encountered in the YAML"), ErrorImpl::SerializeNestedEnum => write!(f, "Nested Enum Serialization Error: Serializing nested enums in YAML is not supported"), ErrorImpl::ScalarInMerge => write!(f, "Invalid Merge Error: Expected a mapping or list of mappings for merging, but found a scalar value"), ErrorImpl::TaggedInMerge => write!(f, "Invalid Merge Error: Unexpected tagged value encountered in a merge operation"), ErrorImpl::ScalarInMergeElement => write!(f, "Invalid Merge Element Error: Expected a mapping for merging, but found a scalar value"), ErrorImpl::SequenceInMergeElement => write!(f, "Invalid Merge Element Error: Expected a mapping for merging, but found a sequence"), ErrorImpl::EmptyTag => write!(f, "Empty Tag Error: Empty YAML tags are not allowed"), ErrorImpl::FailedToParseNumber => write!(f, "Number Parsing Error: Failed to parse the YAML number"), ErrorImpl::Shared(_) => write!(f, "Shared Error: An error occurred in the shared error implementation"), } } } impl Error { /// Returns the I/O error that caused this error, if available. pub fn io_error(&self) -> Option<&io::Error> { if let ErrorImpl::IoError(err) = &*self.0 { Some(err) } else { None } } /// Returns the location where the error occurred, if available. pub fn location(&self) -> Option { self.0.location() } /// Returns a shared reference to the internal error representation. /// /// This method is useful when you need to share an error between multiple threads or for /// other use cases where a shared reference is required. pub fn shared(self) -> Arc { if let ErrorImpl::Shared(err) = *self.0 { err } else { Arc::from(self.0) } } } /// Creates a new `Error` from the given `ErrorImpl`. pub fn new(inner: ErrorImpl) -> Error { Error(Box::new(inner)) } /// Creates a new `Error` from a shared `ErrorImpl`. pub fn shared(shared: Arc) -> Error { Error(Box::new(ErrorImpl::Shared(shared))) } /// Fixes the mark and path in an error. pub fn fix_mark( mut error: Error, mark: libyml::Mark, path: Path<'_>, ) -> Error { if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() { *none = Some(Pos { mark, path: path.to_string(), }); } error } impl From for Error { fn from(err: libyml::Error) -> Self { Error(Box::new(ErrorImpl::Libyml(err))) } } impl From for Error { fn from(err: emitter::Error) -> Self { match err { emitter::Error::Libyml(err) => Self::from(err), emitter::Error::Io(err) => new(ErrorImpl::IoError(err)), } } } impl StdError for Error { fn source(&self) -> Option<&(dyn StdError + 'static)> { self.0.source() } } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.display(f) } } // Remove two layers of verbosity from the debug representation. Humans often // end up seeing this representation because it is what unwrap() shows. impl Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.debug(f) } } impl ser::Error for Error { fn custom(msg: T) -> Self { Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) } } impl de::Error for Error { fn custom(msg: T) -> Self { Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) } } impl ErrorImpl { fn location(&self) -> Option { self.mark().map(Location::from_mark) } fn source(&self) -> Option<&(dyn StdError + 'static)> { match self { ErrorImpl::IoError(err) => err.source(), ErrorImpl::FromUtf8(err) => err.source(), ErrorImpl::Shared(err) => err.source(), _ => None, } } fn mark(&self) -> Option { match self { ErrorImpl::Message(_, Some(Pos { mark, path: _ })) | ErrorImpl::RecursionLimitExceeded(mark) | ErrorImpl::UnknownAnchor(mark) => Some(*mark), ErrorImpl::Libyml(err) => Some(err.mark()), ErrorImpl::Shared(err) => err.mark(), _ => None, } } fn message(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorImpl::Message(description, None) => f.write_str(description), ErrorImpl::Message(description, Some(Pos { mark: _, path })) => { if path != "." { write!(f, "{}: ", path)?; } f.write_str(description) } 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"), ErrorImpl::MoreThanOneDocument => f.write_str( "deserializing from YAML containing more than one document is not supported", ), ErrorImpl::RecursionLimitExceeded(_mark) => { f.write_str("recursion limit exceeded") } ErrorImpl::RepetitionLimitExceeded => { f.write_str("repetition limit exceeded") } ErrorImpl::BytesUnsupported => { f.write_str("serialization and deserialization of bytes in YAML is not implemented") } ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"), ErrorImpl::SerializeNestedEnum => { f.write_str("serializing nested enums in YAML is not supported yet") } ErrorImpl::ScalarInMerge => { f.write_str("expected a mapping or list of mappings for merging, but found scalar") } ErrorImpl::TaggedInMerge => { f.write_str("unexpected tagged value in merge") } ErrorImpl::ScalarInMergeElement => { f.write_str("expected a mapping for merging, but found scalar") } ErrorImpl::SequenceInMergeElement => { f.write_str("expected a mapping for merging, but found sequence") } ErrorImpl::EmptyTag => f.write_str("empty YAML tag is not allowed"), ErrorImpl::FailedToParseNumber => { f.write_str("failed to parse YAML number") } ErrorImpl::Shared(_) => unreachable!(), } } fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorImpl::Libyml(err) => Display::fmt(err, f), ErrorImpl::Shared(err) => err.display(f), _ => { self.message(f)?; if let Some(location) = self.mark() { if location.line() != 0 || location.column() != 0 { write!(f, " at {}", location)?; } } Ok(()) } } } fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorImpl::Libyml(err) => Debug::fmt(err, f), ErrorImpl::Shared(err) => err.debug(f), _ => { f.write_str("Error(")?; struct MessageNoMark<'a>(&'a ErrorImpl); impl Display for MessageNoMark<'_> { fn fmt( &self, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { self.0.message(f) } } let msg = MessageNoMark(self).to_string(); Debug::fmt(&msg, f)?; if let Some(mark) = self.mark() { write!( f, ", line: {}, column: {}", mark.line() + 1, mark.column() + 1, )?; } f.write_str(")") } } } } serde_yml-0.0.12/src/modules/mod.rs000064400000000000000000000002611046102023000152520ustar 00000000000000/// The `error` module contains the `Error` struct and its implementation. pub mod error; /// The `path` module contains the `Path` struct and its implementation. pub mod path; serde_yml-0.0.12/src/modules/path.rs000064400000000000000000000054121046102023000154320ustar 00000000000000use std::fmt::{self, Display}; /// `Path` represents the path to the current value in the input, like `dependencies.serde.typo1`. /// /// The `Path` enum provides a way to represent different types of paths in a YAML-like structure. /// It can be used to track the location of values within the input and provide meaningful error messages. /// /// # Variants /// /// - `Root`: Represents the root path. /// - `Seq`: Represents a sequence (array) path with a reference to the parent path and an index. /// - `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, PartialEq)] pub enum Path<'a> { /// Represents the root path. Root, /// Represents a sequence (array) path with a reference to the parent path and an index. Seq { /// The parent path. parent: &'a Path<'a>, /// The index within the sequence. index: usize, }, /// Represents a map (object) path with a reference to the parent path and a key. Map { /// The parent path. parent: &'a Path<'a>, /// The key within the map. key: &'a str, }, /// Represents an alias path with a reference to the parent path. Alias { /// The parent path. parent: &'a Path<'a>, }, /// Represents an unknown path with a reference to the parent path. Unknown { /// The parent path. parent: &'a Path<'a>, }, } impl Display for Path<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// `Parent` is a helper struct used to format the parent path. /// /// It implements the `Display` trait to recursively format the parent path. struct Parent<'a>(&'a Path<'a>); impl Display for Parent<'_> { fn fmt( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { match self.0 { Path::Root => Ok(()), path => write!(formatter, "{}.", path), } } } match self { Path::Root => formatter.write_str("."), Path::Seq { parent, index } => { write!(formatter, r"{}\[{}\]", Parent(parent), index) } Path::Map { parent, key } => { write!(formatter, "{}{}", Parent(parent), key) } Path::Alias { parent } => { write!(formatter, "{}", Parent(parent)) } Path::Unknown { parent } => { write!(formatter, "{}?", Parent(parent)) } } } } serde_yml-0.0.12/src/number.rs000064400000000000000000000270061046102023000143210ustar 00000000000000use crate::{ de, modules::error::{self, Error, ErrorImpl}, }; use serde::{ de::{Unexpected, Visitor}, forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer, }; use std::{ cmp::Ordering, fmt::{self, Display}, hash::{Hash, Hasher}, str::FromStr, }; /// Represents a YAML number, whether integer or floating point. #[derive(Copy, Clone, PartialEq, PartialOrd)] pub struct Number { n: N, } /// Enum representing different variants of numbers. #[derive(Copy, Clone, Debug)] #[repr(C)] enum N { /// Represents a positive integer. PositiveInteger(u64), /// Represents a negative integer. NegativeInteger(i64), /// Represents a floating point number. Float(f64), } impl Number { /// Returns true if the `Number` is an integer between `i64::MIN` and `i64::MAX`. /// /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to /// return the integer value. #[inline] #[allow(clippy::cast_sign_loss)] pub fn is_i64(&self) -> bool { match self.n { N::PositiveInteger(v) => v <= i64::MAX as u64, N::NegativeInteger(_) => true, N::Float(_) => false, } } /// Returns true if the `Number` is an integer between zero and `u64::MAX`. /// /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to /// return the integer value. #[inline] pub fn is_u64(&self) -> bool { match self.n { N::PositiveInteger(_) => true, N::NegativeInteger(_) | N::Float(_) => false, } } /// Returns true if the `Number` can be represented by f64. /// /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to /// return the floating point value. #[inline] pub fn is_f64(&self) -> bool { match self.n { N::Float(_) => true, N::PositiveInteger(_) | N::NegativeInteger(_) => false, } } /// If the `Number` is an integer, represent it as i64 if possible. Returns /// None otherwise. #[inline] pub fn as_i64(&self) -> Option { match self.n { N::PositiveInteger(n) => { if n <= i64::MAX as u64 { Some(n as i64) } else { None } } N::NegativeInteger(n) => Some(n), N::Float(_) => None, } } /// If the `Number` is an integer, represent it as u64 if possible. Returns /// None otherwise. #[inline] pub fn as_u64(&self) -> Option { match self.n { N::PositiveInteger(n) => Some(n), N::NegativeInteger(_) | N::Float(_) => None, } } /// Represents the number as f64 if possible. Returns None otherwise. #[inline] pub fn as_f64(&self) -> Option { match self.n { N::PositiveInteger(n) => Some(n as f64), N::NegativeInteger(n) => Some(n as f64), N::Float(n) => Some(n), } } /// Returns true if this value is NaN and false otherwise. #[inline] pub fn is_nan(&self) -> bool { match self.n { N::PositiveInteger(_) | N::NegativeInteger(_) => false, N::Float(f) => f.is_nan(), } } /// Returns true if this value is positive infinity or negative infinity and /// false otherwise. #[inline] pub fn is_infinite(&self) -> bool { match self.n { N::PositiveInteger(_) | N::NegativeInteger(_) => false, N::Float(f) => f.is_infinite(), } } /// Returns true if this number is neither infinite nor NaN. #[inline] pub fn is_finite(&self) -> bool { match self.n { N::PositiveInteger(_) | N::NegativeInteger(_) => true, N::Float(f) => f.is_finite(), } } } impl Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self.n { N::PositiveInteger(i) => write!(formatter, "{}", i), N::NegativeInteger(i) => write!(formatter, "{}", i), N::Float(f) if f.is_nan() => formatter.write_str(".nan"), N::Float(f) if f.is_infinite() => { if f.is_sign_negative() { formatter.write_str("-.inf") } else { formatter.write_str(".inf") } } N::Float(f) => { write!(formatter, "{}", ryu::Buffer::new().format(f)) } } } } impl FromStr for Number { type Err = Error; fn from_str(repr: &str) -> Result { if let Ok(result) = de::visit_int(NumberVisitor, repr) { return result; } if !de::digits_but_not_number(repr) { if let Some(float) = de::parse_f64(repr) { return Ok(float.into()); } } Err(error::new(ErrorImpl::FailedToParseNumber)) } } impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) { (N::PositiveInteger(a), N::PositiveInteger(b)) => a == b, (N::NegativeInteger(a), N::NegativeInteger(b)) => a == b, (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN; // the bit representation isn't preserved true } else { a == b } } _ => false, } } } impl PartialOrd for N { fn partial_cmp(&self, other: &Self) -> Option { match (*self, *other) { (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN Some(Ordering::Equal) } else { a.partial_cmp(&b) } } _ => Some(self.total_cmp(other)), } } } impl N { fn total_cmp(&self, other: &Self) -> Ordering { match (*self, *other) { (N::PositiveInteger(a), N::PositiveInteger(b)) => a.cmp(&b), (N::NegativeInteger(a), N::NegativeInteger(b)) => a.cmp(&b), // negint is always less than zero (N::NegativeInteger(_), N::PositiveInteger(_)) => { Ordering::Less } (N::PositiveInteger(_), N::NegativeInteger(_)) => { Ordering::Greater } (N::Float(a), N::Float(b)) => { a.partial_cmp(&b).unwrap_or_else(|| { // arbitrarily sort the NaN last if !a.is_nan() { Ordering::Less } else if !b.is_nan() { Ordering::Greater } else { Ordering::Equal } }) } // arbitrarily sort integers below floats (_, N::Float(_)) => Ordering::Less, (N::Float(_), _) => Ordering::Greater, } } } impl Number { pub(crate) fn total_cmp(&self, other: &Self) -> Ordering { self.n.total_cmp(&other.n) } } impl Serialize for Number { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self.n { N::PositiveInteger(i) => serializer.serialize_u64(i), N::NegativeInteger(i) => serializer.serialize_i64(i), N::Float(f) => serializer.serialize_f64(f), } } } struct NumberVisitor; impl Visitor<'_> for NumberVisitor { type Value = Number; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_str("a number") } #[inline] fn visit_i64(self, value: i64) -> Result { Ok(value.into()) } #[inline] fn visit_u64(self, value: u64) -> Result { Ok(value.into()) } #[inline] fn visit_f64(self, value: f64) -> Result { Ok(value.into()) } } impl<'de> Deserialize<'de> for Number { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any(NumberVisitor) } } impl<'de> Deserializer<'de> for Number { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self.n { N::PositiveInteger(i) => visitor.visit_u64(i), N::NegativeInteger(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } impl<'de> Deserializer<'de> for &Number { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self.n { N::PositiveInteger(i) => visitor.visit_u64(i), N::NegativeInteger(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } macro_rules! from_signed { ($($signed_ty:ident)*) => { $( impl From<$signed_ty> for Number { #[inline] #[allow(clippy::cast_sign_loss)] fn from(i: $signed_ty) -> Self { if i < 0 { Number { n: N::NegativeInteger(i.try_into().unwrap()) } } else { Number { n: N::PositiveInteger(i as u64) } } } } )* }; } macro_rules! from_unsigned { ($($unsigned_ty:ident)*) => { $( impl From<$unsigned_ty> for Number { #[inline] fn from(u: $unsigned_ty) -> Self { Number { n: N::PositiveInteger(u.try_into().unwrap()) } } } )* }; } from_signed!(i8 i16 i32 i64 isize); from_unsigned!(u8 u16 u32 u64 usize); impl From for Number { fn from(f: f32) -> Self { Number::from(f as f64) } } impl From for Number { fn from(mut f: f64) -> Self { if f.is_nan() { // Destroy NaN sign, signalling, and payload. YAML only has one NaN. f = f64::NAN.copysign(1.0); } Number { n: N::Float(f) } } } impl Hash for Number { fn hash(&self, state: &mut H) { match &self.n { N::PositiveInteger(u) => { u.hash(state); } N::NegativeInteger(i) => { i.hash(state); } N::Float(f) => { f.to_bits().hash(state); } } } } /// Returns an `Unexpected` variant based on the given `Number`. pub(crate) fn unexpected(number: &Number) -> Unexpected<'_> { match number.n { N::PositiveInteger(u) => Unexpected::Unsigned(u), N::NegativeInteger(i) => Unexpected::Signed(i), N::Float(f) => Unexpected::Float(f), } } serde_yml-0.0.12/src/ser.rs000064400000000000000000000517671046102023000136350ustar 00000000000000//! YAML Serialization //! //! This module provides YAML serialization with the type `Serializer`. use crate::libyml; use crate::libyml::emitter::{ Emitter, Event, Mapping, Scalar, ScalarStyle, Sequence, }; use crate::{ modules::error::{self, Error, ErrorImpl}, value::tagged::{self, MaybeTag}, }; use serde::{ de::Visitor, ser::{self, Serializer as _}, }; use std::{ fmt::{self, Display}, io, marker::PhantomData, mem, num, str, }; type Result = std::result::Result; /// A structure for serializing Rust values into YAML. /// /// # Example /// /// ``` /// use serde::Serialize; /// use std::collections::BTreeMap; /// /// fn main() -> serde_yml::Result<()> { /// let mut buffer = Vec::new(); /// let mut ser = serde_yml::Serializer::new(&mut buffer); /// /// let mut object = BTreeMap::new(); /// object.insert("k", 107); /// object.serialize(&mut ser)?; /// /// object.insert("J", 74); /// object.serialize(&mut ser)?; /// /// assert_eq!(buffer, b"k: 107\n---\nJ: 74\nk: 107\n"); /// Ok(()) /// } /// ``` #[derive(Debug)] pub struct Serializer { /// The configuration of the serializer. pub config: SerializerConfig, /// The depth of the current serialization. pub depth: usize, /// The current state of the serializer. pub state: State, /// The YAML emitter. pub emitter: Emitter<'static>, /// The underlying writer. pub writer: PhantomData, } /// The configuration of the serializer. #[derive(Copy, Clone, Debug, Default)] pub struct SerializerConfig { /// When set to `true`, all unit variants will be serialized as tags, i.e. `!Unit` instead of `Unit`. pub tag_unit_variants: bool, } /// The state of the serializer. #[derive(Debug)] pub enum State { /// Nothing in particular. NothingInParticular, /// Check for a tag. CheckForTag, /// Check for a duplicate tag. CheckForDuplicateTag, /// Found a tag. FoundTag(String), /// Already tagged. AlreadyTagged, } impl Serializer where W: io::Write, { /// Creates a new YAML serializer. pub fn new(writer: W) -> Self { Self::new_with_config(writer, SerializerConfig::default()) } /// Creates a new YAML serializer with a configuration. pub fn new_with_config( writer: W, config: SerializerConfig, ) -> Self { let mut emitter = Emitter::new({ let writer = Box::new(writer); unsafe { mem::transmute::, Box>( writer, ) } }); emitter.emit(Event::StreamStart).unwrap(); Serializer { config, depth: 0, state: State::NothingInParticular, emitter, writer: PhantomData, } } /// Calls [`.flush()`](io::Write::flush) on the underlying `io::Write` /// object. pub fn flush(&mut self) -> Result<()> { self.emitter.flush()?; Ok(()) } /// Unwrap the underlying `io::Write` object from the `Serializer`. pub fn into_inner(mut self) -> Result { self.emitter.emit(Event::StreamEnd)?; self.emitter.flush()?; let writer = self.emitter.into_inner(); Ok(*unsafe { Box::from_raw(Box::into_raw(writer).cast::()) }) } /// Emit a scalar value. pub fn emit_scalar( &mut self, mut scalar: Scalar<'_>, ) -> Result<()> { self.flush_mapping_start()?; if let Some(tag) = self.take_tag() { scalar.tag = Some(tag); } self.value_start()?; self.emitter.emit(Event::Scalar(scalar))?; self.value_end() } /// Emit a sequence start. pub fn emit_sequence_start(&mut self) -> Result<()> { self.flush_mapping_start()?; self.value_start()?; let tag = self.take_tag(); self.emitter.emit(Event::SequenceStart(Sequence { tag }))?; Ok(()) } /// Emit a sequence end. pub fn emit_sequence_end(&mut self) -> Result<()> { self.emitter.emit(Event::SequenceEnd)?; self.value_end() } /// Emit a mapping start. pub fn emit_mapping_start(&mut self) -> Result<()> { self.flush_mapping_start()?; self.value_start()?; let tag = self.take_tag(); self.emitter.emit(Event::MappingStart(Mapping { tag }))?; Ok(()) } /// Emit a mapping end. pub fn emit_mapping_end(&mut self) -> Result<()> { self.emitter.emit(Event::MappingEnd)?; self.value_end() } /// Emit a value start. pub fn value_start(&mut self) -> Result<()> { if self.depth == 0 { self.emitter.emit(Event::DocumentStart)?; } self.depth += 1; Ok(()) } /// Emit a value end. pub fn value_end(&mut self) -> Result<()> { self.depth -= 1; if self.depth == 0 { self.emitter.emit(Event::DocumentEnd)?; } Ok(()) } /// Take the tag if it exists. pub fn take_tag(&mut self) -> Option { let state = mem::replace(&mut self.state, State::NothingInParticular); if let State::FoundTag(mut tag) = state { if !tag.starts_with('!') { tag.insert(0, '!'); } Some(tag) } else { self.state = state; None } } /// Flush the mapping start. pub fn flush_mapping_start(&mut self) -> Result<()> { if let State::CheckForTag = self.state { self.state = State::NothingInParticular; self.emit_mapping_start()?; } else if let State::CheckForDuplicateTag = self.state { self.state = State::NothingInParticular; } Ok(()) } } impl ser::Serializer for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; type SerializeSeq = Self; type SerializeTuple = Self; type SerializeTupleStruct = Self; type SerializeTupleVariant = Self; type SerializeMap = Self; type SerializeStruct = Self; type SerializeStructVariant = Self; fn serialize_bool(self, v: bool) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: if v { "true" } else { "false" }, style: ScalarStyle::Plain, }) } fn serialize_i8(self, v: i8) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_i16(self, v: i16) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_i32(self, v: i32) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_i64(self, v: i64) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_i128(self, v: i128) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_u8(self, v: u8) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_u16(self, v: u16) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_u32(self, v: u32) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_u64(self, v: u64) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_u128(self, v: u128) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: itoa::Buffer::new().format(v), style: ScalarStyle::Plain, }) } fn serialize_f32(self, v: f32) -> Result<()> { let mut buffer = ryu::Buffer::new(); self.emit_scalar(Scalar { tag: None, value: match v.classify() { num::FpCategory::Infinite if v.is_sign_positive() => { ".inf" } num::FpCategory::Infinite => "-.inf", num::FpCategory::Nan => ".nan", _ => buffer.format_finite(v), }, style: ScalarStyle::Plain, }) } fn serialize_f64(self, v: f64) -> Result<()> { let mut buffer = ryu::Buffer::new(); self.emit_scalar(Scalar { tag: None, value: match v.classify() { num::FpCategory::Infinite if v.is_sign_positive() => { ".inf" } num::FpCategory::Infinite => "-.inf", num::FpCategory::Nan => ".nan", _ => buffer.format_finite(v), }, style: ScalarStyle::Plain, }) } fn serialize_char(self, value: char) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: value.encode_utf8(&mut [0u8; 4]), style: ScalarStyle::SingleQuoted, }) } fn serialize_str(self, value: &str) -> Result<()> { struct InferScalarStyle; impl Visitor<'_> for InferScalarStyle { type Value = ScalarStyle; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_str("I wonder") } fn visit_bool(self, _v: bool) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_i64(self, _v: i64) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_i128(self, _v: i128) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_u64(self, _v: u64) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_u128(self, _v: u128) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_f64(self, _v: f64) -> Result { Ok(ScalarStyle::SingleQuoted) } fn visit_str(self, v: &str) -> Result { if crate::de::ambiguous_string(v) { Ok(ScalarStyle::SingleQuoted) } else { Ok(ScalarStyle::Any) } } fn visit_unit(self) -> Result { Ok(ScalarStyle::SingleQuoted) } } let style = match value { // Backwards compatibility with old YAML boolean scalars. // See https://yaml.org/type/bool.html "y" | "Y" | "yes" | "Yes" | "YES" | "n" | "N" | "no" | "No" | "NO" | "true" | "True" | "TRUE" | "false" | "False" | "FALSE" | "on" | "On" | "ON" | "off" | "Off" | "OFF" => ScalarStyle::SingleQuoted, _ if value.contains('\n') => ScalarStyle::Literal, _ => { let result = crate::de::visit_untagged_scalar( InferScalarStyle, value, None, libyml::parser::ScalarStyle::Plain, ); result.unwrap_or(ScalarStyle::Any) } }; self.emit_scalar(Scalar { tag: None, value, style, }) } fn serialize_bytes(self, _value: &[u8]) -> Result<()> { Err(error::new(ErrorImpl::BytesUnsupported)) } fn serialize_unit(self) -> Result<()> { self.emit_scalar(Scalar { tag: None, value: "null", style: ScalarStyle::Plain, }) } fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { self.serialize_unit() } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result<()> { if !self.config.tag_unit_variants { self.serialize_str(variant) } else { if let State::FoundTag(_) = self.state { return Err(error::new(ErrorImpl::SerializeNestedEnum)); } self.state = State::FoundTag(variant.to_owned()); self.emit_scalar(Scalar { tag: None, value: "", style: ScalarStyle::Plain, }) } } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result<()> where T: ?Sized + ser::Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + ser::Serialize, { if let State::FoundTag(_) = self.state { return Err(error::new(ErrorImpl::SerializeNestedEnum)); } self.state = State::FoundTag(variant.to_owned()); value.serialize(&mut *self) } fn serialize_none(self) -> Result<()> { self.serialize_unit() } fn serialize_some(self, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { value.serialize(self) } fn serialize_seq( self, _len: Option, ) -> Result { self.emit_sequence_start()?; Ok(self) } fn serialize_tuple( self, _len: usize, ) -> Result { self.emit_sequence_start()?; Ok(self) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { self.emit_sequence_start()?; Ok(self) } fn serialize_tuple_variant( self, _enm: &'static str, _idx: u32, variant: &'static str, _len: usize, ) -> Result { if let State::FoundTag(_) = self.state { return Err(error::new(ErrorImpl::SerializeNestedEnum)); } self.state = State::FoundTag(variant.to_owned()); self.emit_sequence_start()?; Ok(self) } fn serialize_map( self, len: Option, ) -> Result { if len == Some(1) { self.state = if let State::FoundTag(_) = self.state { self.emit_mapping_start()?; State::CheckForDuplicateTag } else { State::CheckForTag }; } else { self.emit_mapping_start()?; } Ok(self) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { self.emit_mapping_start()?; Ok(self) } fn serialize_struct_variant( self, _enm: &'static str, _idx: u32, variant: &'static str, _len: usize, ) -> Result { if let State::FoundTag(_) = self.state { return Err(error::new(ErrorImpl::SerializeNestedEnum)); } self.state = State::FoundTag(variant.to_owned()); self.emit_mapping_start()?; Ok(self) } fn collect_str(self, value: &T) -> Result where T: ?Sized + Display, { let string = if let State::CheckForTag | State::CheckForDuplicateTag = self.state { match tagged::check_for_tag(value) { MaybeTag::NotTag(string) => string, MaybeTag::Tag(string) => { return if let State::CheckForDuplicateTag = self.state { Err(error::new(ErrorImpl::SerializeNestedEnum)) } else { self.state = State::FoundTag(string); Ok(()) }; } } } else { value.to_string() }; self.serialize_str(&string) } } impl ser::SerializeSeq for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { elem.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_sequence_end() } } impl ser::SerializeTuple for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { elem.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_sequence_end() } } impl ser::SerializeTupleStruct for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { value.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_sequence_end() } } impl ser::SerializeTupleVariant for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, v: &V) -> Result<()> where V: ?Sized + ser::Serialize, { v.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_sequence_end() } } impl ser::SerializeMap for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.flush_mapping_start()?; key.serialize(&mut **self) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { value.serialize(&mut **self) } fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<(), Self::Error> where K: ?Sized + ser::Serialize, V: ?Sized + ser::Serialize, { key.serialize(&mut **self)?; let tagged = matches!(self.state, State::FoundTag(_)); value.serialize(&mut **self)?; if tagged { self.state = State::AlreadyTagged; } Ok(()) } fn end(self) -> Result<()> { if let State::CheckForTag = self.state { self.emit_mapping_start()?; } if !matches!(self.state, State::AlreadyTagged) { self.emit_mapping_end()?; } self.state = State::NothingInParticular; Ok(()) } } impl ser::SerializeStruct for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &V, ) -> Result<()> where V: ?Sized + ser::Serialize, { self.serialize_str(key)?; value.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_mapping_end() } } impl ser::SerializeStructVariant for &mut Serializer where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field( &mut self, field: &'static str, v: &V, ) -> Result<()> where V: ?Sized + ser::Serialize, { self.serialize_str(field)?; v.serialize(&mut **self) } fn end(self) -> Result<()> { self.emit_mapping_end() } } /// Serialize the given data structure as YAML into the IO stream. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// return an error. pub fn to_writer(writer: W, value: &T) -> Result<()> where W: io::Write, T: ?Sized + ser::Serialize, { let mut serializer = Serializer::new(writer); value.serialize(&mut serializer) } /// Serialize the given data structure as a String of YAML. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// return an error. pub fn to_string(value: &T) -> Result where T: ?Sized + ser::Serialize, { let mut vec = Vec::with_capacity(128); to_writer(&mut vec, value)?; String::from_utf8(vec) .map_err(|error| error::new(ErrorImpl::FromUtf8(error))) } serde_yml-0.0.12/src/value/de.rs000064400000000000000000001046261046102023000145410ustar 00000000000000use crate::value::tagged::{self, TagStringVisitor}; use crate::value::TaggedValue; use crate::{number, Error, Mapping, Sequence, Value}; use serde::de::value::{BorrowedStrDeserializer, StrDeserializer}; use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer}; use serde::de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, Expected, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }; use serde::forward_to_deserialize_any; use std::fmt::Formatter; 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 D: Deserializer<'de>, { struct ValueVisitor; impl<'de> Visitor<'de> for ValueVisitor { type Value = Value; fn expecting( &self, formatter: &mut Formatter<'_>, ) -> FmtResult { formatter.write_str("any YAML value") } fn visit_bool(self, value: bool) -> Result where E: de::Error, { Ok(Value::Bool(value)) } fn visit_i64(self, value: i64) -> Result where E: de::Error, { Ok(Value::Number(value.into())) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { Ok(Value::Number(value.into())) } fn visit_f64(self, value: f64) -> Result where E: de::Error, { Ok(Value::Number(value.into())) } fn visit_str(self, value: &str) -> Result where E: de::Error, { Ok(Value::String(value.to_owned())) } fn visit_string(self, value: String) -> Result where E: de::Error, { Ok(Value::String(value)) } fn visit_unit(self) -> Result where E: de::Error, { Ok(Value::Null) } fn visit_none(self) -> Result where E: de::Error, { Ok(Value::Null) } fn visit_some( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { Deserialize::deserialize(deserializer) } fn visit_seq(self, seq: A) -> Result where A: SeqAccess<'de>, { let de = SeqAccessDeserializer::new(seq); let sequence = Sequence::deserialize(de)?; Ok(Value::Sequence(sequence)) } fn visit_map(self, map: A) -> Result where A: MapAccess<'de>, { let de = MapAccessDeserializer::new(map); let mapping = Mapping::deserialize(de)?; Ok(Value::Mapping(mapping)) } fn visit_enum( self, data: A, ) -> Result where A: EnumAccess<'de>, { let (tag, contents) = data.variant_seed(TagStringVisitor)?; let value = contents.newtype_variant()?; Ok(Value::Tagged(Box::new(TaggedValue { tag, value }))) } } deserializer.deserialize_any(ValueVisitor) } } impl Value { /// Deserializes a number from the given `Value`. fn deserialize_number<'de, V>( &self, visitor: V, ) -> Result where V: Visitor<'de>, { match self.untag_ref() { Value::Number(n) => n.deserialize_any(visitor), other => Err(other.invalid_type(&visitor)), } } } /// Visits a `Sequence` value with the given `Visitor`. fn visit_sequence<'de, V>( sequence: Sequence, visitor: V, ) -> Result where V: Visitor<'de>, { let len = sequence.len(); let mut deserializer = SeqDeserializer::new(sequence); let seq = visitor.visit_seq(&mut deserializer)?; let remaining = deserializer.iter.len(); if remaining == 0 { Ok(seq) } else { Err(Error::invalid_length(len, &"fewer elements in sequence")) } } /// Visits a borrowed `Sequence` value with the given `Visitor`. fn visit_sequence_ref<'de, V>( sequence: &'de Sequence, visitor: V, ) -> Result where V: Visitor<'de>, { let len = sequence.len(); let mut deserializer = SeqRefDeserializer::new(sequence); let seq = visitor.visit_seq(&mut deserializer)?; let remaining = deserializer.iter.len(); if remaining == 0 { Ok(seq) } else { Err(Error::invalid_length(len, &"fewer elements in sequence")) } } /// Visits a `Mapping` value with the given `Visitor`. fn visit_mapping<'de, V>( mapping: Mapping, visitor: V, ) -> Result where V: Visitor<'de>, { let len = mapping.len(); let mut deserializer = MapDeserializer::new(mapping); let map = visitor.visit_map(&mut deserializer)?; let remaining = deserializer.iter.len(); if remaining == 0 { Ok(map) } else { Err(Error::invalid_length(len, &"fewer elements in map")) } } /// Visits a borrowed `Mapping` value with the given `Visitor`. fn visit_mapping_ref<'de, V>( mapping: &'de Mapping, visitor: V, ) -> Result where V: Visitor<'de>, { let len = mapping.len(); let mut deserializer = MapRefDeserializer::new(mapping); let map = visitor.visit_map(&mut deserializer)?; let remaining = deserializer.iter.unwrap().len(); if remaining == 0 { Ok(map) } else { Err(Error::invalid_length(len, &"fewer elements in map")) } } impl<'de> Deserializer<'de> for Value { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), Value::Bool(v) => visitor.visit_bool(v), Value::Number(n) => n.deserialize_any(visitor), Value::String(v) => visitor.visit_string(v), Value::Sequence(v) => visit_sequence(v, visitor), Value::Mapping(v) => visit_mapping(v, visitor), Value::Tagged(tagged) => visitor.visit_enum(*tagged), } } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag() { Value::Bool(v) => visitor.visit_bool(v), other => Err(other.invalid_type(&visitor)), } } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_string( self, visitor: V, ) -> Result where V: Visitor<'de>, { match self.untag() { Value::String(v) => visitor.visit_string(v), other => Err(other.invalid_type(&visitor)), } } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_byte_buf(visitor) } fn deserialize_byte_buf( self, visitor: V, ) -> Result where V: Visitor<'de>, { match self.untag() { Value::String(v) => visitor.visit_string(v), Value::Sequence(v) => visit_sequence(v, visitor), other => Err(other.invalid_type(&visitor)), } } fn deserialize_option( self, visitor: V, ) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_none(), _ => visitor.visit_some(self), } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_unit_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag() { Value::Sequence(v) => visit_sequence(v, visitor), Value::Null => visit_sequence(Sequence::new(), visitor), other => Err(other.invalid_type(&visitor)), } } fn deserialize_tuple( self, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag() { Value::Mapping(v) => visit_mapping(v, visitor), Value::Null => visit_mapping(Mapping::new(), visitor), other => Err(other.invalid_type(&visitor)), } } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_enum( self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let tag; visitor.visit_enum(match self { Value::Tagged(tagged) => EnumDeserializer { tag: { tag = tagged.tag.string; tagged::nobang(&tag) }, value: Some(tagged.value), }, Value::String(variant) => EnumDeserializer { tag: { tag = variant; &tag }, value: None, }, other => { return Err(Error::invalid_type( other.unexpected(), &"a Value::Tagged enum", )); } }) } fn deserialize_identifier( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } } /// Represents an enum deserializer. struct EnumDeserializer<'a> { tag: &'a str, value: Option, } impl<'de> EnumAccess<'de> for EnumDeserializer<'_> { type Error = Error; type Variant = VariantDeserializer; fn variant_seed( self, seed: V, ) -> Result<(V::Value, Self::Variant), Error> where V: DeserializeSeed<'de>, { let str_de = StrDeserializer::::new(self.tag); let variant = seed.deserialize(str_de)?; let visitor = VariantDeserializer { value: self.value }; Ok((variant, visitor)) } } /// Represents a variant deserializer. struct VariantDeserializer { value: Option, } impl<'de> VariantAccess<'de> for VariantDeserializer { type Error = Error; fn unit_variant(self) -> Result<(), Error> { match self.value { Some(value) => value.unit_variant(), None => Ok(()), } } fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value { Some(value) => value.newtype_variant_seed(seed), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"newtype variant", )), } } fn tuple_variant( self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Some(value) => value.tuple_variant(len, visitor), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"tuple variant", )), } } fn struct_variant( self, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Some(value) => value.struct_variant(fields, visitor), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"struct variant", )), } } } /// 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(), } } } impl<'de> Deserializer<'de> for SeqDeserializer { type Error = Error; #[inline] fn deserialize_any( mut self, visitor: V, ) -> Result where V: Visitor<'de>, { let len = self.iter.len(); if len == 0 { visitor.visit_unit() } else { let ret = visitor.visit_seq(&mut self)?; let remaining = self.iter.len(); if remaining == 0 { Ok(ret) } else { Err(Error::invalid_length( len, &"fewer elements in sequence", )) } } } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl<'de> SeqAccess<'de> for SeqDeserializer { type Error = Error; fn next_element_seed( &mut self, seed: T, ) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.next() { Some(value) => seed.deserialize(value).map(Some), None => Ok(None), } } fn size_hint(&self) -> Option { match self.iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } /// 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(), value: None, } } } impl<'de> MapAccess<'de> for MapDeserializer { type Error = Error; fn next_key_seed( &mut self, seed: T, ) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.next() { Some((key, value)) => { self.value = Some(value); seed.deserialize(key).map(Some) } None => Ok(None), } } fn next_value_seed(&mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value.take() { Some(value) => seed.deserialize(value), None => panic!("visit_value called before visit_key"), } } fn size_hint(&self) -> Option { match self.iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } impl<'de> Deserializer<'de> for MapDeserializer { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_map(self) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl<'de> Deserializer<'de> for &'de Value { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), Value::Bool(v) => visitor.visit_bool(*v), Value::Number(n) => n.deserialize_any(visitor), Value::String(v) => visitor.visit_borrowed_str(v), Value::Sequence(v) => visit_sequence_ref(v, visitor), Value::Mapping(v) => visit_mapping_ref(v, visitor), Value::Tagged(tagged) => { let cloned_tagged = tagged; visitor.visit_enum(EnumDeserializer { tag: tagged::nobang(&cloned_tagged.tag.string), value: Some(cloned_tagged.clone().value), }) } } } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag_ref() { Value::Bool(v) => visitor.visit_bool(*v), other => Err(other.invalid_type(&visitor)), } } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag_ref() { Value::String(v) => visitor.visit_borrowed_str(v), other => Err(other.invalid_type(&visitor)), } } fn deserialize_string( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag_ref() { Value::String(v) => visitor.visit_borrowed_str(v), Value::Sequence(v) => visit_sequence_ref(v, visitor), other => Err(other.invalid_type(&visitor)), } } fn deserialize_byte_buf( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_bytes(visitor) } fn deserialize_option( self, visitor: V, ) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_none(), _ => visitor.visit_some(self), } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_unit_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { static EMPTY: Sequence = Sequence::new(); match self.untag_ref() { Value::Sequence(v) => visit_sequence_ref(v, visitor), Value::Null => visit_sequence_ref(&EMPTY, visitor), other => Err(other.invalid_type(&visitor)), } } fn deserialize_tuple( self, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { match self.untag_ref() { Value::Mapping(v) => visit_mapping_ref(v, visitor), Value::Null => visitor.visit_map(&mut MapRefDeserializer { iter: None, value: None, }), other => Err(other.invalid_type(&visitor)), } } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_enum( self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_enum(match self { Value::Tagged(tagged) => EnumRefDeserializer { tag: tagged::nobang(&tagged.tag.string), value: Some(&tagged.value), }, Value::String(variant) => EnumRefDeserializer { tag: variant, value: None, }, other => { return Err(Error::invalid_type( other.unexpected(), &"a Value::Tagged enum", )); } }) } fn deserialize_identifier( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { 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, ) -> Result<(V::Value, Self::Variant), Error> where V: DeserializeSeed<'de>, { let str_de = BorrowedStrDeserializer::::new(self.tag); let variant = seed.deserialize(str_de)?; let visitor = VariantRefDeserializer { value: self.value }; 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) => { ::clone(value).unit_variant() } None => Ok(()), } } fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value { Some(value) => ::clone(value) .newtype_variant_seed(seed), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"newtype variant", )), } } fn tuple_variant( self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Some(value) => ::clone(value) .tuple_variant(len, visitor), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"tuple variant", )), } } fn struct_variant( self, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Some(value) => ::clone(value) .struct_variant(fields, visitor), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"struct variant", )), } } } /// 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, visitor: V, ) -> Result where V: Visitor<'de>, { let len = self.iter.len(); if len == 0 { visitor.visit_unit() } else { let ret = visitor.visit_seq(&mut self)?; let remaining = self.iter.len(); if remaining == 0 { Ok(ret) } else { Err(Error::invalid_length( len, &"fewer elements in sequence", )) } } } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> { type Error = Error; fn next_element_seed( &mut self, seed: T, ) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.next() { Some(value) => seed.deserialize(value).map(Some), None => Ok(None), } } fn size_hint(&self) -> Option { match self.iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } /// 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()), value: None, } } } impl<'de> MapAccess<'de> for MapRefDeserializer<'de> { type Error = Error; fn next_key_seed( &mut self, seed: T, ) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.as_mut().and_then(Iterator::next) { Some((key, value)) => { self.value = Some(value); seed.deserialize(key).map(Some) } None => Ok(None), } } fn next_value_seed(&mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value.take() { Some(value) => seed.deserialize(value), None => panic!("visit_value called before visit_key"), } } fn size_hint(&self) -> Option { match self.iter.as_ref()?.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } impl<'de> Deserializer<'de> for MapRefDeserializer<'de> { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_map(self) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct 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 E: de::Error, { de::Error::invalid_type(self.unexpected(), exp) } /// Returns an `Unexpected` instance for the current `Value`. #[cold] pub(crate) fn unexpected(&self) -> Unexpected<'_> { match self { Value::Null => Unexpected::Unit, Value::Bool(b) => Unexpected::Bool(*b), Value::Number(n) => number::unexpected(n), Value::String(s) => Unexpected::Str(s), Value::Sequence(_) => Unexpected::Seq, Value::Mapping(_) => Unexpected::Map, Value::Tagged(_) => Unexpected::Enum, } } } serde_yml-0.0.12/src/value/debug.rs000064400000000000000000000067461046102023000152430ustar 00000000000000// debug.rs // This module provides implementations of the `Debug` trait for various types in the `serde_yml` crate. // It allows for customized formatting when debugging `Value`, `Number`, and `Mapping` types. use crate::mapping::Mapping; use crate::value::{Number, Value}; use std::fmt::{self, Debug, Display}; /// Implements the `Debug` trait for `Value`. /// This allows for customized formatting when debugging `Value` instances. /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let value = Value::String("Hello, world!".to_string()); /// println!("{:?}", value); /// // Output: String("Hello, world!") /// ``` impl Debug for Value { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Value::Null => formatter.write_str("Null"), Value::Bool(boolean) => { write!(formatter, "Bool({})", boolean) } Value::Number(number) => { write!(formatter, "Number({})", number) } Value::String(string) => { write!(formatter, "String({:?})", string) } Value::Sequence(sequence) => { formatter.write_str("Sequence ")?; formatter.debug_list().entries(sequence).finish() } Value::Mapping(mapping) => Debug::fmt(mapping, formatter), Value::Tagged(tagged) => Debug::fmt(tagged, formatter), } } } /// A wrapper type for `Number` that implements the `Display` trait. /// This allows for customized formatting when displaying `Number` instances. struct DisplayNumber<'a>(&'a Number); /// Implements the `Display` trait for `DisplayNumber`. /// This allows for customized formatting when displaying `Number` instances. impl Debug for DisplayNumber<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(self.0, formatter) } } /// Implements the `Debug` trait for `Number`. /// This allows for customized formatting when debugging `Number` instances. /// /// # Examples /// /// ``` /// use serde_yml::value::Number; /// /// let number = Number::from(42); /// println!("{:?}", number); /// // Output: Number(42) /// ``` impl Debug for Number { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "Number({})", self) } } /// Implements the `Debug` trait for `Mapping`. /// This allows for customized formatting when debugging `Mapping` instances. /// /// # Examples /// /// ``` /// use serde_yml::{Mapping, Value}; /// /// let mut mapping = Mapping::new(); /// mapping.insert(Value::String("name".to_string()), Value::String("John".to_string())); /// mapping.insert(Value::String("age".to_string()), Value::Number(30.into())); /// println!("{:?}", mapping); /// // Output: Mapping {"name": String("John"), "age": Number(30)} /// ``` impl Debug for Mapping { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("Mapping ")?; let mut debug = formatter.debug_map(); for (k, v) in self { let tmp; debug.entry( match k { Value::Bool(boolean) => boolean, Value::Number(number) => { tmp = DisplayNumber(number); &tmp } Value::String(string) => string, _ => k, }, v, ); } debug.finish() } } serde_yml-0.0.12/src/value/from.rs000064400000000000000000000106711046102023000151100ustar 00000000000000use crate::{Mapping, Value}; use std::borrow::Cow; use std::iter::FromIterator; use super::Number; // Implement conversion from number types to `Value`. impl From for Value where T: Into, { fn from(n: T) -> Self { Value::Number(n.into()) } } impl From for Value { /// Convert boolean to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let b = false; /// let x: Value = b.into(); /// assert_eq!(x, Value::Bool(false)); /// ``` fn from(f: bool) -> Self { Value::Bool(f) } } impl From for Value { /// Convert `String` to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let s: String = "lorem".to_string(); /// let x: Value = s.into(); /// assert_eq!(x, Value::String("lorem".to_string())); /// ``` fn from(f: String) -> Self { Value::String(f) } } impl From<&str> for Value { /// Convert string slice to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let s: &str = "lorem"; /// let x: Value = s.into(); /// assert_eq!(x, Value::String("lorem".to_string())); /// ``` fn from(f: &str) -> Self { Value::String(f.to_string()) } } impl<'a> From> for Value { /// Convert copy-on-write string to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// use std::borrow::Cow; /// /// let s: Cow = Cow::Borrowed("lorem"); /// let x: Value = s.into(); /// assert_eq!(x, Value::String("lorem".to_string())); /// ``` /// /// ``` /// use serde_yml::Value; /// use std::borrow::Cow; /// /// let s: Cow = Cow::Owned("lorem".to_string()); /// let x: Value = s.into(); /// assert_eq!(x, Value::String("lorem".to_string())); /// ``` fn from(f: Cow<'a, str>) -> Self { Value::String(f.into_owned()) } } impl From for Value { /// Convert map (with string keys) to `Value` /// /// # Examples /// /// ``` /// use serde_yml::{Mapping, Value}; /// /// let mut m = Mapping::new(); /// m.insert("Lorem".into(), "ipsum".into()); /// let x: Value = m.into(); /// assert_eq!(x, Value::Mapping(Mapping::from_iter(vec![("Lorem".into(), "ipsum".into())]))); /// ``` fn from(f: Mapping) -> Self { Value::Mapping(f) } } impl> From> for Value { /// Convert a `Vec` to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let v = vec!["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// assert_eq!(x, Value::Sequence(vec!["lorem".into(), "ipsum".into(), "dolor".into()])); /// ``` fn from(f: Vec) -> Self { Value::Sequence(f.into_iter().map(Into::into).collect()) } } impl<'a, T: Clone + Into> From<&'a [T]> for Value { /// Convert a slice to `Value` /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// assert_eq!(x, Value::Sequence(vec!["lorem".into(), "ipsum".into(), "dolor".into()])); /// ``` fn from(f: &'a [T]) -> Self { Value::Sequence(f.iter().cloned().map(Into::into).collect()) } } impl> FromIterator for Value { /// Convert an iteratable type to a YAML sequence /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let v = std::iter::repeat(42).take(5); /// let x: Value = v.collect(); /// assert_eq!(x, Value::Sequence(vec![42.into(), 42.into(), 42.into(), 42.into(), 42.into()])); /// ``` /// /// ``` /// use serde_yml::Value; /// /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; /// let x: Value = v.into_iter().collect(); /// assert_eq!(x, Value::Sequence(vec!["lorem".into(), "ipsum".into(), "dolor".into()])); /// ``` /// /// ``` /// use std::iter::FromIterator; /// use serde_yml::Value; /// /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); /// assert_eq!(x, Value::Sequence(vec!["lorem".into(), "ipsum".into(), "dolor".into()])); /// ``` fn from_iter>(iter: I) -> Self { let vec = iter.into_iter().map(T::into).collect(); Value::Sequence(vec) } } serde_yml-0.0.12/src/value/index.rs000064400000000000000000000240601046102023000152510ustar 00000000000000use crate::mapping::Entry; use crate::{mapping, private, Mapping, Value}; use std::fmt::{self, Debug}; use std::ops; /// A type that can be used to index into a `serde_yml::Value`. See the `get` /// and `get_mut` methods of `Value`. /// /// This trait is sealed and cannot be implemented for types outside of /// `serde_yml`. pub trait Index: private::Sealed { /// Return None if the key is not already in the sequence or object. #[doc(hidden)] fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; /// Return None if the key is not already in the sequence or object. #[doc(hidden)] fn index_into_mut<'v>( &self, v: &'v mut Value, ) -> Option<&'v mut Value>; /// Panic if sequence index out of bounds. If key is not already in the object, /// insert it with a value of null. Panic if Value is a type that cannot be /// indexed into, except if Value is null then it can be treated as an empty /// object. #[doc(hidden)] fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; } impl Index for usize { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { match v.untag_ref() { Value::Sequence(vec) => vec.get(*self), Value::Mapping(vec) => { vec.get(Value::Number((*self).into())) } _ => None, } } fn index_into_mut<'v>( &self, v: &'v mut Value, ) -> Option<&'v mut Value> { match v.untag_mut() { Value::Sequence(vec) => vec.get_mut(*self), Value::Mapping(vec) => { vec.get_mut(Value::Number((*self).into())) } _ => None, } } fn index_or_insert<'v>( &self, mut v: &'v mut Value, ) -> &'v mut Value { loop { match v { Value::Sequence(vec) => { let len = vec.len(); return vec.get_mut(*self).unwrap_or_else(|| { panic!( "cannot access index {} of YAML sequence of length {}", self, len ) }); } Value::Mapping(map) => { let n = Value::Number((*self).into()); return map.entry(n).or_insert(Value::Null); } Value::Tagged(tagged) => v = &mut tagged.value, _ => panic!( "cannot access index {} of YAML {}", self, Type(v) ), } } } } fn index_into_mapping<'v, I>( index: &I, v: &'v Value, ) -> Option<&'v Value> where I: ?Sized + mapping::Index, { match v.untag_ref() { Value::Mapping(map) => map.get(index), _ => None, } } fn index_into_mut_mapping<'v, I>( index: &I, v: &'v mut Value, ) -> Option<&'v mut Value> where I: ?Sized + mapping::Index, { match v.untag_mut() { Value::Mapping(map) => map.get_mut(index), _ => None, } } fn index_or_insert_mapping<'v, I>( index: &I, mut v: &'v mut Value, ) -> &'v mut Value where I: ?Sized + mapping::Index + ToOwned + Debug, Value: From, { if let Value::Null = *v { *v = Value::Mapping(Mapping::new()); return match v { Value::Mapping(map) => { match map.entry(index.to_owned().into()) { Entry::Vacant(entry) => entry.insert(Value::Null), Entry::Occupied(_) => unreachable!(), } } _ => unreachable!(), }; } loop { match v { Value::Mapping(map) => { return map .entry(index.to_owned().into()) .or_insert(Value::Null); } Value::Tagged(tagged) => v = &mut tagged.value, _ => panic!( "cannot access key {:?} in YAML {}", index, Type(v) ), } } } 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) } } 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) } } 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) } } impl Index for &T where T: ?Sized + Index, { 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) } } /// Used in panic messages. struct Type<'a>(&'a Value); impl fmt::Display for Type<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { Value::Null => formatter.write_str("null"), Value::Bool(_) => formatter.write_str("boolean"), Value::Number(_) => formatter.write_str("number"), Value::String(_) => formatter.write_str("string"), Value::Sequence(_) => formatter.write_str("sequence"), Value::Mapping(_) => formatter.write_str("mapping"), Value::Tagged(_) => unreachable!(), } } } // The usual semantics of Index is to panic on invalid indexing. // // That said, the usual semantics are for things like `Vec` and `BTreeMap` which // have different use cases than Value. If you are working with a Vec, you know // that you are working with a Vec and you can get the len of the Vec and make // sure your indices are within bounds. The Value use cases are more // loosey-goosey. You got some YAML from an endpoint and you want to pull values // out of it. Outside of this Index impl, you already have the option of using // `value.as_sequence()` and working with the Vec directly, or matching on // `Value::Sequence` and getting the Vec directly. The Index impl means you can // skip that and index directly into the thing using a concise syntax. You don't // have to check the type, you don't have to check the len, it is all about what // you expect the Value to look like. // // Basically the use cases that would be well served by panicking here are // better served by using one of the other approaches: `get` and `get_mut`, // `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; 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, { fn index_mut(&mut self, index: I) -> &mut Value { index.index_or_insert(self) } } serde_yml-0.0.12/src/value/mod.rs000064400000000000000000000541231046102023000147240ustar 00000000000000//! The Value enum, a loosely typed way of representing any valid YAML value. mod de; mod debug; mod from; mod index; mod partial_eq; mod ser; /// A representation of YAML's `!Tag` syntax, used for enums. pub mod tagged; use crate::modules::error::{self, Error, ErrorImpl}; use serde::{ de::{Deserialize, DeserializeOwned, IntoDeserializer}, Serialize, }; use std::{ hash::{Hash, Hasher}, mem, }; pub use self::index::Index; pub use self::ser::Serializer; pub use self::tagged::{Tag, TaggedValue}; #[doc(inline)] pub use crate::mapping::Mapping; pub use crate::number::Number; /// Represents any valid YAML value. #[derive(Clone, PartialEq, PartialOrd)] pub enum Value { /// Represents a YAML null value. Null, /// Represents a YAML boolean. Bool(bool), /// Represents a YAML numerical value, whether integer or floating point. Number(Number), /// Represents a YAML string. String(String), /// Represents a YAML sequence in which the elements are /// `serde_yml::Value`. Sequence(Sequence), /// Represents a YAML mapping in which the keys and values are both /// `serde_yml::Value`. Mapping(Mapping), /// A representation of YAML's `!Tag` syntax, used for enums. Tagged(Box), } /// The default value is `Value::Null`. /// /// This is useful for handling omitted `Value` fields when deserializing. /// /// # Examples /// /// ``` /// # use serde_derive::Deserialize; /// use serde_yml::Value; /// /// #[derive(Deserialize)] /// struct Settings { /// level: i32, /// #[serde(default)] /// extras: Value, /// } /// /// # fn try_main() -> Result<(), serde_yml::Error> { /// let data = r#" { "level": 42 } "#; /// let s: Settings = serde_yml::from_str(data)?; /// /// assert_eq!(s.level, 42); /// assert_eq!(s.extras, Value::Null); /// # /// # Ok(()) /// # } /// # /// # try_main().unwrap() /// ``` impl Default for Value { fn default() -> Value { Value::Null } } /// A YAML sequence in which the elements are `serde_yml::Value`. pub type Sequence = Vec; /// Converts a serializable value into a `serde_yml::Value`. /// /// This function is a convenience wrapper around the `serde_yml::value::Serializer`. /// It allows serializing a value of type `T` into a `serde_yml::Value` using the /// default serializer configuration. /// /// # Examples /// /// ``` /// use serde::Serialize; /// use serde_yml::to_value; /// /// #[derive(Serialize)] /// struct User { /// name: String, /// age: u32, /// } /// /// let user = User { /// name: "John Doe".to_string(), /// age: 30, /// }; /// /// let yaml_value = to_value(user).unwrap(); /// ``` pub fn to_value(value: T) -> Result where T: Serialize, { value.serialize(Serializer) } /// Interpret a `serde_yml::Value` as an instance of type `T`. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// ``` /// # use serde_yml::Value; /// let val = Value::String("foo".to_owned()); /// let s: String = serde_yml::from_value(val).unwrap(); /// assert_eq!("foo", s); /// ``` pub fn from_value(value: Value) -> Result where T: DeserializeOwned, { Deserialize::deserialize(value) } impl Value { /// Index into a YAML sequence or map. A string index can be used to access /// a value in a map, and a usize index can be used to access an element of /// an sequence. /// /// Returns `None` 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 `None` if the given key does not exist in the map /// or the given index is not within the bounds of the sequence. /// /// ``` /// # fn main() -> serde_yml::Result<()> { /// use serde_yml::Value; /// /// let object: Value = serde_yml::from_str(r#"{ A: 65, B: 66, C: 67 }"#)?; /// let x = object.get("A").unwrap(); /// assert_eq!(x, 65); /// /// let sequence: Value = serde_yml::from_str(r#"[ "A", "B", "C" ]"#)?; /// let x = sequence.get(2).unwrap(); /// assert_eq!(x, &Value::String("C".into())); /// /// assert_eq!(sequence.get("A"), None); /// # Ok(()) /// # } /// ``` /// /// Square brackets can also be used to index into a value in a more concise /// way. This returns `Value::Null` in cases where `get` would have returned /// `None`. /// /// ``` /// # use serde_yml::Value; /// # /// # fn main() -> serde_yml::Result<()> { /// let object: Value = serde_yml::from_str(r#" /// A: [a, á, à] /// B: [b, b́] /// C: [c, ć, ć̣, ḉ] /// 42: true /// "#)?; /// assert_eq!(object["B"][0], Value::String("b".into())); /// /// assert_eq!(object[Value::String("D".into())], Value::Null); /// assert_eq!(object["D"], Value::Null); /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null); /// /// assert_eq!(object[42], Value::Bool(true)); /// # Ok(()) /// # } /// ``` pub fn get(&self, index: I) -> Option<&Value> { index.index_into(self) } /// Index into a YAML sequence or map. A string index can be used to access /// a value in a map, and a usize index can be used to access an element of /// an sequence. /// /// Returns `None` 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 `None` if the given key does not exist in the map /// or the given index is not within the bounds of the sequence. pub fn get_mut( &mut self, index: I, ) -> Option<&mut Value> { index.index_into_mut(self) } /// Returns true if the `Value` is a Null. Returns false otherwise. /// /// For any Value on which `is_null` returns true, `as_null` is guaranteed /// to return `Some(())`. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("null").unwrap(); /// assert!(v.is_null()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert!(!v.is_null()); /// ``` pub fn is_null(&self) -> bool { #[allow(clippy::match_like_matches_macro)] if let Value::Null = self.untag_ref() { true } else { false } } /// If the `Value` is a Null, returns (). Returns None otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("null").unwrap(); /// assert_eq!(v.as_null(), Some(())); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_null(), None); /// ``` pub fn as_null(&self) -> Option<()> { match self.untag_ref() { Value::Null => Some(()), _ => None, } } /// Returns true if the `Value` is a Boolean. Returns false otherwise. /// /// For any Value on which `is_boolean` returns true, `as_bool` is /// guaranteed to return the boolean value. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert!(v.is_bool()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("42").unwrap(); /// assert!(!v.is_bool()); /// ``` pub fn is_bool(&self) -> bool { self.as_bool().is_some() } /// If the `Value` is a Boolean, returns the associated bool. Returns None /// otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert_eq!(v.as_bool(), Some(true)); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("42").unwrap(); /// assert_eq!(v.as_bool(), None); /// ``` pub fn as_bool(&self) -> Option { match self.untag_ref() { Value::Bool(b) => Some(*b), _ => None, } } /// Returns true if the `Value` is a Number. Returns false otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("5").unwrap(); /// assert!(v.is_number()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert!(!v.is_number()); /// ``` pub fn is_number(&self) -> bool { #[allow(clippy::match_like_matches_macro)] match self.untag_ref() { Value::Number(_) => true, _ => false, } } /// Returns true if the `Value` is an integer between `i64::MIN` and /// `i64::MAX`. /// /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to /// return the integer value. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("1337").unwrap(); /// assert!(v.is_i64()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("null").unwrap(); /// assert!(!v.is_i64()); /// ``` pub fn is_i64(&self) -> bool { self.as_i64().is_some() } /// If the `Value` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("1337").unwrap(); /// assert_eq!(v.as_i64(), Some(1337)); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_i64(), None); /// ``` pub fn as_i64(&self) -> Option { match self.untag_ref() { Value::Number(n) => n.as_i64(), _ => None, } } /// Returns true if the `Value` is an integer between `u64::MIN` and /// `u64::MAX`. /// /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to /// return the integer value. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("1337").unwrap(); /// assert!(v.is_u64()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("null").unwrap(); /// assert!(!v.is_u64()); /// ``` pub fn is_u64(&self) -> bool { self.as_u64().is_some() } /// If the `Value` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("1337").unwrap(); /// assert_eq!(v.as_u64(), Some(1337)); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_u64(), None); /// ``` pub fn as_u64(&self) -> Option { match self.untag_ref() { Value::Number(n) => n.as_u64(), _ => None, } } /// Returns true if the `Value` is a number that can be represented by f64. /// /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to /// return the floating point value. /// /// Currently this function returns true if and only if both `is_i64` and /// `is_u64` return false but this is not a guarantee in the future. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("256.01").unwrap(); /// assert!(v.is_f64()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert!(!v.is_f64()); /// ``` pub fn is_f64(&self) -> bool { match self.untag_ref() { Value::Number(n) => n.is_f64(), _ => false, } } /// If the `Value` is a number, represent it as f64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("13.37").unwrap(); /// assert_eq!(v.as_f64(), Some(13.37)); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_f64(), None); /// ``` pub fn as_f64(&self) -> Option { match self.untag_ref() { Value::Number(i) => i.as_f64(), _ => None, } } /// Returns true if the `Value` is a String. Returns false otherwise. /// /// For any Value on which `is_string` returns true, `as_str` is guaranteed /// to return the string slice. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("'lorem ipsum'").unwrap(); /// assert!(v.is_string()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("42").unwrap(); /// assert!(!v.is_string()); /// ``` pub fn is_string(&self) -> bool { self.as_str().is_some() } /// If the `Value` is a String, returns the associated str. Returns None /// otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("'lorem ipsum'").unwrap(); /// assert_eq!(v.as_str(), Some("lorem ipsum")); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_str(), None); /// ``` pub fn as_str(&self) -> Option<&str> { match self.untag_ref() { Value::String(s) => Some(s), _ => None, } } /// Returns true if the `Value` is a sequence. Returns false otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("[1, 2, 3]").unwrap(); /// assert!(v.is_sequence()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert!(!v.is_sequence()); /// ``` pub fn is_sequence(&self) -> bool { self.as_sequence().is_some() } /// If the `Value` is a sequence, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yml::{Value, Number}; /// let v: Value = serde_yml::from_str("[1, 2]").unwrap(); /// assert_eq!(v.as_sequence(), Some(&vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))])); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_sequence(), None); /// ``` pub fn as_sequence(&self) -> Option<&Sequence> { match self.untag_ref() { Value::Sequence(seq) => Some(seq), _ => None, } } /// If the `Value` is a sequence, return a mutable reference to it if /// possible. Returns None otherwise. /// /// ``` /// # use serde_yml::{Value, Number}; /// let mut v: Value = serde_yml::from_str("[1]").unwrap(); /// let s = v.as_sequence_mut().unwrap(); /// s.push(Value::Number(Number::from(2))); /// assert_eq!(s, &vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]); /// ``` /// /// ``` /// # use serde_yml::Value; /// let mut v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_sequence_mut(), None); /// ``` pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> { match self.untag_mut() { Value::Sequence(seq) => Some(seq), _ => None, } } /// Returns true if the `Value` is a mapping. Returns false otherwise. /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("a: 42").unwrap(); /// assert!(v.is_mapping()); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("true").unwrap(); /// assert!(!v.is_mapping()); /// ``` pub fn is_mapping(&self) -> bool { self.as_mapping().is_some() } /// If the `Value` is a mapping, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yml::{Value, Mapping, Number}; /// let v: Value = serde_yml::from_str("a: 42").unwrap(); /// /// let mut expected = Mapping::new(); /// expected.insert(Value::String("a".into()),Value::Number(Number::from(42))); /// /// assert_eq!(v.as_mapping(), Some(&expected)); /// ``` /// /// ``` /// # use serde_yml::Value; /// let v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_mapping(), None); /// ``` pub fn as_mapping(&self) -> Option<&Mapping> { match self.untag_ref() { Value::Mapping(map) => Some(map), _ => None, } } /// If the `Value` is a mapping, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yml::{Value, Mapping, Number}; /// let mut v: Value = serde_yml::from_str("a: 42").unwrap(); /// let m = v.as_mapping_mut().unwrap(); /// m.insert(Value::String("b".into()), Value::Number(Number::from(21))); /// /// let mut expected = Mapping::new(); /// expected.insert(Value::String("a".into()), Value::Number(Number::from(42))); /// expected.insert(Value::String("b".into()), Value::Number(Number::from(21))); /// /// assert_eq!(m, &expected); /// ``` /// /// ``` /// # use serde_yml::{Value, Mapping}; /// let mut v: Value = serde_yml::from_str("false").unwrap(); /// assert_eq!(v.as_mapping_mut(), None); /// ``` pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> { match self.untag_mut() { Value::Mapping(map) => Some(map), _ => None, } } /// Performs merging of `<<` keys into the surrounding mapping. /// /// The intended use of this in YAML is described in /// . /// /// ``` /// use serde_yml::Value; /// /// let config = "\ /// tasks: /// build: &webpack_shared /// command: webpack /// args: build /// inputs: /// - 'src/**/*' /// start: /// <<: *webpack_shared /// args: start /// "; /// /// let mut value: Value = serde_yml::from_str(config).unwrap(); /// value.apply_merge().unwrap(); /// /// assert_eq!(value["tasks"]["start"]["command"], "webpack"); /// assert_eq!(value["tasks"]["start"]["args"], "start"); /// ``` pub fn apply_merge(&mut self) -> Result<(), Error> { let mut stack = Vec::new(); stack.push(self); while let Some(node) = stack.pop() { match node { Value::Mapping(mapping) => { match mapping.remove("<<") { Some(Value::Mapping(merge)) => { for (k, v) in merge { mapping.entry(k).or_insert(v); } } Some(Value::Sequence(sequence)) => { for value in sequence { match value { Value::Mapping(merge) => { for (k, v) in merge { mapping .entry(k) .or_insert(v); } } Value::Sequence(_) => { return Err(error::new(ErrorImpl::SequenceInMergeElement)); } Value::Tagged(_) => { return Err(error::new( ErrorImpl::TaggedInMerge, )); } _unexpected => { return Err(error::new(ErrorImpl::ScalarInMergeElement)); } } } } None => {} Some(Value::Tagged(_)) => { return Err(error::new( ErrorImpl::TaggedInMerge, )) } Some(_unexpected) => { return Err(error::new( ErrorImpl::ScalarInMerge, )) } } stack.extend(mapping.values_mut()); } Value::Sequence(sequence) => stack.extend(sequence), Value::Tagged(tagged) => stack.push(&mut tagged.value), _ => {} } } Ok(()) } } impl Eq for Value {} // NOTE: This impl must be kept consistent with HashLikeValue's Hash impl in // mapping.rs in order for value[str] indexing to work. impl Hash for Value { fn hash(&self, state: &mut H) { mem::discriminant(self).hash(state); match self { Value::Null => {} Value::Bool(v) => v.hash(state), Value::Number(v) => v.hash(state), Value::String(v) => v.hash(state), Value::Sequence(v) => v.hash(state), Value::Mapping(v) => v.hash(state), Value::Tagged(v) => v.hash(state), } } } impl IntoDeserializer<'_, Error> for Value { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } serde_yml-0.0.12/src/value/partial_eq.rs000064400000000000000000000053271046102023000162700ustar 00000000000000use crate::Value; impl PartialEq for Value { /// Compare `str` with YAML value /// /// # Examples /// /// ``` /// # use serde_yml::Value; /// assert!(Value::String("lorem".into()) == *"lorem"); /// ``` fn eq(&self, other: &str) -> bool { self.as_str().map_or(false, |s| s == other) } } impl PartialEq<&str> for Value { /// Compare `&str` with YAML value /// /// # Examples /// /// ``` /// # use serde_yml::Value; /// assert!(Value::String("lorem".into()) == "lorem"); /// ``` fn eq(&self, other: &&str) -> bool { self.as_str().map_or(false, |s| s == *other) } } impl PartialEq for Value { /// Compare YAML value with String /// /// # Examples /// /// ``` /// # use serde_yml::Value; /// assert!(Value::String("lorem".into()) == "lorem".to_string()); /// ``` fn eq(&self, other: &String) -> bool { self.as_str().map_or(false, |s| s == other) } } impl PartialEq for Value { /// Compare YAML value with bool /// /// # Examples /// /// ``` /// # use serde_yml::Value; /// assert!(Value::Bool(true) == true); /// ``` fn eq(&self, other: &bool) -> bool { self.as_bool().map_or(false, |b| b == *other) } } fn compare_numeric(i: T, other: U) -> bool where T: PartialEq, U: Into, { i == other } /// A macro that generates implementations of the `PartialEq` trait for /// primitive numeric types and `Value` based on the specified conversion /// method and base type. /// /// # Examples /// /// ``` /// use serde_yml::Value; /// /// let v1: Value = 10.into(); /// assert_eq!(v1, 10); /// /// let v2: Value = serde_yml::from_str("10").unwrap(); /// assert_eq!(v2, 10); /// ``` macro_rules! partialeq_numeric { ($([$($ty:ty)*], $conversion:ident, $base:ty)*) => { $($( impl PartialEq<$ty> for Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| compare_numeric(i, (*other).try_into().unwrap())) } } impl PartialEq<$ty> for &Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| compare_numeric(i, (*other).try_into().unwrap())) } } impl PartialEq<$ty> for &mut Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| compare_numeric(i, (*other).try_into().unwrap())) } } )*)* } } partialeq_numeric! { [i8 i16 i32 i64 isize], as_i64, i64 [u8 u16 u32 u64 usize], as_u64, u64 [f32 f64], as_f64, f64 } serde_yml-0.0.12/src/value/ser.rs000064400000000000000000000646351046102023000147470ustar 00000000000000use crate::modules::error::{self, Error, ErrorImpl}; use crate::value::tagged::{self, MaybeTag}; use crate::value::{ to_value, Mapping, Number, Sequence, Tag, TaggedValue, Value, }; use serde::ser::{self, Serialize}; use std::fmt::Display; use std::mem; type Result = std::result::Result; impl Serialize for Value { // Serializes a `Value` into the given serializer. fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { match self { Value::Null => serializer.serialize_unit(), Value::Bool(b) => serializer.serialize_bool(*b), Value::Number(n) => n.serialize(serializer), Value::String(s) => serializer.serialize_str(s), Value::Sequence(seq) => seq.serialize(serializer), Value::Mapping(mapping) => { use serde::ser::SerializeMap; let mut map = serializer.serialize_map(Some(mapping.len()))?; for (k, v) in mapping { map.serialize_entry(k, v)?; } map.end() } Value::Tagged(tagged) => tagged.serialize(serializer), } } } /// Serializer whose output is a `Value`. /// /// This is the serializer that backs [`serde_yml::to_value`][crate::to_value]. /// Unlike the main serde_yml serializer which goes from some serializable /// value of type `T` to YAML text, this one goes from `T` to /// `serde_yml::Value`. /// /// The `to_value` function is implementable as: /// /// ``` /// use serde::Serialize; /// use serde_yml::{Error, Value}; /// /// pub fn to_value(input: T) -> Result /// where /// T: Serialize, /// { /// input.serialize(serde_yml::value::Serializer) /// } /// ``` #[derive(Clone, Copy, Debug)] pub struct Serializer; impl ser::Serializer for Serializer { type Ok = Value; type Error = Error; type SerializeSeq = SerializeArray; type SerializeTuple = SerializeArray; type SerializeTupleStruct = SerializeArray; type SerializeTupleVariant = SerializeTupleVariant; type SerializeMap = SerializeMap; type SerializeStruct = SerializeStruct; type SerializeStructVariant = SerializeStructVariant; fn serialize_bool(self, v: bool) -> Result { Ok(Value::Bool(v)) } fn serialize_i8(self, v: i8) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_i16(self, v: i16) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_i32(self, v: i32) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_i64(self, v: i64) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_i128(self, v: i128) -> Result { if let Ok(v) = u64::try_from(v) { self.serialize_u64(v) } else if let Ok(v) = i64::try_from(v) { self.serialize_i64(v) } else { Ok(Value::String(v.to_string())) } } fn serialize_u8(self, v: u8) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_u16(self, v: u16) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_u32(self, v: u32) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_u64(self, v: u64) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_u128(self, v: u128) -> Result { if let Ok(v) = u64::try_from(v) { self.serialize_u64(v) } else { Ok(Value::String(v.to_string())) } } fn serialize_f32(self, v: f32) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_f64(self, v: f64) -> Result { Ok(Value::Number(Number::from(v))) } fn serialize_char(self, value: char) -> Result { Ok(Value::String(value.to_string())) } fn serialize_str(self, value: &str) -> Result { Ok(Value::String(value.to_owned())) } fn serialize_bytes(self, value: &[u8]) -> Result { let vec = value .iter() .map(|&b| Value::Number(Number::from(b))) .collect(); Ok(Value::Sequence(vec)) } fn serialize_unit(self) -> Result { Ok(Value::Null) } fn serialize_unit_struct( self, _name: &'static str, ) -> Result { self.serialize_unit() } fn serialize_unit_variant( self, _name: &str, _variant_index: u32, variant: &str, ) -> Result { Ok(Value::String(variant.to_owned())) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &str, _variant_index: u32, variant: &str, value: &T, ) -> Result where T: ?Sized + Serialize, { if variant.is_empty() { return Err(error::new(ErrorImpl::EmptyTag)); } Ok(Value::Tagged(Box::new(TaggedValue { tag: Tag::new(variant), value: to_value(value)?, }))) } fn serialize_none(self) -> Result { self.serialize_unit() } fn serialize_some(self, value: &V) -> Result where V: ?Sized + Serialize, { value.serialize(self) } fn serialize_seq( self, len: Option, ) -> Result { let sequence = match len { None => Sequence::new(), Some(len) => Sequence::with_capacity(len), }; Ok(SerializeArray { sequence }) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_variant( self, _enum: &'static str, _idx: u32, variant: &'static str, len: usize, ) -> Result { if variant.is_empty() { return Err(error::new(ErrorImpl::EmptyTag)); } Ok(SerializeTupleVariant { tag: variant, sequence: Sequence::with_capacity(len), }) } fn serialize_map(self, len: Option) -> Result { if len == Some(1) { Ok(SerializeMap::CheckForTag) } else { Ok(SerializeMap::Untagged { mapping: Mapping::new(), next_key: None, }) } } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Ok(SerializeStruct { mapping: Mapping::new(), }) } fn serialize_struct_variant( self, _enum: &'static str, _idx: u32, variant: &'static str, _len: usize, ) -> Result { if variant.is_empty() { return Err(error::new(ErrorImpl::EmptyTag)); } Ok(SerializeStructVariant { tag: variant, mapping: Mapping::new(), }) } fn is_human_readable(&self) -> bool { false } } /// A helper struct to serialize arrays. #[derive(Debug)] pub struct SerializeArray { sequence: Sequence, } impl ser::SerializeSeq for SerializeArray { type Ok = Value; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + Serialize, { self.sequence.push(to_value(elem)?); Ok(()) } fn end(self) -> Result { Ok(Value::Sequence(self.sequence)) } } impl ser::SerializeTuple for SerializeArray { type Ok = Value; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + Serialize, { ser::SerializeSeq::serialize_element(self, elem) } fn end(self) -> Result { ser::SerializeSeq::end(self) } } impl ser::SerializeTupleStruct for SerializeArray { type Ok = Value; type Error = Error; fn serialize_field(&mut self, value: &V) -> Result<()> where V: ?Sized + Serialize, { ser::SerializeSeq::serialize_element(self, value) } fn end(self) -> Result { ser::SerializeSeq::end(self) } } /// A helper struct to serialize tuple variants. #[derive(Debug)] pub struct SerializeTupleVariant { tag: &'static str, sequence: Sequence, } impl ser::SerializeTupleVariant for SerializeTupleVariant { type Ok = Value; type Error = Error; fn serialize_field(&mut self, v: &V) -> Result<()> where V: ?Sized + Serialize, { self.sequence.push(to_value(v)?); Ok(()) } fn end(self) -> Result { Ok(Value::Tagged(Box::new(TaggedValue { tag: Tag::new(self.tag), value: Value::Sequence(self.sequence), }))) } } /// An enum to handle the serialization of maps. #[derive(Debug)] pub enum SerializeMap { /// Represents a map with a single key-value pair, used to check for a tag. CheckForTag, /// Represents a tagged map, storing the tag and the associated value. Tagged(TaggedValue), /// Represents an untagged map, storing the mapping and the next key. Untagged { mapping: Mapping, next_key: Option, }, } impl ser::SerializeMap for SerializeMap { type Ok = Value; type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { let key = Some(to_value(key)?); match self { SerializeMap::CheckForTag => { *self = SerializeMap::Untagged { mapping: Mapping::new(), next_key: key, }; } SerializeMap::Tagged(tagged) => { let mut mapping = Mapping::new(); mapping.insert( Value::String(tagged.tag.to_string()), mem::take(&mut tagged.value), ); *self = SerializeMap::Untagged { mapping, next_key: key, }; } SerializeMap::Untagged { next_key, .. } => *next_key = key, } Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { let (mapping, key) = match self { SerializeMap::CheckForTag | SerializeMap::Tagged(_) => { unreachable!() } SerializeMap::Untagged { mapping, next_key } => { (mapping, next_key) } }; match key.take() { Some(key) => mapping.insert(key, to_value(value)?), None => { panic!("serialize_value called before serialize_key") } }; Ok(()) } fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<()> where K: ?Sized + Serialize, V: ?Sized + Serialize, { /// A helper struct to check for the presence of a tag in the serialized value. struct CheckForTag; /// A helper struct to wrap the serialized value when it is not a tag. struct NotTag { delegate: T, } impl ser::Serializer for CheckForTag { type Ok = MaybeTag; type Error = Error; type SerializeSeq = NotTag; type SerializeTuple = NotTag; type SerializeTupleStruct = NotTag; type SerializeTupleVariant = NotTag; type SerializeMap = NotTag; type SerializeStruct = NotTag; type SerializeStructVariant = NotTag; fn serialize_bool(self, v: bool) -> Result { Serializer.serialize_bool(v).map(MaybeTag::NotTag) } fn serialize_i8(self, v: i8) -> Result { Serializer.serialize_i8(v).map(MaybeTag::NotTag) } fn serialize_i16(self, v: i16) -> Result { Serializer.serialize_i16(v).map(MaybeTag::NotTag) } fn serialize_i32(self, v: i32) -> Result { Serializer.serialize_i32(v).map(MaybeTag::NotTag) } fn serialize_i64(self, v: i64) -> Result { Serializer.serialize_i64(v).map(MaybeTag::NotTag) } fn serialize_i128(self, v: i128) -> Result { Serializer.serialize_i128(v).map(MaybeTag::NotTag) } fn serialize_u8(self, v: u8) -> Result { Serializer.serialize_u8(v).map(MaybeTag::NotTag) } fn serialize_u16(self, v: u16) -> Result { Serializer.serialize_u16(v).map(MaybeTag::NotTag) } fn serialize_u32(self, v: u32) -> Result { Serializer.serialize_u32(v).map(MaybeTag::NotTag) } fn serialize_u64(self, v: u64) -> Result { Serializer.serialize_u64(v).map(MaybeTag::NotTag) } fn serialize_u128(self, v: u128) -> Result { Serializer.serialize_u128(v).map(MaybeTag::NotTag) } fn serialize_f32(self, v: f32) -> Result { Serializer.serialize_f32(v).map(MaybeTag::NotTag) } fn serialize_f64(self, v: f64) -> Result { Serializer.serialize_f64(v).map(MaybeTag::NotTag) } fn serialize_char(self, value: char) -> Result { Serializer.serialize_char(value).map(MaybeTag::NotTag) } fn serialize_str(self, value: &str) -> Result { Serializer.serialize_str(value).map(MaybeTag::NotTag) } fn serialize_bytes(self, value: &[u8]) -> Result { Serializer.serialize_bytes(value).map(MaybeTag::NotTag) } fn serialize_unit(self) -> Result { Serializer.serialize_unit().map(MaybeTag::NotTag) } fn serialize_unit_struct( self, name: &'static str, ) -> Result { Serializer .serialize_unit_struct(name) .map(MaybeTag::NotTag) } fn serialize_unit_variant( self, name: &'static str, variant_index: u32, variant: &'static str, ) -> Result { Serializer .serialize_unit_variant( name, variant_index, variant, ) .map(MaybeTag::NotTag) } fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { Serializer .serialize_newtype_struct(name, value) .map(MaybeTag::NotTag) } fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { Serializer .serialize_newtype_variant( name, variant_index, variant, value, ) .map(MaybeTag::NotTag) } fn serialize_none(self) -> Result { Serializer.serialize_none().map(MaybeTag::NotTag) } fn serialize_some(self, value: &V) -> Result where V: ?Sized + Serialize, { Serializer.serialize_some(value).map(MaybeTag::NotTag) } fn serialize_seq( self, len: Option, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_seq(len)?, }) } fn serialize_tuple( self, len: usize, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_tuple(len)?, }) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { Ok(NotTag { delegate: Serializer .serialize_tuple_struct(name, len)?, }) } fn serialize_tuple_variant( self, name: &'static str, variant_index: u32, variant: &'static str, len: usize, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_tuple_variant( name, variant_index, variant, len, )?, }) } fn serialize_map( self, len: Option, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_map(len)?, }) } fn serialize_struct( self, name: &'static str, len: usize, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_struct(name, len)?, }) } fn serialize_struct_variant( self, name: &'static str, variant_index: u32, variant: &'static str, len: usize, ) -> Result { Ok(NotTag { delegate: Serializer.serialize_struct_variant( name, variant_index, variant, len, )?, }) } fn collect_str(self, value: &T) -> Result where T: ?Sized + Display, { Ok(match tagged::check_for_tag(value) { MaybeTag::Tag(tag) => MaybeTag::Tag(tag), MaybeTag::NotTag(string) => { MaybeTag::NotTag(Value::String(string)) } }) } } impl ser::SerializeSeq for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + Serialize, { self.delegate.serialize_element(elem) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeTuple for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + Serialize, { self.delegate.serialize_element(elem) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeTupleStruct for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_field(&mut self, value: &V) -> Result<()> where V: ?Sized + Serialize, { self.delegate.serialize_field(value) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeTupleVariant for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_field(&mut self, v: &V) -> Result<()> where V: ?Sized + Serialize, { self.delegate.serialize_field(v) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeMap for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { self.delegate.serialize_key(key) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.delegate.serialize_value(value) } fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<()> where K: ?Sized + Serialize, V: ?Sized + Serialize, { self.delegate.serialize_entry(key, value) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeStruct for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &V, ) -> Result<()> where V: ?Sized + Serialize, { self.delegate.serialize_field(key, value) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } impl ser::SerializeStructVariant for NotTag { type Ok = MaybeTag; type Error = Error; fn serialize_field( &mut self, field: &'static str, v: &V, ) -> Result<()> where V: ?Sized + Serialize, { self.delegate.serialize_field(field, v) } fn end(self) -> Result { self.delegate.end().map(MaybeTag::NotTag) } } match self { SerializeMap::CheckForTag => { let key = key.serialize(CheckForTag)?; let mut mapping = Mapping::new(); *self = match key { MaybeTag::Tag(string) => { SerializeMap::Tagged(TaggedValue { tag: Tag::new(string), value: to_value(value)?, }) } MaybeTag::NotTag(key) => { mapping.insert(key, to_value(value)?); SerializeMap::Untagged { mapping, next_key: None, } } }; } SerializeMap::Tagged(tagged) => { let mut mapping = Mapping::new(); mapping.insert( Value::String(tagged.tag.to_string()), mem::take(&mut tagged.value), ); mapping.insert(to_value(key)?, to_value(value)?); *self = SerializeMap::Untagged { mapping, next_key: None, }; } SerializeMap::Untagged { mapping, .. } => { mapping.insert(to_value(key)?, to_value(value)?); } } Ok(()) } fn end(self) -> Result { Ok(match self { SerializeMap::CheckForTag => Value::Mapping(Mapping::new()), SerializeMap::Tagged(tagged) => { Value::Tagged(Box::new(tagged)) } SerializeMap::Untagged { mapping, .. } => { Value::Mapping(mapping) } }) } } /// A helper struct to serialize structs. #[derive(Debug)] pub struct SerializeStruct { mapping: Mapping, } impl ser::SerializeStruct for SerializeStruct { type Ok = Value; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &V, ) -> Result<()> where V: ?Sized + Serialize, { self.mapping.insert(to_value(key)?, to_value(value)?); Ok(()) } fn end(self) -> Result { Ok(Value::Mapping(self.mapping)) } } /// A helper struct to serialize struct variants. #[derive(Debug)] pub struct SerializeStructVariant { tag: &'static str, mapping: Mapping, } impl ser::SerializeStructVariant for SerializeStructVariant { type Ok = Value; type Error = Error; fn serialize_field( &mut self, field: &'static str, v: &V, ) -> Result<()> where V: ?Sized + Serialize, { self.mapping.insert(to_value(field)?, to_value(v)?); Ok(()) } fn end(self) -> Result { Ok(Value::Tagged(Box::new(TaggedValue { tag: Tag::new(self.tag), value: Value::Mapping(self.mapping), }))) } } serde_yml-0.0.12/src/value/tagged.rs000064400000000000000000000255101046102023000153760ustar 00000000000000// Copyright notice and licensing information. // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. // Copyright © 2024 Serde YML, Seamless YAML Serialization for Rust. All rights reserved. use crate::{ modules::error::Error, value::{ de::{MapDeserializer, SeqDeserializer}, Value, }, }; use serde::{ de::{ value::StrDeserializer, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, VariantAccess, Visitor, }, forward_to_deserialize_any, ser::{Serialize, SerializeMap, Serializer}, }; use std::{ cmp::Ordering, convert::TryFrom, fmt::{self, Debug, Display}, hash::{Hash, Hasher}, str::from_utf8, }; /// A representation of YAML's `!Tag` syntax, used for enums. #[derive(Clone)] pub struct Tag { /// The string representation of the tag. pub string: String, } /// A `Tag` + `Value` representing a tagged YAML scalar, sequence, or mapping. #[derive(Clone, PartialEq, PartialOrd, Hash, Debug)] pub struct TaggedValue { /// The tag of the tagged value. pub tag: Tag, /// The value of the tagged value. pub value: Value, } impl TaggedValue { /// Creates a new `TaggedValue`. pub fn copy(&self) -> TaggedValue { TaggedValue { tag: self.tag.clone(), value: self.value.clone(), } } } impl Tag { /// Creates a new `Tag`. pub fn new(string: impl Into) -> Self { let tag: String = string.into(); assert!(!tag.is_empty(), "empty YAML tag is not allowed"); Tag { string: tag } } } impl TryFrom<&[u8]> for Tag { type Error = Error; fn try_from(bytes: &[u8]) -> Result { let tag_str = from_utf8(bytes) .map_err(|_| Error::custom("invalid UTF-8 sequence"))?; Ok(Tag::new(tag_str)) } } impl Value { pub(crate) fn untag(self) -> Self { let mut cur = self; while let Value::Tagged(tagged) = cur { cur = tagged.value; } cur } pub(crate) fn untag_ref(&self) -> &Self { let mut cur = self; while let Value::Tagged(tagged) = cur { cur = &tagged.value; } cur } pub(crate) fn untag_mut(&mut self) -> &mut Self { let mut cur = self; while let Value::Tagged(tagged) = cur { cur = &mut tagged.value; } cur } } /// Returns the portion of a YAML tag after the exclamation mark, if any. /// /// A YAML tag is denoted by a leading exclamation mark (`!`). If the input value is empty, it is considered not to be a tag. If the input value starts with an exclamation mark, it is considered to be a tag but not a bang tag (i.e., `!foo` is a tag, but `!bar` is not). If the input value does not start with an exclamation mark, it is considered not to be a tag. /// /// # Examples /// /// ``` /// use serde_yml::value::tagged::nobang; /// /// let result = nobang("foo"); /// assert_eq!("foo", result); /// /// let result = nobang("!bar"); /// assert_eq!("bar", result); /// /// let result = nobang(""); /// assert_eq!("", result); /// ``` pub fn nobang(maybe_banged: &str) -> &str { match maybe_banged.strip_prefix('!') { Some("") | None => maybe_banged, Some(unbanged) => unbanged, } } impl Eq for Tag {} impl PartialEq for Tag { fn eq(&self, other: &Tag) -> bool { PartialEq::eq(nobang(&self.string), nobang(&other.string)) } } impl PartialEq for Tag where T: ?Sized + AsRef, { fn eq(&self, other: &T) -> bool { PartialEq::eq(nobang(&self.string), nobang(other.as_ref())) } } impl Ord for Tag { fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(nobang(&self.string), nobang(&other.string)) } } impl PartialOrd for Tag { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Hash for Tag { fn hash(&self, hasher: &mut H) { nobang(&self.string).hash(hasher); } } impl Display for Tag { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "!{}", nobang(&self.string)) } } impl Debug for Tag { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(self, formatter) } } impl Serialize for TaggedValue { fn serialize(&self, serializer: S) -> Result where S: Serializer, { struct SerializeTag<'a>(&'a Tag); impl Serialize for SerializeTag<'_> { fn serialize( &self, serializer: S, ) -> Result where S: Serializer, { serializer.collect_str(self.0) } } let mut map = serializer.serialize_map(Some(1))?; map.serialize_entry(&SerializeTag(&self.tag), &self.value)?; map.end() } } impl<'de> Deserialize<'de> for TaggedValue { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct TaggedValueVisitor; impl<'de> Visitor<'de> for TaggedValueVisitor { type Value = TaggedValue; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_str("a YAML value with a !Tag") } fn visit_enum( self, data: A, ) -> Result where A: EnumAccess<'de>, { let (tag, contents) = data.variant_seed(TagStringVisitor)?; let value = contents.newtype_variant()?; Ok(TaggedValue { tag, value }) } } deserializer.deserialize_any(TaggedValueVisitor) } } impl<'de> Deserializer<'de> for TaggedValue { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_enum(self) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl<'de> EnumAccess<'de> for TaggedValue { type Error = Error; type Variant = Value; fn variant_seed( self, seed: V, ) -> Result<(V::Value, Self::Variant), Error> where V: DeserializeSeed<'de>, { let tag = StrDeserializer::::new(nobang(&self.tag.string)); let value = seed.deserialize(tag)?; Ok((value, self.value)) } } impl<'de> VariantAccess<'de> for Value { type Error = Error; fn unit_variant(self) -> Result<(), Error> { Deserialize::deserialize(self) } fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de>, { seed.deserialize(self) } fn tuple_variant( self, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { if let Value::Sequence(v) = self { Deserializer::deserialize_any( SeqDeserializer::new(v), visitor, ) } else { Err(Error::invalid_type( self.unexpected(), &"tuple variant", )) } } fn struct_variant( self, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { if let Value::Mapping(v) = self { Deserializer::deserialize_any( MapDeserializer::new(v), visitor, ) } else { Err(Error::invalid_type( self.unexpected(), &"struct variant", )) } } } pub(crate) struct TagStringVisitor; impl Visitor<'_> for TagStringVisitor { type Value = Tag; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { formatter.write_str("a YAML tag string") } fn visit_str(self, string: &str) -> Result where E: serde::de::Error, { self.visit_string(string.to_owned()) } fn visit_string(self, string: String) -> Result where E: serde::de::Error, { if string.is_empty() { return Err(E::custom("empty YAML tag is not allowed")); } Ok(Tag::new(string)) } } impl<'de> DeserializeSeed<'de> for TagStringVisitor { type Value = Tag; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { deserializer.deserialize_string(self) } } /// A tagged value with an optional tag. #[derive(Debug)] pub enum MaybeTag { /// The tag. Tag(String), /// The value. NotTag(T), } /// Returns a `MaybeTag` enum indicating whether the input value is a YAML tag or not. /// /// A YAML tag is denoted by a leading exclamation mark (`!`). If the input value is empty, it is considered not to be a tag. If the input value starts with an exclamation mark, it is considered to be a tag but not a bang tag (i.e., `!foo` is a tag, but `!bar` is not). If the input value does not start with an exclamation mark, it is considered not to be a tag. /// /// # Examples /// /// ``` /// use serde_yml::value::tagged::check_for_tag; /// use serde_yml::value::tagged::MaybeTag; /// /// let result = check_for_tag(&"foo".to_owned()); /// assert!( /// matches!(result, MaybeTag::NotTag(_)), /// "Expected MaybeTag::NotTag but got {:?}", result /// ); /// ``` /// pub fn check_for_tag(value: &T) -> MaybeTag where T: ?Sized + Display, { enum CheckForTag { Empty, Bang, Tag(String), NotTag(String), } let check_for_tag = match format!("{}", value).as_str() { "" => CheckForTag::Empty, "!" => CheckForTag::Bang, tag => { if tag.starts_with('!') { CheckForTag::Tag(tag.to_owned()) } else { CheckForTag::NotTag(tag.to_owned()) } } }; match check_for_tag { CheckForTag::Empty => MaybeTag::NotTag(String::new()), CheckForTag::Bang => MaybeTag::NotTag("!".to_owned()), CheckForTag::Tag(string) => MaybeTag::Tag(string), CheckForTag::NotTag(string) => MaybeTag::NotTag(string), } } serde_yml-0.0.12/src/with.rs000064400000000000000000002312341046102023000140040ustar 00000000000000//! Customizations to use with Serde's `#[serde(with = …)]` attribute. /// Serialize/deserialize an enum using a YAML map containing one entry in which /// the key identifies the variant name. /// /// # Example /// /// ``` /// use serde::{Deserialize, Serialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum Enum { /// Unit, /// Newtype(usize), /// Tuple(usize, usize), /// Struct { value: usize }, /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Struct { /// #[serde(with = "serde_yml::with::singleton_map")] /// w: Enum, /// #[serde(with = "serde_yml::with::singleton_map")] /// x: Enum, /// #[serde(with = "serde_yml::with::singleton_map")] /// y: Enum, /// #[serde(with = "serde_yml::with::singleton_map")] /// z: Enum, /// } /// /// let object = Struct { /// w: Enum::Unit, /// x: Enum::Newtype(1), /// y: Enum::Tuple(1, 1), /// z: Enum::Struct { value: 1 }, /// }; /// /// let yaml = serde_yml::to_string(&object).unwrap(); /// print!("{}", yaml); /// /// let deserialized: Struct = serde_yml::from_str(&yaml).unwrap(); /// assert_eq!(object, deserialized); /// ``` /// /// The representation using `singleton_map` on all the fields is: /// /// ```yaml /// w: Unit /// x: /// Newtype: 1 /// y: /// Tuple: /// - 1 /// - 1 /// z: /// Struct: /// value: 1 /// ``` /// /// Without `singleton_map`, the default behaviour would have been to serialize /// as: /// /// ```yaml /// w: Unit /// x: !Newtype 1 /// y: !Tuple /// - 1 /// - 1 /// z: !Struct /// value: 1 /// ``` pub mod singleton_map { use crate::value::{Mapping, Sequence, Value}; use serde::de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, MapAccess, Unexpected, VariantAccess, Visitor, }; use serde::ser::{ self, Serialize, SerializeMap, SerializeStructVariant, SerializeTupleVariant, Serializer, }; use std::fmt::{self, Display}; /// Serializes a given value using a singleton map representation. /// /// This function wraps the given value in a singleton map structure before serialization. /// The singleton map representation uses the enum variant name as the key and the variant value as the value. /// /// # Arguments /// * `value` - A reference to the value to be serialized. /// * `serializer` - The serializer to use for serializing the value. /// /// # Returns /// A result containing the serialization output or an error in case of failure. /// pub fn serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: Serializer, { value.serialize(SingletonMap { delegate: serializer, }) } #[allow(missing_docs)] pub fn deserialize<'de, T, D>( deserializer: D, ) -> Result where T: Deserialize<'de>, D: Deserializer<'de>, { T::deserialize(SingletonMap { delegate: deserializer, }) } /// A wrapper struct that delegates serialization and deserialization to an underlying serializer or deserializer. /// /// This struct is used internally by the `singleton_map` module to wrap the serializer or deserializer /// and provide the necessary functionality for serializing and deserializing enums using the singleton map representation. /// /// The `SingletonMap` struct contains a single field, `delegate`, which holds the underlying serializer or deserializer. /// /// # Type Parameters /// /// * `D` - The type of the underlying serializer or deserializer. /// /// # Fields /// /// * `delegate` - The underlying serializer or deserializer to which serialization and deserialization are delegated. #[derive(Clone, Copy, Debug)] pub struct SingletonMap { /// The underlying serializer or deserializer to which serialization and deserialization are delegated. pub delegate: D, } impl Serialize for SingletonMap where D: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.delegate.serialize(SingletonMap { delegate: serializer, }) } } impl Serializer for SingletonMap where D: Serializer, { type Ok = D::Ok; type Error = D::Error; type SerializeSeq = D::SerializeSeq; type SerializeTuple = D::SerializeTuple; type SerializeTupleStruct = D::SerializeTupleStruct; type SerializeTupleVariant = SerializeTupleVariantAsSingletonMap; type SerializeMap = D::SerializeMap; type SerializeStruct = D::SerializeStruct; type SerializeStructVariant = SerializeStructVariantAsSingletonMap; fn serialize_bool( self, v: bool, ) -> Result { self.delegate.serialize_bool(v) } fn serialize_i8(self, v: i8) -> Result { self.delegate.serialize_i8(v) } fn serialize_i16( self, v: i16, ) -> Result { self.delegate.serialize_i16(v) } fn serialize_i32( self, v: i32, ) -> Result { self.delegate.serialize_i32(v) } fn serialize_i64( self, v: i64, ) -> Result { self.delegate.serialize_i64(v) } fn serialize_i128( self, v: i128, ) -> Result { self.delegate.serialize_i128(v) } fn serialize_u8(self, v: u8) -> Result { self.delegate.serialize_u8(v) } fn serialize_u16( self, v: u16, ) -> Result { self.delegate.serialize_u16(v) } fn serialize_u32( self, v: u32, ) -> Result { self.delegate.serialize_u32(v) } fn serialize_u64( self, v: u64, ) -> Result { self.delegate.serialize_u64(v) } fn serialize_u128( self, v: u128, ) -> Result { self.delegate.serialize_u128(v) } fn serialize_f32( self, v: f32, ) -> Result { self.delegate.serialize_f32(v) } fn serialize_f64( self, v: f64, ) -> Result { self.delegate.serialize_f64(v) } fn serialize_char( self, v: char, ) -> Result { self.delegate.serialize_char(v) } fn serialize_str( self, v: &str, ) -> Result { self.delegate.serialize_str(v) } fn serialize_bytes( self, v: &[u8], ) -> Result { self.delegate.serialize_bytes(v) } fn serialize_unit(self) -> Result { self.delegate.serialize_unit() } fn serialize_unit_struct( self, name: &'static str, ) -> Result { self.delegate.serialize_unit_struct(name) } fn serialize_unit_variant( self, name: &'static str, variant_index: u32, variant: &'static str, ) -> Result { self.delegate.serialize_unit_variant( name, variant_index, variant, ) } fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { self.delegate.serialize_newtype_struct(name, value) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_entry(variant, value)?; map.end() } fn serialize_none(self) -> Result { self.delegate.serialize_none() } fn serialize_some( self, value: &V, ) -> Result where V: ?Sized + Serialize, { self.delegate .serialize_some(&SingletonMap { delegate: value }) } fn serialize_seq( self, len: Option, ) -> Result { self.delegate.serialize_seq(len) } fn serialize_tuple( self, len: usize, ) -> Result { self.delegate.serialize_tuple(len) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { self.delegate.serialize_tuple_struct(name, len) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_key(variant)?; let sequence = Sequence::with_capacity(len); Ok(SerializeTupleVariantAsSingletonMap { map, sequence }) } fn serialize_map( self, len: Option, ) -> Result { self.delegate.serialize_map(len) } fn serialize_struct( self, name: &'static str, len: usize, ) -> Result { self.delegate.serialize_struct(name, len) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_key(variant)?; let mapping = Mapping::with_capacity(len); Ok(SerializeStructVariantAsSingletonMap { map, mapping }) } fn collect_str( self, value: &T, ) -> Result where T: ?Sized + Display, { self.delegate.collect_str(value) } fn is_human_readable(&self) -> bool { self.delegate.is_human_readable() } } /// A helper struct for serializing tuple variants as singleton maps. /// /// This struct is used internally by the `singleton_map` module to serialize tuple variants /// as YAML maps with a single key-value pair, where the key is the variant name and the value /// is a YAML sequence containing the tuple elements. /// /// # Type Parameters /// /// * `M` - The type of the underlying serializer map. #[derive(Clone, Debug)] pub struct SerializeTupleVariantAsSingletonMap { /// The underlying serializer map to which the tuple variant is serialized. map: M, /// The YAML sequence that holds the tuple elements. sequence: Sequence, } impl SerializeTupleVariant for SerializeTupleVariantAsSingletonMap where M: SerializeMap, { type Ok = M::Ok; type Error = M::Error; fn serialize_field( &mut self, field: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { let value = field .serialize(crate::value::Serializer) .map_err(ser::Error::custom)?; self.sequence.push(value); Ok(()) } fn end(mut self) -> Result { self.map.serialize_value(&self.sequence)?; self.map.end() } } /// A helper struct for serializing struct variants as singleton maps. /// /// This struct is used internally by the `singleton_map` module to serialize struct variants /// as YAML maps with a single key-value pair, where the key is the variant name and the value /// is a YAML mapping containing the struct fields. /// /// # Type Parameters /// /// * `M` - The type of the underlying serializer map. #[derive(Clone, Debug)] pub struct SerializeStructVariantAsSingletonMap { /// The underlying serializer map to which the struct variant is serialized. map: M, /// The YAML mapping that holds the struct fields. mapping: Mapping, } impl SerializeStructVariant for SerializeStructVariantAsSingletonMap where M: SerializeMap, { type Ok = M::Ok; type Error = M::Error; fn serialize_field( &mut self, name: &'static str, field: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { let value = field .serialize(crate::value::Serializer) .map_err(ser::Error::custom)?; self.mapping.insert(Value::String(name.to_owned()), value); Ok(()) } fn end(mut self) -> Result { self.map.serialize_value(&self.mapping)?; self.map.end() } } impl<'de, D> Deserializer<'de> for SingletonMap where D: Deserializer<'de>, { type Error = D::Error; fn deserialize_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_any(visitor) } fn deserialize_bool( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_bool(visitor) } fn deserialize_i8( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i8(visitor) } fn deserialize_i16( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i16(visitor) } fn deserialize_i32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i32(visitor) } fn deserialize_i64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i64(visitor) } fn deserialize_i128( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i128(visitor) } fn deserialize_u8( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u8(visitor) } fn deserialize_u16( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u16(visitor) } fn deserialize_u32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u32(visitor) } fn deserialize_u64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u64(visitor) } fn deserialize_u128( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u128(visitor) } fn deserialize_f32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_f32(visitor) } fn deserialize_f64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_f64(visitor) } fn deserialize_char( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_char(visitor) } fn deserialize_str( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_str(visitor) } fn deserialize_string( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_string(visitor) } fn deserialize_bytes( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_bytes(visitor) } fn deserialize_byte_buf( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_byte_buf(visitor) } fn deserialize_option( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_option(SingletonMapAsEnum { name: "", delegate: visitor, }) } fn deserialize_unit( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_unit(visitor) } fn deserialize_unit_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_unit_struct(name, visitor) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_newtype_struct(name, visitor) } fn deserialize_seq( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_seq(visitor) } fn deserialize_tuple( self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_tuple(len, visitor) } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_tuple_struct(name, len, visitor) } fn deserialize_map( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_map(visitor) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_struct(name, fields, visitor) } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_any(SingletonMapAsEnum { name, delegate: visitor, }) } fn deserialize_identifier( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_identifier(visitor) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_ignored_any(visitor) } fn is_human_readable(&self) -> bool { self.delegate.is_human_readable() } } struct SingletonMapAsEnum { name: &'static str, delegate: D, } impl<'de, V> Visitor<'de> for SingletonMapAsEnum where V: Visitor<'de>, { type Value = V::Value; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { self.delegate.expecting(formatter) } fn visit_str(self, v: &str) -> Result where E: de::Error, { self.delegate.visit_enum(de::value::StrDeserializer::new(v)) } fn visit_borrowed_str( self, v: &'de str, ) -> Result where E: de::Error, { self.delegate .visit_enum(de::value::BorrowedStrDeserializer::new(v)) } fn visit_string(self, v: String) -> Result where E: de::Error, { self.delegate .visit_enum(de::value::StringDeserializer::new(v)) } fn visit_none(self) -> Result where E: de::Error, { self.delegate.visit_none() } fn visit_some( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { self.delegate.visit_some(SingletonMap { delegate: deserializer, }) } fn visit_unit(self) -> Result where E: de::Error, { self.delegate.visit_unit() } fn visit_map(self, map: A) -> Result where A: MapAccess<'de>, { self.delegate.visit_enum(SingletonMapAsEnum { name: self.name, delegate: map, }) } } impl<'de, D> EnumAccess<'de> for SingletonMapAsEnum where D: MapAccess<'de>, { type Error = D::Error; type Variant = Self; fn variant_seed( mut self, seed: V, ) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de>, { match self.delegate.next_key_seed(seed)? { Some(value) => Ok((value, self)), None => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } } impl<'de, D> VariantAccess<'de> for SingletonMapAsEnum where D: MapAccess<'de>, { type Error = D::Error; fn unit_variant(self) -> Result<(), Self::Error> { Err(de::Error::invalid_type( Unexpected::Map, &"unit variant", )) } fn newtype_variant_seed( mut self, seed: T, ) -> Result where T: DeserializeSeed<'de>, { let value = self.delegate.next_value_seed(seed)?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } fn tuple_variant( mut self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { let value = self .delegate .next_value_seed(TupleVariantSeed { len, visitor })?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } fn struct_variant( mut self, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let value = self.delegate.next_value_seed(StructVariantSeed { name: self.name, fields, visitor, })?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } } struct TupleVariantSeed { len: usize, visitor: V, } impl<'de, V> DeserializeSeed<'de> for TupleVariantSeed where V: Visitor<'de>, { type Value = V::Value; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { deserializer.deserialize_tuple(self.len, self.visitor) } } struct StructVariantSeed { name: &'static str, fields: &'static [&'static str], visitor: V, } impl<'de, V> DeserializeSeed<'de> for StructVariantSeed where V: Visitor<'de>, { type Value = V::Value; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { deserializer.deserialize_struct( self.name, self.fields, self.visitor, ) } } } /// Serialize/deserialize an optional enum using a YAML map containing one entry in which /// the key identifies the variant name. /// /// This module is similar to `singleton_map`, but it works with optional (`Option`) fields. /// If the field is `Some`, it will be serialized/deserialized using the `singleton_map` representation. /// If the field is `None`, it will be serialized/deserialized as `null`. /// /// # Example /// /// ``` /// use serde::{Deserialize, Serialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum MyEnum { /// Variant1, /// Variant2(String), /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Example { /// #[serde(with = "serde_yml::with::singleton_map_optional")] /// field: Option, /// } /// /// let example = Example { /// field: Some(MyEnum::Variant2("value".to_string())), /// }; /// /// let yaml = serde_yml::to_string(&example).unwrap(); /// assert_eq!(yaml, "field:\n Variant2: value\n"); /// /// let deserialized: Example = serde_yml::from_str(&yaml).unwrap(); /// assert_eq!(example, deserialized); /// ``` pub mod singleton_map_optional { use super::singleton_map; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Serializes an optional value using the `singleton_map` representation. /// /// If the value is `Some`, it will be serialized using the `singleton_map` representation. /// If the value is `None`, it will be serialized as `null`. /// /// # Arguments /// /// * `value` - A reference to the optional value to be serialized. /// * `serializer` - The serializer to use for serializing the value. /// /// # Returns /// /// A result containing the serialization output or an error if serialization fails. pub fn serialize( value: &Option, serializer: S, ) -> Result where T: Serialize, S: Serializer, { match value { Some(v) => singleton_map::serialize(v, serializer), None => serializer.serialize_none(), } } /// Deserializes a value using the `singleton_map` representation. /// /// This function expects the input to be in the `singleton_map` representation. /// If the input is a YAML map with a single key-value pair, the value will be deserialized /// and wrapped in `Some`. If the input is `null`, it will be deserialized as `None`. /// /// # Arguments /// /// * `deserializer` - The deserializer to use for deserializing the value. /// /// # Returns /// /// A result containing the deserialized optional value or an error if deserialization fails. pub fn deserialize<'de, T, D>( deserializer: D, ) -> Result, D::Error> where T: Deserialize<'de>, D: Deserializer<'de>, { Deserialize::deserialize(singleton_map::SingletonMap { delegate: deserializer, }) } } /// Serialize/deserialize an enum using a YAML map containing one entry in which /// the key identifies the variant name, while allowing combination with other `serialize_with` attributes. /// /// This module provides a way to use `singleton_map` in combination with other `serialize_with` attributes. /// It simply forwards the serialization and deserialization calls to the `singleton_map` module. /// /// # Example /// /// ``` /// use serde::{Deserialize, Serialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum MyEnum { /// Variant1, /// Variant2(String), /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Example { /// #[serde(with = "serde_yml::with::singleton_map_with")] /// field: MyEnum, /// } /// /// // Assuming `some_other_module` is defined elsewhere /// mod some_other_module { /// use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// /// pub fn serialize(value: &T, serializer: S) -> Result /// where /// T: Serialize, /// S: Serializer, /// { /// // Custom serialization logic /// value.serialize(serializer) /// } /// /// pub fn deserialize<'de, T, D>(deserializer: D) -> Result /// where /// T: Deserialize<'de>, /// D: Deserializer<'de>, /// { /// // Custom deserialization logic /// T::deserialize(deserializer) /// } /// } /// /// let example = Example { /// field: MyEnum::Variant2("value".to_string()), /// }; /// /// let yaml = serde_yml::to_string(&example).unwrap(); /// assert_eq!(yaml, "field:\n Variant2: value\n"); /// /// let deserialized: Example = serde_yml::from_str(&yaml).unwrap(); /// assert_eq!(example, deserialized); /// ``` pub mod singleton_map_with { use super::singleton_map; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Serializes a value using the `singleton_map` representation. /// /// This function is a wrapper around `singleton_map::serialize` and allows using /// `singleton_map` in combination with other `serialize_with` attributes. /// /// # Arguments /// /// * `value` - A reference to the value to be serialized. /// * `serializer` - The serializer to use for serializing the value. /// /// # Returns /// /// A result containing the serialization output or an error if serialization fails. pub fn serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: Serializer, { singleton_map::serialize(value, serializer) } /// Deserializes a value using the `singleton_map` representation. /// /// This function is a wrapper around `singleton_map::deserialize` and allows using /// `singleton_map` in combination with other `serialize_with` attributes. /// /// # Arguments /// /// * `deserializer` - The deserializer to use for deserializing the value. /// /// # Returns /// /// A result containing the deserialized value or an error if deserialization fails. pub fn deserialize<'de, T, D>( deserializer: D, ) -> Result where T: Deserialize<'de>, D: Deserializer<'de>, { singleton_map::deserialize(deserializer) } } /// Apply [`singleton_map`] to *all* enums contained within the data structure. /// /// # Example /// /// ``` /// use serde::{Deserialize, Serialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum Enum { /// Int(i32), /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Inner { /// a: Enum, /// bs: Vec, /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Outer { /// tagged_style: Inner, /// /// #[serde(with = "serde_yml::with::singleton_map_recursive")] /// singleton_map_style: Inner, /// } /// /// let object = Outer { /// tagged_style: Inner { /// a: Enum::Int(0), /// bs: vec![Enum::Int(1)], /// }, /// singleton_map_style: Inner { /// a: Enum::Int(2), /// bs: vec![Enum::Int(3)], /// }, /// }; /// /// let yaml = serde_yml::to_string(&object).unwrap(); /// print!("{}", yaml); /// /// let deserialized: Outer = serde_yml::from_str(&yaml).unwrap(); /// assert_eq!(object, deserialized); /// ``` /// /// The serialized output is: /// /// ```yaml /// tagged_style: /// a: !Int 0 /// bs: /// - !Int 1 /// singleton_map_style: /// a: /// Int: 2 /// bs: /// - Int: 3 /// ``` /// /// This module can also be used for the top-level serializer or deserializer /// call, without `serde(with = …)`, as follows. /// /// ``` /// # use serde_derive::{Deserialize, Serialize}; /// # /// # #[derive(Serialize, Deserialize, PartialEq, Debug)] /// # enum Enum { /// # Int(i32), /// # } /// # /// # #[derive(Serialize, Deserialize, PartialEq, Debug)] /// # struct Inner { /// # a: Enum, /// # bs: Vec, /// # } /// # /// use std::io::{self, Write}; /// /// fn main() { /// let object = Inner { /// a: Enum::Int(0), /// bs: vec![Enum::Int(1)], /// }; /// /// let mut buf = Vec::new(); /// let mut serializer = serde_yml::Serializer::new(&mut buf); /// serde_yml::with::singleton_map_recursive::serialize(&object, &mut serializer).unwrap(); /// io::stdout().write_all(&buf).unwrap(); /// /// let deserializer = serde_yml::Deserializer::from_slice(&buf); /// let deserialized: Inner = serde_yml::with::singleton_map_recursive::deserialize(deserializer).unwrap(); /// assert_eq!(object, deserialized); /// } /// ``` pub mod singleton_map_recursive { use crate::value::{Mapping, Sequence, Value}; use serde::de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }; use serde::ser::{ self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer, }; use std::fmt::{self, Display}; #[allow(missing_docs)] pub fn serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: Serializer, { value.serialize(SingletonMapRecursive { delegate: serializer, }) } #[allow(missing_docs)] pub fn deserialize<'de, T, D>( deserializer: D, ) -> Result where T: Deserialize<'de>, D: Deserializer<'de>, { T::deserialize(SingletonMapRecursive { delegate: deserializer, }) } struct SingletonMapRecursive { delegate: D, } impl Serialize for SingletonMapRecursive where D: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.delegate.serialize(SingletonMapRecursive { delegate: serializer, }) } } impl Serializer for SingletonMapRecursive where D: Serializer, { type Ok = D::Ok; type Error = D::Error; type SerializeSeq = SingletonMapRecursive; type SerializeTuple = SingletonMapRecursive; type SerializeTupleStruct = SingletonMapRecursive; type SerializeTupleVariant = SerializeTupleVariantAsSingletonMapRecursive< D::SerializeMap, >; type SerializeMap = SingletonMapRecursive; type SerializeStruct = SingletonMapRecursive; type SerializeStructVariant = SerializeStructVariantAsSingletonMapRecursive< D::SerializeMap, >; fn serialize_bool( self, v: bool, ) -> Result { self.delegate.serialize_bool(v) } fn serialize_i8(self, v: i8) -> Result { self.delegate.serialize_i8(v) } fn serialize_i16( self, v: i16, ) -> Result { self.delegate.serialize_i16(v) } fn serialize_i32( self, v: i32, ) -> Result { self.delegate.serialize_i32(v) } fn serialize_i64( self, v: i64, ) -> Result { self.delegate.serialize_i64(v) } fn serialize_i128( self, v: i128, ) -> Result { self.delegate.serialize_i128(v) } fn serialize_u8(self, v: u8) -> Result { self.delegate.serialize_u8(v) } fn serialize_u16( self, v: u16, ) -> Result { self.delegate.serialize_u16(v) } fn serialize_u32( self, v: u32, ) -> Result { self.delegate.serialize_u32(v) } fn serialize_u64( self, v: u64, ) -> Result { self.delegate.serialize_u64(v) } fn serialize_u128( self, v: u128, ) -> Result { self.delegate.serialize_u128(v) } fn serialize_f32( self, v: f32, ) -> Result { self.delegate.serialize_f32(v) } fn serialize_f64( self, v: f64, ) -> Result { self.delegate.serialize_f64(v) } fn serialize_char( self, v: char, ) -> Result { self.delegate.serialize_char(v) } fn serialize_str( self, v: &str, ) -> Result { self.delegate.serialize_str(v) } fn serialize_bytes( self, v: &[u8], ) -> Result { self.delegate.serialize_bytes(v) } fn serialize_unit(self) -> Result { self.delegate.serialize_unit() } fn serialize_unit_struct( self, name: &'static str, ) -> Result { self.delegate.serialize_unit_struct(name) } fn serialize_unit_variant( self, name: &'static str, variant_index: u32, variant: &'static str, ) -> Result { self.delegate.serialize_unit_variant( name, variant_index, variant, ) } fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { self.delegate.serialize_newtype_struct( name, &SingletonMapRecursive { delegate: value }, ) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: ?Sized + Serialize, { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_entry( variant, &SingletonMapRecursive { delegate: value }, )?; map.end() } fn serialize_none(self) -> Result { self.delegate.serialize_none() } fn serialize_some( self, value: &V, ) -> Result where V: ?Sized + Serialize, { self.delegate.serialize_some(&SingletonMapRecursive { delegate: value, }) } fn serialize_seq( self, len: Option, ) -> Result { Ok(SingletonMapRecursive { delegate: self.delegate.serialize_seq(len)?, }) } fn serialize_tuple( self, len: usize, ) -> Result { Ok(SingletonMapRecursive { delegate: self.delegate.serialize_tuple(len)?, }) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { Ok(SingletonMapRecursive { delegate: self .delegate .serialize_tuple_struct(name, len)?, }) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_key(variant)?; let sequence = Sequence::with_capacity(len); Ok(SerializeTupleVariantAsSingletonMapRecursive { map, sequence, }) } fn serialize_map( self, len: Option, ) -> Result { Ok(SingletonMapRecursive { delegate: self.delegate.serialize_map(len)?, }) } fn serialize_struct( self, name: &'static str, len: usize, ) -> Result { Ok(SingletonMapRecursive { delegate: self.delegate.serialize_struct(name, len)?, }) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { let mut map = self.delegate.serialize_map(Some(1))?; map.serialize_key(variant)?; let mapping = Mapping::with_capacity(len); Ok(SerializeStructVariantAsSingletonMapRecursive { map, mapping, }) } fn collect_str( self, value: &T, ) -> Result where T: ?Sized + Display, { self.delegate.collect_str(value) } fn is_human_readable(&self) -> bool { self.delegate.is_human_readable() } } impl SerializeSeq for SingletonMapRecursive where D: SerializeSeq, { type Ok = D::Ok; type Error = D::Error; fn serialize_element( &mut self, elem: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { self.delegate.serialize_element(&SingletonMapRecursive { delegate: elem, }) } fn end(self) -> Result { self.delegate.end() } } impl SerializeTuple for SingletonMapRecursive where D: SerializeTuple, { type Ok = D::Ok; type Error = D::Error; fn serialize_element( &mut self, elem: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { self.delegate.serialize_element(&SingletonMapRecursive { delegate: elem, }) } fn end(self) -> Result { self.delegate.end() } } impl SerializeTupleStruct for SingletonMapRecursive where D: SerializeTupleStruct, { type Ok = D::Ok; type Error = D::Error; fn serialize_field( &mut self, value: &V, ) -> Result<(), Self::Error> where V: ?Sized + Serialize, { self.delegate.serialize_field(&SingletonMapRecursive { delegate: value, }) } fn end(self) -> Result { self.delegate.end() } } struct SerializeTupleVariantAsSingletonMapRecursive { map: M, sequence: Sequence, } impl SerializeTupleVariant for SerializeTupleVariantAsSingletonMapRecursive where M: SerializeMap, { type Ok = M::Ok; type Error = M::Error; fn serialize_field( &mut self, field: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { let value = field .serialize(SingletonMapRecursive { delegate: crate::value::Serializer, }) .map_err(ser::Error::custom)?; self.sequence.push(value); Ok(()) } fn end(mut self) -> Result { self.map.serialize_value(&self.sequence)?; self.map.end() } } impl SerializeMap for SingletonMapRecursive where D: SerializeMap, { type Ok = D::Ok; type Error = D::Error; fn serialize_key( &mut self, key: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { self.delegate .serialize_key(&SingletonMapRecursive { delegate: key }) } fn serialize_value( &mut self, value: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { self.delegate.serialize_value(&SingletonMapRecursive { delegate: value, }) } fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<(), Self::Error> where K: ?Sized + Serialize, V: ?Sized + Serialize, { self.delegate.serialize_entry( &SingletonMapRecursive { delegate: key }, &SingletonMapRecursive { delegate: value }, ) } fn end(self) -> Result { self.delegate.end() } } impl SerializeStruct for SingletonMapRecursive where D: SerializeStruct, { type Ok = D::Ok; type Error = D::Error; fn serialize_field( &mut self, key: &'static str, value: &V, ) -> Result<(), Self::Error> where V: ?Sized + Serialize, { self.delegate.serialize_field( key, &SingletonMapRecursive { delegate: value }, ) } fn end(self) -> Result { self.delegate.end() } } struct SerializeStructVariantAsSingletonMapRecursive { map: M, mapping: Mapping, } impl SerializeStructVariant for SerializeStructVariantAsSingletonMapRecursive where M: SerializeMap, { type Ok = M::Ok; type Error = M::Error; fn serialize_field( &mut self, name: &'static str, field: &T, ) -> Result<(), Self::Error> where T: ?Sized + Serialize, { let value = field .serialize(SingletonMapRecursive { delegate: crate::value::Serializer, }) .map_err(ser::Error::custom)?; self.mapping.insert(Value::String(name.to_owned()), value); Ok(()) } fn end(mut self) -> Result { self.map.serialize_value(&self.mapping)?; self.map.end() } } impl<'de, D> Deserializer<'de> for SingletonMapRecursive where D: Deserializer<'de>, { type Error = D::Error; fn deserialize_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_any(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_bool( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_bool(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_i8( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i8(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_i16( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i16(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_i32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i32(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_i64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i64(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_i128( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_i128(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_u8( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u8(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_u16( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u16(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_u32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u32(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_u64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u64(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_u128( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_u128(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_f32( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_f32(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_f64( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_f64(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_char( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_char(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_str( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_str(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_string( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_string(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_bytes( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_bytes(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_byte_buf( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_byte_buf(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_option( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_option( SingletonMapRecursiveAsEnum { name: "", delegate: visitor, }, ) } fn deserialize_unit( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_unit(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_unit_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_unit_struct( name, SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_newtype_struct( name, SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_seq( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_seq(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_tuple( self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_tuple( len, SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_tuple_struct( name, len, SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_map( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_map(SingletonMapRecursive { delegate: visitor, }) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_struct( name, fields, SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_any(SingletonMapRecursiveAsEnum { name, delegate: visitor, }) } fn deserialize_identifier( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_identifier( SingletonMapRecursive { delegate: visitor }, ) } fn deserialize_ignored_any( self, visitor: V, ) -> Result where V: Visitor<'de>, { self.delegate.deserialize_ignored_any( SingletonMapRecursive { delegate: visitor }, ) } fn is_human_readable(&self) -> bool { self.delegate.is_human_readable() } } impl<'de, V> Visitor<'de> for SingletonMapRecursive where V: Visitor<'de>, { type Value = V::Value; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { self.delegate.expecting(formatter) } fn visit_bool(self, v: bool) -> Result where E: de::Error, { self.delegate.visit_bool(v) } fn visit_i8(self, v: i8) -> Result where E: de::Error, { self.delegate.visit_i8(v) } fn visit_i16(self, v: i16) -> Result where E: de::Error, { self.delegate.visit_i16(v) } fn visit_i32(self, v: i32) -> Result where E: de::Error, { self.delegate.visit_i32(v) } fn visit_i64(self, v: i64) -> Result where E: de::Error, { self.delegate.visit_i64(v) } fn visit_i128(self, v: i128) -> Result where E: de::Error, { self.delegate.visit_i128(v) } fn visit_u8(self, v: u8) -> Result where E: de::Error, { self.delegate.visit_u8(v) } fn visit_u16(self, v: u16) -> Result where E: de::Error, { self.delegate.visit_u16(v) } fn visit_u32(self, v: u32) -> Result where E: de::Error, { self.delegate.visit_u32(v) } fn visit_u64(self, v: u64) -> Result where E: de::Error, { self.delegate.visit_u64(v) } fn visit_u128(self, v: u128) -> Result where E: de::Error, { self.delegate.visit_u128(v) } fn visit_f32(self, v: f32) -> Result where E: de::Error, { self.delegate.visit_f32(v) } fn visit_f64(self, v: f64) -> Result where E: de::Error, { self.delegate.visit_f64(v) } fn visit_char(self, v: char) -> Result where E: de::Error, { self.delegate.visit_char(v) } fn visit_str(self, v: &str) -> Result where E: de::Error, { self.delegate.visit_str(v) } fn visit_borrowed_str( self, v: &'de str, ) -> Result where E: de::Error, { self.delegate.visit_borrowed_str(v) } fn visit_string(self, v: String) -> Result where E: de::Error, { self.delegate.visit_string(v) } fn visit_bytes(self, v: &[u8]) -> Result where E: de::Error, { self.delegate.visit_bytes(v) } fn visit_borrowed_bytes( self, v: &'de [u8], ) -> Result where E: de::Error, { self.delegate.visit_borrowed_bytes(v) } fn visit_byte_buf(self, v: Vec) -> Result where E: de::Error, { self.delegate.visit_byte_buf(v) } fn visit_none(self) -> Result where E: de::Error, { self.delegate.visit_none() } fn visit_some( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { self.delegate.visit_some(SingletonMapRecursive { delegate: deserializer, }) } fn visit_unit(self) -> Result where E: de::Error, { self.delegate.visit_unit() } fn visit_newtype_struct( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { self.delegate.visit_newtype_struct(SingletonMapRecursive { delegate: deserializer, }) } fn visit_seq(self, seq: A) -> Result where A: SeqAccess<'de>, { self.delegate .visit_seq(SingletonMapRecursive { delegate: seq }) } fn visit_map(self, map: A) -> Result where A: MapAccess<'de>, { self.delegate .visit_map(SingletonMapRecursive { delegate: map }) } } impl<'de, T> DeserializeSeed<'de> for SingletonMapRecursive where T: DeserializeSeed<'de>, { type Value = T::Value; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { self.delegate.deserialize(SingletonMapRecursive { delegate: deserializer, }) } } impl<'de, S> SeqAccess<'de> for SingletonMapRecursive where S: SeqAccess<'de>, { type Error = S::Error; fn next_element_seed( &mut self, seed: T, ) -> Result, Self::Error> where T: DeserializeSeed<'de>, { self.delegate.next_element_seed(SingletonMapRecursive { delegate: seed, }) } } impl<'de, M> MapAccess<'de> for SingletonMapRecursive where M: MapAccess<'de>, { type Error = M::Error; fn next_key_seed( &mut self, seed: K, ) -> Result, Self::Error> where K: DeserializeSeed<'de>, { self.delegate .next_key_seed(SingletonMapRecursive { delegate: seed }) } fn next_value_seed( &mut self, seed: V, ) -> Result where V: DeserializeSeed<'de>, { self.delegate.next_value_seed(SingletonMapRecursive { delegate: seed, }) } } struct SingletonMapRecursiveAsEnum { name: &'static str, delegate: D, } impl<'de, V> Visitor<'de> for SingletonMapRecursiveAsEnum where V: Visitor<'de>, { type Value = V::Value; fn expecting( &self, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { self.delegate.expecting(formatter) } fn visit_str(self, v: &str) -> Result where E: de::Error, { self.delegate.visit_enum(de::value::StrDeserializer::new(v)) } fn visit_borrowed_str( self, v: &'de str, ) -> Result where E: de::Error, { self.delegate .visit_enum(de::value::BorrowedStrDeserializer::new(v)) } fn visit_string(self, v: String) -> Result where E: de::Error, { self.delegate .visit_enum(de::value::StringDeserializer::new(v)) } fn visit_none(self) -> Result where E: de::Error, { self.delegate.visit_none() } fn visit_some( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { self.delegate.visit_some(SingletonMapRecursive { delegate: deserializer, }) } fn visit_unit(self) -> Result where E: de::Error, { self.delegate.visit_unit() } fn visit_map(self, map: A) -> Result where A: MapAccess<'de>, { self.delegate.visit_enum(SingletonMapRecursiveAsEnum { name: self.name, delegate: map, }) } } impl<'de, D> EnumAccess<'de> for SingletonMapRecursiveAsEnum where D: MapAccess<'de>, { type Error = D::Error; type Variant = Self; fn variant_seed( mut self, seed: V, ) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de>, { match self.delegate.next_key_seed(seed)? { Some(value) => Ok((value, self)), None => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } } impl<'de, D> VariantAccess<'de> for SingletonMapRecursiveAsEnum where D: MapAccess<'de>, { type Error = D::Error; fn unit_variant(self) -> Result<(), Self::Error> { Err(de::Error::invalid_type( Unexpected::Map, &"unit variant", )) } fn newtype_variant_seed( mut self, seed: T, ) -> Result where T: DeserializeSeed<'de>, { let value = self.delegate.next_value_seed( SingletonMapRecursive { delegate: seed }, )?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } fn tuple_variant( mut self, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { let value = self.delegate.next_value_seed(TupleVariantSeed { len, visitor: SingletonMapRecursive { delegate: visitor, }, })?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } fn struct_variant( mut self, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let value = self.delegate.next_value_seed(StructVariantSeed { name: self.name, fields, visitor: SingletonMapRecursive { delegate: visitor, }, })?; match self.delegate.next_key()? { None => Ok(value), Some(IgnoredAny) => Err(de::Error::invalid_value( Unexpected::Map, &"map with a single key", )), } } } struct TupleVariantSeed { len: usize, visitor: V, } impl<'de, V> DeserializeSeed<'de> for TupleVariantSeed where V: Visitor<'de>, { type Value = V::Value; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { deserializer.deserialize_tuple(self.len, self.visitor) } } struct StructVariantSeed { name: &'static str, fields: &'static [&'static str], visitor: V, } impl<'de, V> DeserializeSeed<'de> for StructVariantSeed where V: Visitor<'de>, { type Value = V::Value; fn deserialize( self, deserializer: D, ) -> Result where D: Deserializer<'de>, { deserializer.deserialize_struct( self.name, self.fields, self.visitor, ) } } } /// Serialize/deserialize nested enums using a YAML map containing one entry in which /// the key identifies the variant name. /// /// This function is similar to `singleton_map`, but it applies the singleton map representation /// recursively to all nested enums within the data structure. /// /// # Example /// /// ``` /// use serde::{Deserialize, Serialize}; /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum InnerEnum { /// Variant1, /// Variant2(String), /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// enum OuterEnum { /// Variant1(InnerEnum), /// Variant2 { /// inner: InnerEnum, /// }, /// } /// /// #[derive(Serialize, Deserialize, PartialEq, Debug)] /// struct Example { /// #[serde(with = "serde_yml::with::nested_singleton_map")] /// field: OuterEnum, /// } /// /// let example = Example { /// field: OuterEnum::Variant2 { /// inner: InnerEnum::Variant2("value".to_string()), /// }, /// }; /// /// let yaml = serde_yml::to_string(&example).unwrap(); /// assert_eq!(yaml, "field:\n Variant2:\n inner:\n Variant2: value\n"); /// /// let deserialized: Example = serde_yml::from_str(&yaml).unwrap(); /// assert_eq!(example, deserialized); /// ``` pub mod nested_singleton_map { use super::singleton_map_recursive; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Serializes a value using the nested singleton map representation. /// /// This function applies the singleton map representation recursively to all nested enums /// within the value being serialized. /// /// # Arguments /// /// * `value` - A reference to the value to be serialized. /// * `serializer` - The serializer to use for serializing the value. /// /// # Returns /// /// A result containing the serialization output or an error if serialization fails. pub fn serialize( value: &T, serializer: S, ) -> Result where T: Serialize, S: Serializer, { singleton_map_recursive::serialize(value, serializer) } /// Deserializes a value using the nested singleton map representation. /// /// This function expects the input to be in the nested singleton map representation, where /// all nested enums are represented as YAML maps with a single key-value pair. /// /// # Arguments /// /// * `deserializer` - The deserializer to use for deserializing the value. /// /// # Returns /// /// A result containing the deserialized value or an error if deserialization fails. pub fn deserialize<'de, T, D>( deserializer: D, ) -> Result where T: Deserialize<'de>, D: Deserializer<'de>, { singleton_map_recursive::deserialize(deserializer) } } serde_yml-0.0.12/tests/data/test.json000064400000000000000000000001021046102023000156050ustar 00000000000000{ "name": "John Doe", "age": 30, "city": "New York" } serde_yml-0.0.12/tests/libyml/mod.rs000064400000000000000000000007611046102023000154520ustar 00000000000000/// 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; serde_yml-0.0.12/tests/libyml/test_emitter.rs000064400000000000000000000335111046102023000174020ustar 00000000000000#[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"); } } serde_yml-0.0.12/tests/libyml/test_error.rs000064400000000000000000000012021046102023000170520ustar 00000000000000#[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") } } } } serde_yml-0.0.12/tests/libyml/test_parser.rs000064400000000000000000000151141046102023000172240ustar 00000000000000#[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" ); } } serde_yml-0.0.12/tests/libyml/test_safe_cstr.rs000064400000000000000000000214171046102023000177040ustar 00000000000000#[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"); } } serde_yml-0.0.12/tests/libyml/test_tag.rs000064400000000000000000000062341046102023000165060ustar 00000000000000#[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); } } serde_yml-0.0.12/tests/libyml/test_util.rs000064400000000000000000000072741046102023000167150ustar 00000000000000#[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); } } serde_yml-0.0.12/tests/mod.rs000064400000000000000000000003461046102023000141610ustar 00000000000000/// This module contains the tests for the `libyml` module. pub mod libyml; /// This module contains the tests for the `modules` module. pub mod modules; /// This module contains the tests for the `value` module. pub mod value; serde_yml-0.0.12/tests/modules/mod.rs000064400000000000000000000001151046102023000156230ustar 00000000000000/// This module contains the tests for the `path` module. pub mod test_path; serde_yml-0.0.12/tests/modules/test_path.rs000064400000000000000000000230161046102023000170440ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::{de::Event, 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::Seq` variant with a very large index. /// /// This test checks that a sequence path with a large index is correctly formatted. #[test] fn test_path_seq_large_index() { let root = Path::Root; let path = Path::Seq { parent: &root, index: usize::MAX, }; assert_eq!( format!("{}", path), format!("\\[{}\\]", usize::MAX) ); } /// Test the `Path::Seq` variant with a nested parent. /// /// This test checks that a sequence path with a parent sequence is correctly formatted. #[test] fn test_seq_with_parent() { let root = Path::Root; let parent_seq = Path::Seq { parent: &root, index: 1, }; let child_seq = Path::Seq { parent: &parent_seq, index: 42, }; assert_eq!(format!("{}", child_seq), "\\[1\\].\\[42\\]"); } /// Test the `Path::Seq` variant with different indices. /// /// This test validates that various index values in the `Seq` variant are correctly formatted. #[test] fn test_seq_with_different_indices() { let root = Path::Root; let path_zero = Path::Seq { parent: &root, index: 0, }; assert_eq!(format!("{}", path_zero), "\\[0\\]"); let path_large = Path::Seq { parent: &root, index: 100, }; assert_eq!(format!("{}", path_large), "\\[100\\]"); } /// 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_name", }; assert_eq!(format!("{}", path), "key_name"); } /// Test the `Path::Map` variant with an empty key. /// /// 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), ""); } /// Test the `Path::Map` variant with different keys. /// /// This test validates that various key values in the `Map` variant are correctly formatted. #[test] fn test_map_with_different_keys() { let root = Path::Root; let path_empty_key = Path::Map { parent: &root, key: "", }; assert_eq!(format!("{}", path_empty_key), ""); let path_special_key = Path::Map { parent: &root, key: "special_key", }; assert_eq!(format!("{}", path_special_key), "special_key"); let path_number_key = Path::Map { parent: &root, key: "123", }; assert_eq!(format!("{}", path_number_key), "123"); } /// Test the `Path::Map` variant with a parent sequence. /// /// This test checks that the `parent` field in a `Map` variant is correctly formatted. #[test] fn test_map_with_parent() { let root = Path::Root; let parent_seq = Path::Seq { parent: &root, index: 1, }; let map = Path::Map { parent: &parent_seq, key: "key", }; assert_eq!(format!("{}", map), "\\[1\\].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::Alias` variant with a parent map. /// /// This test checks that the `parent` field in an `Alias` variant is correctly formatted. #[test] fn test_alias_with_parent() { let root = Path::Root; let parent_map = Path::Map { parent: &root, key: "parent_key", }; let alias = Path::Alias { parent: &parent_map, }; assert_eq!(format!("{}", alias), "parent_key."); } /// 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 the `Path::Unknown` variant with a parent map. /// /// This test checks that the `parent` field in an `Unknown` variant is correctly formatted. #[test] fn test_unknown_with_parent() { let root = Path::Root; let parent_map = Path::Map { parent: &root, key: "parent_key", }; let unknown = Path::Unknown { parent: &parent_map, }; assert_eq!(format!("{}", unknown), "parent_key.?"); } /// Test equality of two `Path` instances with the same structure. /// /// This test checks that two instances of `Path` with identical structures are considered equal. #[test] fn test_path_equality() { let root = Path::Root; let seq1 = Path::Seq { parent: &root, index: 42, }; let seq2 = Path::Seq { parent: &root, index: 42, }; assert_eq!(seq1, seq2); } /// Test cloning and copying a `Path` instance. /// /// This test checks that copying a `Path` instance results in an identical path. #[test] fn test_path_clone_and_copy() { let root = Path::Root; let seq = Path::Seq { parent: &root, index: 42, }; // No need to explicitly clone, just copy directly let seq_copy = seq; assert_eq!(seq, seq_copy); } /// 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 a complex nested structure with a `Seq` inside a `Map` inside another `Seq`. /// /// This test checks the formatting of a complex nested structure involving sequences and maps. #[test] fn test_path_complex_nested() { let root = Path::Root; let seq1 = Path::Seq { parent: &root, index: 1, }; let map = Path::Map { parent: &seq1, key: "key", }; let seq2 = Path::Seq { parent: &map, index: 99, }; assert_eq!(format!("{}", seq2), "\\[1\\].key.\\[99\\]"); } /// Test panic for unexpected end of sequence. #[test] #[should_panic(expected = "unexpected end of sequence")] fn test_panic_unexpected_end_of_sequence() { panic!("unexpected end of sequence"); } /// Test panic for unexpected end of mapping. #[test] #[should_panic(expected = "unexpected end of mapping")] fn test_panic_unexpected_end_of_mapping() { panic!("unexpected end of mapping"); } /// Test deserialization of the `Alias` variant in the `Event` enum. /// /// This test checks that the `Alias` variant is correctly handled in the `Event` enum. #[test] fn test_event_alias_variant() { let alias_index: usize = 42; // Example index let event = Event::Alias(alias_index); // Match the alias case to ensure it handles the usize correctly if let Event::Alias(index) = event { assert_eq!(index, alias_index); } else { panic!("Failed to match the Alias variant."); } } } serde_yml-0.0.12/tests/test_anchors_and_aliases.rs000064400000000000000000000041271046102023000204220ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::de::Event; use serde_yml::de::Progress; use serde_yml::loader::Loader; use std::str; #[test] fn test_document_loaded_successfully() { let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert!(document.error.is_none()); } #[test] fn test_document_events_count() { let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 6); // Update expected count to 6 } #[test] fn test_document_anchor_event_map_count() { let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.anchor_event_map.len(), 1); } #[test] fn test_document_event_contents() { let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[3]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "alias"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[4]; assert!(matches!(event, Event::Alias(0))); } } serde_yml-0.0.12/tests/test_de.rs000064400000000000000000000717631046102023000150440ustar 00000000000000#[cfg(test)] mod tests { #![allow( clippy::cast_lossless, clippy::cast_possible_wrap, clippy::derive_partial_eq_without_eq, clippy::similar_names, clippy::uninlined_format_args )] use indoc::indoc; use serde_derive::Deserialize; use serde_yml::{ de::{Event, Progress}, libyml::parser::{ MappingStart, Scalar, ScalarStyle::Plain, SequenceStart, }, loader::Loader, modules::error::ErrorImpl, Deserializer, Number, Value::{self, String as SerdeString}, }; use std::{ collections::BTreeMap, fmt::{Debug, Formatter}, io::Cursor, string::String, sync::Arc, }; // Helper functions fn test_de(yaml: &str, expected: &T) where T: serde::de::DeserializeOwned + PartialEq + Debug, { let deserialized: T = serde_yml::from_str(yaml).unwrap(); assert_eq!(*expected, deserialized); let value: Value = serde_yml::from_str(yaml).unwrap(); let deserialized = T::deserialize(&value).unwrap(); assert_eq!(*expected, deserialized); let deserialized: T = serde_yml::from_value(value).unwrap(); assert_eq!(*expected, deserialized); serde_yml::from_str::(yaml).unwrap(); let mut deserializer = Deserializer::from_str(yaml); let document = deserializer.next().unwrap(); let deserialized = T::deserialize(document).unwrap(); assert_eq!(*expected, deserialized); assert!(deserializer.next().is_none()); } fn test_de_no_value<'de, T>(yaml: &'de str, expected: &T) where T: serde::de::Deserialize<'de> + PartialEq + Debug, { let deserialized: T = serde_yml::from_str(yaml).unwrap(); assert_eq!(*expected, deserialized); serde_yml::from_str::(yaml).unwrap(); serde_yml::from_str::(yaml).unwrap(); } fn test_de_seed<'de, T, S>(yaml: &'de str, seed: S, expected: &T) where T: PartialEq + Debug, S: serde::de::DeserializeSeed<'de, Value = T>, { let deserialized: T = seed.deserialize(Deserializer::from_str(yaml)).unwrap(); assert_eq!(*expected, deserialized); serde_yml::from_str::(yaml).unwrap(); serde_yml::from_str::(yaml).unwrap(); } // *** Basic Deserialization Tests *** #[test] /// Test YAML deserialization with cyclic aliasing. fn test_alias() { let yaml = indoc! {" first: &alias 1 second: *alias third: 3 "}; let mut expected = BTreeMap::new(); expected.insert("first".to_owned(), 1); expected.insert("second".to_owned(), 1); expected.insert("third".to_owned(), 3); test_de(yaml, &expected); } #[test] /// Test borrowed strings with different YAML representations. fn test_borrowed() { let yaml = indoc! {" - plain nonàscii - 'single quoted' - \"double quoted\" "}; let expected = vec!["plain nonàscii", "single quoted", "double quoted"]; test_de_no_value(yaml, &expected); } #[test] /// Test YAML deserialization with a bomb-like structure to test depth limit. fn test_bomb() { #[derive(Debug, Deserialize, PartialEq)] struct Data { expected: String, } let yaml = indoc! {" a: &a ~ b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i] k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j] l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k] m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l] n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m] o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n] p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o] q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p] r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q] s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r] t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s] u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t] v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u] w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v] x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w] 'y': &y [*x,*x,*x,*x,*x,*x,*x,*x,*x] z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y] expected: string "}; let expected = Data { expected: "string".to_owned(), }; assert_eq!( expected, serde_yml::from_str::(yaml).unwrap() ); } #[test] /// Test handling of byte order marks (BOM) in YAML. fn test_byte_order_mark() { let yaml = "\u{feff}- 0\n"; let expected = vec![0]; test_de(yaml, &expected); } #[test] /// Test YAML deserialization with an enum that uses an alias. fn test_enum_alias() { #[derive(Deserialize, PartialEq, Debug)] enum E { A, B(u8, u8), } #[derive(Deserialize, PartialEq, Debug)] struct Data { a: E, b: E, } let yaml = indoc! {" aref: &aref A bref: &bref !B - 1 - 2 a: *aref b: *bref "}; let expected = Data { a: E::A, b: E::B(1, 2), }; test_de(yaml, &expected); } // Test for unresolved alias panic #[test] #[should_panic(expected = "unresolved alias: 42")] fn test_unresolved_alias_panic() { let alias_pos = 42; let result: Option = None; if result.is_none() { panic!("unresolved alias: {}", alias_pos); } } #[test] /// Test YAML deserialization with different enum representations. fn test_enum_representations() { #[derive(Deserialize, PartialEq, Debug)] enum Enum { Unit, Tuple(i32, i32), Struct { x: i32, y: i32 }, String(String), Number(f64), } let yaml = indoc! {" - Unit - 'Unit' - !Unit - !Unit ~ - !Unit null - !Tuple [0, 0] - !Tuple - 0 - 0 - !Struct {x: 0, 'y': 0} - !Struct x: 0 'y': 0 - !String '...' - !String ... - !Number 0 "}; let expected = vec![ Enum::Unit, Enum::Unit, Enum::Unit, Enum::Unit, Enum::Unit, Enum::Tuple(0, 0), Enum::Tuple(0, 0), Enum::Struct { x: 0, y: 0 }, Enum::Struct { x: 0, y: 0 }, Enum::String("...".to_owned()), Enum::String("...".to_owned()), Enum::Number(0.0), ]; test_de(yaml, &expected); let yaml = indoc! {" - !String "}; let expected = vec![Enum::String(String::new())]; test_de_no_value(yaml, &expected); } #[test] /// Test deserialization of untagged enums. fn test_enum_untagged() { #[derive(Deserialize, PartialEq, Debug)] #[serde(untagged)] pub(crate) enum UntaggedEnum { A { r#match: bool, }, AB { r#match: String, }, B { #[serde(rename = "if")] r#match: bool, }, C(String), } // A { let expected = UntaggedEnum::A { r#match: true }; let deserialized: UntaggedEnum = serde_yml::from_str("match: True").unwrap(); assert_eq!(expected, deserialized); } // AB { let expected = UntaggedEnum::AB { r#match: "T".to_owned(), }; let deserialized: UntaggedEnum = serde_yml::from_str("match: T").unwrap(); assert_eq!(expected, deserialized); } // B { let expected = UntaggedEnum::B { r#match: true }; let deserialized: UntaggedEnum = serde_yml::from_str("if: True").unwrap(); assert_eq!(expected, deserialized); } // C { let expected = UntaggedEnum::C("match".to_owned()); let deserialized: UntaggedEnum = serde_yml::from_str("match").unwrap(); assert_eq!(expected, deserialized); } } #[test] /// Test handling of empty string and tilde in YAML. fn test_empty_string() { #[derive(Deserialize, PartialEq, Debug)] struct Struct { empty: String, tilde: String, } let yaml = indoc! {" empty: tilde: ~ "}; let expected = Struct { empty: String::new(), tilde: "~".to_owned(), }; test_de_no_value(yaml, &expected); } #[test] /// Test YAML deserialization with empty scalar values. fn test_empty_scalar() { #[derive(Deserialize, PartialEq, Debug)] struct Struct { thing: T, } let yaml = "thing:\n"; let expected = Struct { thing: serde_yml::Sequence::new(), }; test_de(yaml, &expected); let expected = Struct { thing: serde_yml::Mapping::new(), }; test_de(yaml, &expected); } #[test] /// Test deserialization of i128 numbers that are larger than i64. fn test_i128_big() { let expected: i128 = i64::MIN as i128 - 1; let yaml = indoc! {" -9223372036854775809 "}; assert_eq!( expected, serde_yml::from_str::(yaml).unwrap() ); let octal = indoc! {" -0o1000000000000000000001 "}; assert_eq!( expected, serde_yml::from_str::(octal).unwrap() ); } #[test] /// Test YAML deserialization while ignoring tags. fn test_ignore_tag() { #[derive(Deserialize, Debug, PartialEq)] struct Data { struc: Struc, tuple: Tuple, newtype: Newtype, map: BTreeMap, vec: Vec, } #[derive(Deserialize, Debug, PartialEq)] struct Struc { x: usize, } #[derive(Deserialize, Debug, PartialEq)] struct Tuple(usize, usize); #[derive(Deserialize, Debug, PartialEq)] struct Newtype(usize); let yaml = indoc! {" struc: !wat x: 0 tuple: !wat - 0 - 0 newtype: !wat 0 map: !wat x: 0 vec: !wat - 0 "}; let expected = Data { struc: Struc { x: 0 }, tuple: Tuple(0, 0), newtype: Newtype(0), map: { let mut map = BTreeMap::new(); map.insert('x', 0); map }, vec: vec![0], }; test_de(yaml, &expected); } #[test] /// Test deserialization of mappings. fn test_de_mapping() { #[derive(Debug, Deserialize, PartialEq)] struct Data { pub(crate) substructure: serde_yml::Mapping, } let yaml = indoc! {" substructure: a: 'foo' b: 'bar' "}; let mut expected = Data { substructure: serde_yml::Mapping::new(), }; expected.substructure.insert( SerdeString("a".to_owned()), SerdeString("foo".to_owned()), ); expected.substructure.insert( SerdeString("b".to_owned()), SerdeString("bar".to_owned()), ); test_de(yaml, &expected); } #[test] /// Test YAML deserialization without using Value. fn test_no_value() { let yaml = "key: value"; let expected = BTreeMap::from([("key".to_string(), "value".to_string())]); test_de_no_value(yaml, &expected); } #[test] /// Test deserialization when no required fields are present. fn test_no_required_fields() { #[derive(Deserialize, PartialEq, Debug)] pub(crate) struct NoRequiredFields { optional: Option, } for document in ["", "# comment\n"] { let expected = NoRequiredFields { optional: None }; let deserialized: NoRequiredFields = serde_yml::from_str(document).unwrap(); assert_eq!(expected, deserialized); let expected = Vec::::new(); let deserialized: Vec = serde_yml::from_str(document).unwrap(); assert_eq!(expected, deserialized); let expected = BTreeMap::new(); let deserialized: BTreeMap = serde_yml::from_str(document).unwrap(); assert_eq!(expected, deserialized); let expected = None; let deserialized: Option = serde_yml::from_str(document).unwrap(); assert_eq!(expected, deserialized); let expected = Value::Null; let deserialized: Value = serde_yml::from_str(document).unwrap(); assert_eq!(expected, deserialized); } } #[test] /// Test various number formats in YAML, including hexadecimal, octal, and binary. fn test_numbers() { let cases = [ ("0xF0", "240"), ("+0xF0", "240"), ("-0xF0", "-240"), ("0o70", "56"), ("+0o70", "56"), ("-0o70", "-56"), ("0b10", "2"), ("+0b10", "2"), ("-0b10", "-2"), ("127", "127"), ("+127", "127"), ("-127", "-127"), (".inf", ".inf"), (".Inf", ".inf"), (".INF", ".inf"), ("-.inf", "-.inf"), ("-.Inf", "-.inf"), ("-.INF", "-.inf"), (".nan", ".nan"), (".NaN", ".nan"), (".NAN", ".nan"), ("0.1", "0.1"), ]; for &(yaml, expected) in &cases { let value = serde_yml::from_str::(yaml).unwrap(); match value { Value::Number(number) => { assert_eq!(number.to_string(), expected) } _ => panic!( "expected number. input={:?}, result={:?}", yaml, value ), } } // NOT numbers. let cases = [ "0127", "+0127", "-0127", "++.inf", "+-.inf", "++1", "+-1", "-+1", "--1", "0x+1", "0x-1", "-0x+1", "-0x-1", "++0x1", "+-0x1", "-+0x1", "--0x1", ]; for yaml in &cases { let value = serde_yml::from_str::(yaml).unwrap(); match value { Value::String(string) => assert_eq!(string, *yaml), _ => panic!( "expected string. input={:?}, result={:?}", yaml, value ), } } } #[test] /// Test handling of NaN (Not a Number) in YAML. fn test_nan() { assert!(serde_yml::from_str::(".nan") .unwrap() .is_sign_positive()); assert!(serde_yml::from_str::(".nan") .unwrap() .is_sign_positive()); } #[test] /// Test YAML number aliasing and deserialization as strings. fn test_number_alias_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { version: String, value: String, } let yaml = indoc! {" version: &a 1.10 value: *a "}; let expected = Num { version: "1.10".to_owned(), value: "1.10".to_owned(), }; test_de_no_value(yaml, &expected); } #[test] /// Test deserialization of strings that are large numbers. fn test_number_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { value: String, } let yaml = indoc! {" # Cannot be represented as u128 value: 340282366920938463463374607431768211457 "}; let expected = Num { value: "340282366920938463463374607431768211457".to_owned(), }; test_de_no_value(yaml, &expected); } // *** Event Handling Tests *** #[test] /// Test creation and formatting of an Event::Alias. fn test_event_alias() { let event = Event::Alias(42); assert_eq!(format!("{:?}", event), "Alias(42)"); } #[test] /// Test creation and formatting of an Event::Scalar. fn test_event_scalar() { let scalar = Scalar { value: b"some scalar value".to_vec().into(), tag: None, style: Plain, repr: None, anchor: None, }; let event = Event::Scalar(scalar); assert!(format!("{:?}", event).starts_with("Scalar(")); } #[test] /// Test creation and formatting of an Event::SequenceStart. fn test_event_sequence_start() { let sequence_start = SequenceStart { anchor: None, tag: None, }; let event = Event::SequenceStart(sequence_start); assert!(format!("{:?}", event).starts_with("SequenceStart(")); } #[test] /// Test creation and formatting of an Event::SequenceEnd. fn test_event_sequence_end() { let event = Event::SequenceEnd; assert_eq!(format!("{:?}", event), "SequenceEnd"); } #[test] /// Test creation and formatting of an Event::MappingStart. fn test_event_mapping_start() { let mapping_start = MappingStart { anchor: None, tag: None, }; let event = Event::MappingStart(mapping_start); assert!(format!("{:?}", event).starts_with("MappingStart(")); } #[test] /// Test creation and formatting of an Event::MappingEnd. fn test_event_mapping_end() { let event = Event::MappingEnd; assert_eq!(format!("{:?}", event), "MappingEnd"); } #[test] /// Test creation and formatting of an Event::Void. fn test_event_void() { let event = Event::Void; assert_eq!(format!("{:?}", event), "Void"); } // *** Progress Handling Tests *** #[test] /// Test deserialization of Progress::Slice variant. fn test_progress_slice() { let progress = Progress::Slice(b"test slice"); assert_eq!( format!("{:?}", progress), r#"Progress::Slice([116, 101, 115, 116, 32, 115, 108, 105, 99, 101])"# ); } #[test] /// Test deserialization of Progress::Read variant. fn test_progress_read() { let cursor = Cursor::new("test read"); let progress = Progress::Read(Box::new(cursor)); assert_eq!( format!("{:?}", progress), "Progress::Read(Box)" ); } #[test] /// Test deserialization of Progress::Str variant. fn test_progress_str() { let progress = Progress::Str("test string"); assert_eq!( format!("{:?}", progress), r#"Progress::Str("test string")"# ); } #[test] fn test_progress_document_returns_none() { // Obtain a Document from the Loader. let mut deserializer = Deserializer::from_str("test document"); let document = match deserializer.next() { Some(deserializer) => { if let Progress::Document(doc) = deserializer.progress { doc } else { panic!("Expected Progress::Document"); } } None => panic!("Expected a Document"), }; // Pass the Document to Progress::Document. let mut deserializer = Deserializer { progress: Progress::Document(document), }; match deserializer.progress { Progress::Document(_) => { assert!(deserializer.next().is_none()); } _ => panic!("Expected Progress::Document"), } } #[test] fn test_progress_fail_propagates_error() { // Create an Arc-wrapped ErrorImpl directly let error_impl = Arc::new(ErrorImpl::Message( "Mock error message".into(), None, )); // Pass the Arc to Progress::Fail let progress = Progress::Fail(error_impl.clone()); let deserializer = Deserializer { progress }; match deserializer.progress { Progress::Fail(err) => { // Ensure the error Arc is the same assert!(Arc::ptr_eq(&err, &error_impl)); } _ => panic!("Expected Progress::Fail"), } } #[test] /// Test deserialization of Progress::Iterable variant. fn test_progress_iterable() { let loader = match Loader::new(Progress::Str("dummy")) { Ok(loader) => loader, Err(err) => { eprintln!("Error: {}", err); return; } }; let progress = Progress::Iterable(loader); assert!(format!("{:?}", progress) .starts_with("Progress::Iterable(")); } #[test] /// Test deserialization of Progress::Document variant. fn test_progress_document() { let mut deserializer = Deserializer::from_str("test document"); let document = match deserializer.next() { Some(deserializer) => { if let Progress::Document(doc) = deserializer.progress { doc } else { panic!("Expected Progress::Document"); } } None => panic!("Expected a Document"), }; let progress = Progress::Document(document); assert!(format!("{:?}", progress) .starts_with("Progress::Document(")); } #[test] /// Test handling of Progress::Fail variant. fn test_progress_fail() { let error_impl = Arc::new(ErrorImpl::Message( "Mock error message".into(), None, )); let progress = Progress::Fail(Arc::clone(&error_impl)); assert!( format!("{:?}", progress).starts_with("Progress::Fail(") ); } #[test] /// Test error handling during progress in deserialization. fn test_error_handling_progress_fail() { let mut deserializer = Deserializer::from_str("invalid_yaml: [unterminated"); let result = deserializer.next(); match result { Some(Deserializer { progress: Progress::Document(doc), .. }) => { if doc.error.is_none() { panic!("Expected an error within the Document, but none was found."); } } Some(Deserializer { progress, .. }) => { panic!("Expected Progress::Document with an error, but got: {:?}", progress); } None => { panic!("Expected an error but none was found."); } } } // *** Advanced Deserialization Tests *** #[test] /// Test parsing of numbers and handling of errors. fn test_parse_number() { let n = "111".parse::().unwrap(); assert_eq!(n, Number::from(111)); let n = "-111".parse::().unwrap(); assert_eq!(n, Number::from(-111)); let n = "-1.1".parse::().unwrap(); assert_eq!(n, Number::from(-1.1)); let n = ".nan".parse::().unwrap(); assert_eq!(n, Number::from(f64::NAN)); assert!(n.as_f64().unwrap().is_sign_positive()); let n = ".inf".parse::().unwrap(); assert_eq!(n, Number::from(f64::INFINITY)); let n = "-.inf".parse::().unwrap(); assert_eq!(n, Number::from(f64::NEG_INFINITY)); let err = "null".parse::().unwrap_err(); assert_eq!(err.to_string(), "failed to parse YAML number"); let err = " 1 ".parse::().unwrap_err(); assert_eq!(err.to_string(), "failed to parse YAML number"); } #[test] /// Test deserialization with a custom DeserializeSeed implementation. fn test_seed() { #[derive(Debug, PartialEq)] struct MySeed; impl<'de> serde::de::DeserializeSeed<'de> for MySeed { type Value = String; fn deserialize( self, deserializer: D, ) -> Result where D: serde::de::Deserializer<'de>, { serde::Deserialize::deserialize(deserializer) } } let yaml = "seed_value"; let expected = "seed_value".to_string(); test_de_seed(yaml, MySeed, &expected); } #[test] /// Test YAML deserialization with stateful seeds. fn test_stateful() { struct Seed(i64); impl<'de> serde::de::DeserializeSeed<'de> for Seed { type Value = i64; fn deserialize( self, deserializer: D, ) -> Result where D: serde::de::Deserializer<'de>, { struct Visitor(i64); impl serde::de::Visitor<'_> for Visitor { type Value = i64; fn expecting( &self, formatter: &mut Formatter<'_>, ) -> std::fmt::Result { write!(formatter, "an integer") } fn visit_i64( self, v: i64, ) -> Result { Ok(v * self.0) } fn visit_u64( self, v: u64, ) -> Result { Ok(v as i64 * self.0) } } deserializer.deserialize_any(Visitor(self.0)) } } let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)]; for &(yaml, seed, expected) in &cases { test_de_seed(yaml, Seed(seed), &expected); } } #[test] /// Test deserialization of YAML with Python's `safe_dump` output format. fn test_python_safe_dump() { #[derive(Deserialize, PartialEq, Debug)] struct Frob { foo: u32, } let yaml = indoc! {r#" "foo": !!int |- 7200 "#}; let expected = Frob { foo: 7200 }; test_de(yaml, &expected); } #[test] /// Test YAML tag resolution. fn test_tag_resolution() { let yaml = indoc! {" - null - Null - NULL - ~ - - true - True - TRUE - false - False - FALSE - y - Y - yes - Yes - YES - n - N - no - No - NO - on - On - ON - off - Off - OFF "}; let expected = vec![ Value::Null, Value::Null, Value::Null, Value::Null, Value::Null, Value::Bool(true), Value::Bool(true), Value::Bool(true), Value::Bool(false), Value::Bool(false), Value::Bool(false), Value::String("y".to_owned()), Value::String("Y".to_owned()), Value::String("yes".to_owned()), Value::String("Yes".to_owned()), Value::String("YES".to_owned()), Value::String("n".to_owned()), Value::String("N".to_owned()), Value::String("no".to_owned()), Value::String("No".to_owned()), Value::String("NO".to_owned()), Value::String("on".to_owned()), Value::String("On".to_owned()), Value::String("ON".to_owned()), Value::String("off".to_owned()), Value::String("Off".to_owned()), Value::String("OFF".to_owned()), ]; test_de(yaml, &expected); } #[test] /// Test deserialization of u128 numbers that are larger than u64. fn test_u128_big() { let expected: u128 = u64::MAX as u128 + 1; let yaml = indoc! {" 18446744073709551616 "}; assert_eq!( expected, serde_yml::from_str::(yaml).unwrap() ); let octal = indoc! {" 0o2000000000000000000000 "}; assert_eq!( expected, serde_yml::from_str::(octal).unwrap() ); } } serde_yml-0.0.12/tests/test_error.rs000064400000000000000000000305511046102023000155730ustar 00000000000000#![allow(clippy::zero_sized_map_values)] use indoc::indoc; use serde::de::Deserialize; #[cfg(not(miri))] use serde::de::{SeqAccess, Visitor}; use serde_derive::{Deserialize, Serialize}; use serde_yml::value::{Tag, TaggedValue}; use serde_yml::{Deserializer, Value}; #[cfg(not(miri))] use std::collections::BTreeMap; #[cfg(not(miri))] use std::fmt; use std::fmt::Debug; use std::fmt::Formatter; fn test_error<'de, T>(yaml: &'de str, expected: &str) where T: Deserialize<'de> + Debug, { let result = serde_yml::from_str::(yaml); assert_eq!(expected, result.unwrap_err().to_string()); let mut deserializer = Deserializer::from_str(yaml); if let Some(first_document) = deserializer.next() { if deserializer.next().is_none() { let result = T::deserialize(first_document); assert_eq!(expected, result.unwrap_err().to_string()); } } } #[test] fn test_scan_error() { let yaml = ">\n@"; let expected = "found character that cannot start any token at line 2 column 1, while scanning for the next token"; test_error::(yaml, expected); } #[test] fn test_incorrect_type() { let yaml = indoc! {" --- str "}; let expected = "invalid type: string \"str\", expected i16 at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_incorrect_nested_type() { #[derive(Deserialize, Debug)] pub(crate) struct A { #[allow(dead_code)] pub(crate) b: Vec, } #[derive(Deserialize, Debug)] pub(crate) enum B { C(#[allow(dead_code)] C), } #[derive(Deserialize, Debug)] pub(crate) struct C { #[allow(dead_code)] pub(crate) d: bool, } let yaml = indoc! {" b: - !C d: fase "}; let expected = "b.\\[0\\].d: invalid type: string \"fase\", expected a boolean at line 3 column 8"; test_error::(yaml, expected); } #[test] fn test_empty() { let expected = "EOF while parsing a value"; test_error::("", expected); } #[test] fn test_missing_field() { #[derive(Deserialize, Debug)] pub(crate) struct Basic { #[allow(dead_code)] pub(crate) v: bool, #[allow(dead_code)] pub(crate) w: bool, } let yaml = indoc! {" --- v: true "}; let expected = "missing field `w` at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_unknown_anchor() { let yaml = indoc! {" --- *some "}; let expected = "unknown anchor at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_ignored_unknown_anchor() { #[derive(Deserialize, Debug)] pub(crate) struct Wrapper { #[allow(dead_code)] pub(crate) c: (), } let yaml = indoc! {" b: [*a] c: ~ "}; let expected = "unknown anchor at line 1 column 5"; test_error::(yaml, expected); } #[test] fn test_bytes() { let expected = "serialization and deserialization of bytes in YAML is not implemented"; test_error::<&[u8]>("...", expected); } #[test] fn test_two_documents() { let yaml = indoc! {" --- 0 --- 1 "}; let expected = "deserializing from YAML containing more than one document is not supported"; test_error::(yaml, expected); } #[test] fn test_second_document_syntax_error() { let yaml = indoc! {" --- 0 --- ] "}; let mut de = Deserializer::from_str(yaml); let first_doc = de.next().unwrap(); let result = ::deserialize(first_doc); assert_eq!(0, result.unwrap()); let second_doc = de.next().unwrap(); let result = ::deserialize(second_doc); let expected = "did not find expected node content at line 4 column 1, while parsing a block node"; assert_eq!(expected, result.unwrap_err().to_string()); } #[test] fn test_missing_enum_tag() { #[derive(Deserialize, Debug)] pub(crate) enum E { V(#[allow(dead_code)] usize), } let yaml = indoc! {r#" "V": 16 "other": 32 "#}; let expected = "invalid type: map, expected a YAML tag starting with '!'"; test_error::(yaml, expected); } #[test] fn test_serialize_nested_enum() { #[derive(Serialize, Debug)] pub(crate) enum Outer { Inner(Inner), } #[derive(Serialize, Debug)] pub(crate) enum Inner { Newtype(usize), Tuple(usize, usize), Struct { x: usize }, } let expected = "serializing nested enums in YAML is not supported yet"; let e = Outer::Inner(Inner::Newtype(0)); let error = serde_yml::to_string(&e).unwrap_err(); assert_eq!(error.to_string(), expected); let e = Outer::Inner(Inner::Tuple(0, 0)); let error = serde_yml::to_string(&e).unwrap_err(); assert_eq!(error.to_string(), expected); let e = Outer::Inner(Inner::Struct { x: 0 }); let error = serde_yml::to_string(&e).unwrap_err(); assert_eq!(error.to_string(), expected); let e = Value::Tagged(Box::new(TaggedValue { tag: Tag::new("Outer"), value: Value::Tagged(Box::new(TaggedValue { tag: Tag::new("Inner"), value: Value::Null, })), })); let error = serde_yml::to_string(&e).unwrap_err(); assert_eq!(error.to_string(), expected); } #[test] fn test_deserialize_nested_enum() { #[derive(Deserialize, Debug)] pub(crate) enum Outer { Inner(#[allow(dead_code)] Inner), } #[derive(Deserialize, Debug)] pub(crate) enum Inner { Variant(#[allow(dead_code)] Vec), } let yaml = indoc! {" --- !Inner [] "}; let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1"; test_error::(yaml, expected); let yaml = indoc! {" --- !Variant [] "}; let expected = "unknown variant `Variant`, expected `Inner`"; test_error::(yaml, expected); let yaml = indoc! {" --- !Inner !Variant [] "}; let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_variant_not_a_seq() { #[derive(Deserialize, Debug)] pub(crate) enum E { V(#[allow(dead_code)] usize), } let yaml = indoc! {" --- !V value: 0 "}; let expected = "invalid type: map, expected usize at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_struct_from_sequence() { #[derive(Deserialize, Debug)] pub(crate) struct Struct { #[allow(dead_code)] pub(crate) x: usize, #[allow(dead_code)] pub(crate) y: usize, } let yaml = indoc! {" [0, 0] "}; let expected = "invalid type: sequence, expected struct Struct"; test_error::(yaml, expected); } #[test] fn test_bad_bool() { let yaml = indoc! {" --- !!bool str "}; let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_bad_int() { let yaml = indoc! {" --- !!int str "}; let expected = "invalid value: string \"str\", expected an integer at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_bad_float() { let yaml = indoc! {" --- !!float str "}; let expected = "invalid value: string \"str\", expected a float at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_bad_null() { let yaml = indoc! {" --- !!null str "}; let expected = "invalid value: string \"str\", expected null at line 2 column 1"; test_error::<()>(yaml, expected); } #[test] fn test_short_tuple() { let yaml = indoc! {" --- [0, 0] "}; let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1"; test_error::<(u8, u8, u8)>(yaml, expected); } #[test] fn test_long_tuple() { let yaml = indoc! {" --- [0, 0, 0] "}; let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1"; test_error::<(u8, u8)>(yaml, expected); } #[test] fn test_invalid_scalar_type() { #[derive(Deserialize, Debug)] pub(crate) struct S { #[allow(dead_code)] pub(crate) x: [i32; 1], } let yaml = "x: ''\n"; let expected = "x: invalid type: string \"\", expected an array of length 1 at line 1 column 4"; test_error::(yaml, expected); } #[cfg(not(miri))] #[test] fn test_infinite_recursion_objects() { #[derive(Deserialize, Debug)] pub(crate) struct S { #[allow(dead_code)] pub(crate) x: Option>, } let yaml = "&a {'x': *a}"; let expected = "recursion limit exceeded"; test_error::(yaml, expected); } #[cfg(not(miri))] #[test] fn test_infinite_recursion_arrays() { #[derive(Deserialize, Debug)] pub(crate) struct S( #[allow(dead_code)] pub(crate) usize, #[allow(dead_code)] pub(crate) Option>, ); let yaml = "&a [0, *a]"; let expected = "recursion limit exceeded"; test_error::(yaml, expected); } #[cfg(not(miri))] #[test] fn test_infinite_recursion_newtype() { #[derive(Deserialize, Debug)] pub(crate) struct S(#[allow(dead_code)] pub(crate) Option>); let yaml = "&a [*a]"; let expected = "recursion limit exceeded"; test_error::(yaml, expected); } #[cfg(not(miri))] #[test] fn test_finite_recursion_objects() { #[derive(Deserialize, Debug)] pub(crate) struct S { #[allow(dead_code)] pub(crate) x: Option>, } let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000); let expected = "recursion limit exceeded at line 1 column 641"; test_error::(&yaml, expected); } #[cfg(not(miri))] #[test] fn test_finite_recursion_arrays() { #[derive(Deserialize, Debug)] pub(crate) struct S( #[allow(dead_code)] pub(crate) usize, #[allow(dead_code)] pub(crate) Option>, ); let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000); let expected = "recursion limit exceeded at line 1 column 513"; test_error::(&yaml, expected); } #[cfg(not(miri))] #[test] fn test_billion_laughs() { #[derive(Debug)] struct X; impl<'de> Visitor<'de> for X { type Value = X; fn expecting( &self, formatter: &mut Formatter<'_>, ) -> fmt::Result { formatter.write_str("exponential blowup") } fn visit_unit(self) -> Result { Ok(X) } fn visit_seq(self, mut seq: S) -> Result where S: SeqAccess<'de>, { while let Some(X) = seq.next_element()? {} Ok(X) } } impl<'de> Deserialize<'de> for X { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_any(X) } } let yaml = indoc! {" a: &a ~ b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] "}; let expected = "repetition limit exceeded"; test_error::>(yaml, expected); } #[test] fn test_duplicate_keys() { let yaml = indoc! {" --- thing: true thing: false "}; let expected = "duplicate entry with key \"thing\" at line 2 column 1"; test_error::(yaml, expected); let yaml = indoc! {" --- null: true ~: false "}; let expected = "duplicate entry with null key at line 2 column 1"; test_error::(yaml, expected); let yaml = indoc! {" --- 99: true 99: false "}; let expected = "duplicate entry with key 99 at line 2 column 1"; test_error::(yaml, expected); let yaml = indoc! {" --- {}: true {}: false "}; let expected = "duplicate entry in YAML map at line 2 column 1"; test_error::(yaml, expected); } serde_yml-0.0.12/tests/test_lib.rs000064400000000000000000000040511046102023000152040ustar 00000000000000#[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use serde_yml::{ from_reader, from_slice, from_str, to_string, Mapping, Number, Result, Sequence, Value, }; use std::io::Cursor; #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Point { x: f64, y: f64, } /// Test serialization of a Point struct to YAML string #[test] fn test_serialization() -> Result<()> { let point = Point { x: 1.0, y: 2.0 }; let yaml = to_string(&point)?; assert_eq!(yaml, "x: 1.0\n'y': 2.0\n"); Ok(()) } /// Test deserialization of a YAML string to a Point struct #[test] fn test_deserialization() -> Result<()> { let yaml = "x: 1.0\ny: 2.0\n"; let point: Point = from_str(yaml)?; assert_eq!(point, Point { x: 1.0, y: 2.0 }); Ok(()) } /// Test deserialization from a reader (Cursor in this case) #[test] fn test_from_reader() -> Result<()> { let yaml = "x: 1.0\ny: 2.0\n"; let mut cursor = Cursor::new(yaml); let point: Point = from_reader(&mut cursor)?; assert_eq!(point, Point { x: 1.0, y: 2.0 }); Ok(()) } /// Test deserialization from a byte slice #[test] fn test_from_slice() -> Result<()> { let yaml = b"x: 1.0\ny: 2.0\n"; let point: Point = from_slice(yaml)?; assert_eq!(point, Point { x: 1.0, y: 2.0 }); Ok(()) } /// Test Mapping functionality #[test] fn test_mapping() { let mut map = Mapping::new(); map.insert( Value::String("key".to_string()), Value::Number(Number::from(42)), ); assert_eq!(map.get("key").and_then(Value::as_i64), Some(42)); } /// Test Sequence functionality #[test] fn test_sequence() { let seq = Sequence::from(vec![ Value::Number(Number::from(1)), Value::Number(Number::from(2)), ]); assert_eq!(seq.len(), 2); assert_eq!(seq[0].as_i64(), Some(1)); } } serde_yml-0.0.12/tests/test_loader.rs000064400000000000000000000341001046102023000157020ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::{ de::{Event, Progress}, loader::Loader, modules::error::ErrorImpl, }; use std::io::Cursor; use std::str; use std::sync::Arc; #[test] // Tests for creating a new Loader instance and basic functionality fn test_loader_new() { // Arrange let input = "key: value"; let progress = Progress::Str(input); // Act let loader = Loader::new(progress).unwrap(); // Assert assert!(loader.parser.is_some()); assert_eq!(loader.parsed_document_count, 0); } #[test] // Tests for handling multiple documents in the input fn test_loader_multiple_documents() { // Arrange let input = "---\nkey1: value1\n...\n---\nkey2: value2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); // Act & Assert // Document 1 let document1 = loader.next_document().unwrap(); assert_eq!(document1.events.len(), 4); assert!(document1.error.is_none()); assert_eq!(document1.anchor_event_map.len(), 0); // Document 2 let document2 = loader.next_document().unwrap(); assert_eq!(document2.events.len(), 4); assert!(document2.error.is_none()); assert_eq!(document2.anchor_event_map.len(), 0); // No more documents assert!(loader.next_document().is_none()); } #[test] // Tests for handling unknown anchor errors fn test_loader_unknown_anchor() { // Arrange let input = "*unknown"; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); // Act let document = loader.next_document().unwrap(); // Assert assert_eq!(document.events.len(), 0); assert!(document.error.is_some()); assert_eq!(document.anchor_event_map.len(), 0); let error = document.error.unwrap(); assert!(matches!(*error, ErrorImpl::UnknownAnchor(_))); } #[test] // Tests for handling anchors and aliases fn test_loader_anchor_and_alias() { // Arrange let input = "---\nkey: &anchor value\nalias: *anchor\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); // Act let document = loader.next_document().unwrap(); // Assert assert_eq!(document.events.len(), 6); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 1); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[3]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "alias"); assert_eq!(scalar.anchor, None); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[4]; assert!(matches!(event, Event::Alias(0))); } #[test] // Tests for handling empty documents fn test_loader_empty_document() { let input = "---\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 1); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); let (event, _) = &document.events[0]; assert!(matches!(event, Event::Scalar(_))); } #[test] // Tests for handling sequences fn test_loader_sequence() { // Arrange let input = "---\n- item1\n- item2\n..."; let progress = Progress::Str(input); // Act let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); // Assert assert_eq!(document.events.len(), 4); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); let (event, _) = &document.events[0]; assert!(matches!(event, Event::SequenceStart(_))); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "item1"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[2]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "item2"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[3]; assert!(matches!(event, Event::SequenceEnd)); } #[test] /// Tests for loading mappings fn test_loader_mapping() { let input = "---\nkey1: value1\nkey2: value2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 6); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); let (event, _) = &document.events[0]; assert!(matches!(event, Event::MappingStart(_))); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key1"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[2]; if let Event::Scalar(scalar) = event { assert_eq!( str::from_utf8(&scalar.value).unwrap(), "value1" ); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[3]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key2"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[4]; if let Event::Scalar(scalar) = event { assert_eq!( str::from_utf8(&scalar.value).unwrap(), "value2" ); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[5]; assert!(matches!(event, Event::MappingEnd)); } #[test] /// Tests for loading escaped characters fn test_loader_escaped_characters() { let input = "---\nkey: \"value with \\\"quotes\\\"\"\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 4); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[2]; if let Event::Scalar(scalar) = event { assert_eq!( str::from_utf8(&scalar.value).unwrap(), "value with \"quotes\"" ); } else { panic!("Expected Event::Scalar"); } } #[test] /// Tests for loader ignoring comments fn test_loader_ignored_comments() { let input = "---\n# This is a comment\nkey: value # Inline comment\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 4); // Including comments assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); let (event, _) = &document.events[1]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "key"); } else { panic!("Expected Event::Scalar"); } let (event, _) = &document.events[2]; if let Event::Scalar(scalar) = event { assert_eq!(str::from_utf8(&scalar.value).unwrap(), "value"); } else { panic!("Expected Event::Scalar"); } } #[test] /// Tests for loading from a slice fn test_loader_new_from_slice() { let input = "key: value".as_bytes(); let progress = Progress::Slice(input); let loader = Loader::new(progress).unwrap(); assert!(loader.parser.is_some()); assert_eq!(loader.parsed_document_count, 0); } #[test] /// Tests for loading from a reader fn test_loader_new_from_reader() { let input = Cursor::new("key: value".as_bytes()); let progress = Progress::Read(Box::new(input)); let loader = Loader::new(progress).unwrap(); assert!(loader.parser.is_some()); assert_eq!(loader.parsed_document_count, 0); } #[test] /// Tests for loading from a reader with an error fn test_loader_new_from_fail() { let error = ErrorImpl::IoError(std::io::Error::new( std::io::ErrorKind::Other, "test error", )); let progress = Progress::Fail(Arc::new(ErrorImpl::Shared( Arc::new(error), ))); let loader_result = Loader::new(progress); assert!(loader_result.is_err()); } #[test] /// Tests for next_document() with empty input fn test_loader_next_document_empty_input() { let input = ""; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 1); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); assert!(loader.next_document().is_none()); } #[test] /// Tests for comments only fn test_loader_comments_only() { let input = "---\n# Comment\n# Another comment\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 1); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); } #[test] /// Tests for malformed YAML input fn test_loader_malformed_yaml() { let input = "---\nkey: value\nkey2 value2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert!(document.error.is_some()); } #[test] /// Tests for nested structures fn test_loader_nested_structures() { let input = "---\nkey:\n subkey: value\n list:\n - item1\n - item2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 12); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); } #[test] /// Test for nested mappings fn test_loader_nested_mappings() { let input = "---\nkey:\n subkey: value\n subkey2: value2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 9); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); } #[test] /// Test for nested sequences fn test_loader_nested_sequences() { let input = "---\nkey:\n - item1\n - item2\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 7); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); } #[test] /// Test for nested mappings and sequences fn test_loader_nested_mappings_and_sequences() { let input = "---\nkey:\n - item1\n - item2\n subkey: value\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 5); assert_eq!(document.anchor_event_map.len(), 0); } #[test] // Tests performance for loading large YAML documents fn test_loader_performance() { // Generate a large YAML input let mut input = String::from("---\n"); for i in 0..10000 { input.push_str(&format!("key{}: value{}\n", i, i)); } input.push_str("..."); let progress = Progress::Str(&input); let mut loader = Loader::new(progress).unwrap(); // Measure the time to parse the document let start_time = std::time::Instant::now(); let document = loader.next_document().unwrap(); let elapsed = start_time.elapsed(); // Assert that the document was parsed successfully assert!(document.error.is_none()); // Assert that the time taken to parse is reasonable assert!(elapsed.as_secs() < 1, "Parsing took too long"); } #[test] // Tests for handling documents with special characters fn test_loader_special_characters() { let input = "---\nkey: value!@#$%^&*()\n..."; let progress = Progress::Str(input); let mut loader = Loader::new(progress).unwrap(); let document = loader.next_document().unwrap(); assert_eq!(document.events.len(), 4); assert!(document.error.is_none()); assert_eq!(document.anchor_event_map.len(), 0); } } serde_yml-0.0.12/tests/test_mapping.rs000064400000000000000000000434171046102023000161020ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::mapping::*; use serde_yml::value::Value; /// Tests the creation of a new empty `Mapping`. #[test] fn test_mapping_new() { let map = Mapping::new(); assert!(map.map.is_empty()); } /// Tests creating a `Mapping` with a specified capacity. #[test] fn test_mapping_with_capacity() { let capacity = 10; let map = Mapping::with_capacity(capacity); assert!(map.map.is_empty()); assert!(map.map.capacity() >= capacity); } /// Tests reserving additional capacity in the `Mapping`. #[test] fn test_mapping_reserve() { let mut map = Mapping::new(); let additional = 10; map.reserve(additional); assert!(map.map.capacity() >= additional); } /// Tests shrinking the capacity of the `Mapping` to fit its content. #[test] fn test_mapping_shrink_to_fit() { let mut map = Mapping::with_capacity(100); map.shrink_to_fit(); assert!(map.map.capacity() <= 100); } /// Tests inserting a key-value pair into the `Mapping`. #[test] fn test_mapping_insert() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); assert!(map.insert(key.clone(), value.clone()).is_none()); assert_eq!(map.get(&key), Some(&value)); } /// Tests retrieving a mutable reference to a value in the `Mapping`. #[test] fn test_mapping_get_mut() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value); assert!(map.get_mut(&key).is_some()); } /// Tests getting the capacity of the `Mapping`. #[test] fn test_mapping_capacity() { let map = Mapping::with_capacity(10); assert_eq!(map.capacity(), 10); } /// Tests getting the length of the `Mapping`. #[test] fn test_mapping_len() { let mut map = Mapping::new(); assert_eq!(map.len(), 0); map.insert(Value::String("key".to_string()), Value::Null); assert_eq!(map.len(), 1); } /// Tests checking if the `Mapping` is empty. #[test] fn test_mapping_is_empty() { let map = Mapping::new(); assert!(map.is_empty()); } /// Tests clearing the `Mapping`. #[test] fn test_mapping_clear() { let mut map = Mapping::new(); map.insert(Value::String("key".to_string()), Value::Null); map.clear(); assert!(map.is_empty()); } /// Tests iterating over mutable references to the key-value pairs in the `Mapping`. #[test] fn test_mapping_iter_mut() { let mut map = Mapping::new(); map.insert( Value::String("key".to_string()), Value::String("value".to_string()), ); let mut iter = map.iter_mut(); let (key, value) = iter.next().unwrap(); assert_eq!(key, &Value::String("key".to_string())); assert_eq!(value, &mut Value::String("value".to_string())); } /// Tests iterating over the keys in the `Mapping`. #[test] fn test_mapping_keys() { let mut map = Mapping::new(); map.insert(Value::String("key".to_string()), Value::Null); let mut keys = map.keys(); assert_eq!( keys.next(), Some(&Value::String("key".to_string())) ); } /// Tests consuming the `Mapping` and iterating over its keys. #[test] fn test_mapping_into_keys() { let mut map = Mapping::new(); map.insert(Value::String("key".to_string()), Value::Null); let mut keys = map.into_keys(); assert_eq!(keys.next(), Some(Value::String("key".to_string()))); } /// Tests consuming the `Mapping` and iterating over its values. #[test] fn test_mapping_into_values() { let mut map = Mapping::new(); map.insert(Value::String("key".to_string()), Value::Null); let mut values = map.into_values(); assert_eq!(values.next(), Some(Value::Null)); } /// Tests removing an entry from the `Mapping` and returning the key-value pair. #[test] fn test_swap_remove_entry_from() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); let entry = key.swap_remove_entry_from(&mut map); assert_eq!(entry, Some((key, value))); } /// Tests removing a value from the `Mapping` by shifting following elements. #[test] fn test_shift_remove_from() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); let removed_value = key.shift_remove_from(&mut map); assert_eq!(removed_value, Some(value)); } /// Tests removing an entry from the `Mapping` by shifting following elements. #[test] fn test_shift_remove_entry_from() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); let entry = key.shift_remove_entry_from(&mut map); assert_eq!(entry, Some((key, value))); } /// Tests checking if a string key exists in the `Mapping`. #[test] fn test_str_is_key_into() { let mut map = Mapping::new(); let key = "key"; map.insert(Value::String(key.to_string()), Value::Null); assert!(key.is_key_into(&map)); } /// Tests retrieving a mutable reference to a value in the `Mapping` using a string key. #[test] fn test_str_index_into_mut() { let mut map = Mapping::new(); let key = "key"; let value = Value::String("value".to_string()); map.insert(Value::String(key.to_string()), value); assert!(key.index_into_mut(&mut map).is_some()); } /// Tests removing an entry from the `Mapping` using a string key and returning the key-value pair. #[test] fn test_str_swap_remove_entry_from() { let mut map = Mapping::new(); let key = "key"; let value = Value::String("value".to_string()); map.insert(Value::String(key.to_string()), value.clone()); let entry = key.swap_remove_entry_from(&mut map); assert_eq!( entry, Some((Value::String(key.to_string()), value)) ); } /// Tests removing a value from the `Mapping` using a string key by shifting following elements. #[test] fn test_str_shift_remove_from() { let mut map = Mapping::new(); let key = "key"; let value = Value::String("value".to_string()); map.insert(Value::String(key.to_string()), value.clone()); let removed_value = key.shift_remove_from(&mut map); assert_eq!(removed_value, Some(value)); } /// Tests removing an entry from the `Mapping` using a string key by shifting following elements. #[test] fn test_str_shift_remove_entry_from() { let mut map = Mapping::new(); let key = "key"; let value = Value::String("value".to_string()); map.insert(Value::String(key.to_string()), value.clone()); let entry = key.shift_remove_entry_from(&mut map); assert_eq!( entry, Some((Value::String(key.to_string()), value)) ); } /// Tests checking if a `String` key exists in the `Mapping`. #[test] fn test_string_is_key_into() { let mut map = Mapping::new(); let key = "key".to_string(); map.insert(Value::String(key.clone()), Value::Null); assert!(key.is_key_into(&map)); } /// Tests retrieving a reference to a value in the `Mapping` using a `String` key. #[test] fn test_string_index_into() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value.clone()); assert_eq!(key.index_into(&map), Some(&value)); } /// Tests retrieving a mutable reference to a value in the `Mapping` using a `String` key. #[test] fn test_string_index_into_mut() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value); assert!(key.index_into_mut(&mut map).is_some()); } /// Tests removing a value from the `Mapping` using a `String` key. #[test] fn test_string_swap_remove_from() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value.clone()); let removed_value = key.swap_remove_from(&mut map); assert_eq!(removed_value, Some(value)); } /// Tests removing an entry from the `Mapping` using a `String` key and returning the key-value pair. #[test] fn test_string_swap_remove_entry_from() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value.clone()); let entry = key.swap_remove_entry_from(&mut map); assert_eq!(entry, Some((Value::String(key), value))); } /// Tests removing a value from the `Mapping` using a `String` key by shifting following elements. #[test] fn test_string_shift_remove_from() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value.clone()); let removed_value = key.shift_remove_from(&mut map); assert_eq!(removed_value, Some(value)); } /// Tests removing an entry from the `Mapping` using a `String` key by shifting following elements. #[test] fn test_string_shift_remove_entry_from() { let mut map = Mapping::new(); let key = "key".to_string(); let value = Value::String("value".to_string()); map.insert(Value::String(key.clone()), value.clone()); let entry = key.shift_remove_entry_from(&mut map); assert_eq!(entry, Some((Value::String(key), value))); } /// Tests the `Entry` API for inserting a new key-value pair. #[test] fn test_mapping_entry_insert() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.entry(key.clone()).or_insert(value.clone()); assert_eq!(map.get(&key), Some(&value)); } /// Tests the `Entry` API for updating an existing key-value pair. #[test] fn test_mapping_entry_update() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value1 = Value::String("value1".to_string()); let value2 = Value::String("value2".to_string()); map.insert(key.clone(), value1.clone()); map.entry(key.clone()).and_modify(|v| *v = value2.clone()); assert_eq!(map.get(&key), Some(&value2)); } /// Tests the `retain` method for removing key-value pairs based on a predicate. #[test] fn test_mapping_retain() { let mut map = Mapping::new(); map.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); map.insert( Value::String("key2".to_string()), Value::Number(2.into()), ); map.insert( Value::String("key3".to_string()), Value::Number(3.into()), ); map.retain(|_, v| match v { Value::Number(n) => n.as_u64().unwrap() % 2 == 0, _ => false, }); assert_eq!(map.len(), 1); assert_eq!(map.get("key2"), Some(&Value::Number(2.into()))); } /// Tests the `Ord` implementation for `Mapping`. #[test] fn test_mapping_ord() { let mut map1 = Mapping::new(); map1.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); map1.insert( Value::String("key2".to_string()), Value::Number(2.into()), ); let mut map2 = Mapping::new(); map2.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); map2.insert( Value::String("key2".to_string()), Value::Number(3.into()), ); assert!(map1 < map2); } /// Tests the `PartialOrd` implementation for `Mapping`. #[test] fn test_mapping_partial_ord() { let mut map1 = Mapping::new(); map1.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); let mut map2 = Mapping::new(); map2.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); map2.insert( Value::String("key2".to_string()), Value::Number(2.into()), ); assert!(map1 <= map2); } /// Tests the `Hash` implementation for `Mapping`. #[test] fn test_mapping_hash() { use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; let mut map1 = Mapping::new(); map1.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); map1.insert( Value::String("key2".to_string()), Value::Number(2.into()), ); let mut map2 = Mapping::new(); map2.insert( Value::String("key2".to_string()), Value::Number(2.into()), ); map2.insert( Value::String("key1".to_string()), Value::Number(1.into()), ); let mut hasher1 = DefaultHasher::new(); map1.hash(&mut hasher1); let hash1 = hasher1.finish(); let mut hasher2 = DefaultHasher::new(); map2.hash(&mut hasher2); let hash2 = hasher2.finish(); assert_eq!(hash1, hash2); } /// Tests the `Index` trait implementation for `Mapping`. #[test] fn test_mapping_index() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); assert_eq!(map[&key], value); } /// Tests the `IndexMut` trait implementation for `Mapping`. #[test] fn test_mapping_index_mut() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value1 = Value::String("value1".to_string()); let value2 = Value::String("value2".to_string()); map.insert(key.clone(), value1.clone()); map[&key] = value2.clone(); assert_eq!(map[&key], value2); } /// Tests the `Extend` trait implementation for `Mapping`. #[test] fn test_mapping_extend() { let mut map = Mapping::new(); let key1 = Value::String("key1".to_string()); let value1 = Value::String("value1".to_string()); let key2 = Value::String("key2".to_string()); let value2 = Value::String("value2".to_string()); map.extend(vec![ (key1.clone(), value1.clone()), (key2.clone(), value2.clone()), ]); assert_eq!(map.len(), 2); assert_eq!(map.get(&key1), Some(&value1)); assert_eq!(map.get(&key2), Some(&value2)); } /// Tests the `FromIterator` trait implementation for `Mapping`. #[test] fn test_mapping_from_iterator() { let key1 = Value::String("key1".to_string()); let value1 = Value::String("value1".to_string()); let key2 = Value::String("key2".to_string()); let value2 = Value::String("value2".to_string()); let map: Mapping = vec![ (key1.clone(), value1.clone()), (key2.clone(), value2.clone()), ] .into_iter() .collect(); assert_eq!(map.len(), 2); assert_eq!(map.get(&key1), Some(&value1)); assert_eq!(map.get(&key2), Some(&value2)); } /// Tests the `Debug` trait implementation for `DuplicateKeyError`. #[test] fn test_duplicate_key_error_debug() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); match map.entry(key.clone()) { Entry::Occupied(entry) => { let error = DuplicateKeyError { entry }; let debug_str = format!("{:?}", error); assert_eq!( debug_str, "DuplicateKeyError { entry: OccupiedEntry { occupied: OccupiedEntry { key: String(\"key\"), value: String(\"value\") } } }" ); } Entry::Vacant(_) => panic!("Expected occupied entry"), } } /// Tests the `Display` trait implementation for `DuplicateKeyError`. #[test] fn test_duplicate_key_error_display() { let mut map = Mapping::new(); let key = Value::String("key".to_string()); let value = Value::String("value".to_string()); map.insert(key.clone(), value.clone()); match map.entry(key.clone()) { Entry::Occupied(entry) => { let error = DuplicateKeyError { entry }; let display_str = format!("{}", error); assert_eq!( display_str, "duplicate entry with key \"key\"" ); } Entry::Vacant(_) => panic!("Expected occupied entry"), } } } serde_yml-0.0.12/tests/test_number.rs000064400000000000000000000166701046102023000157400ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::Number; use std::{ cmp::Ordering, hash::{DefaultHasher, Hash, Hasher}, str::FromStr, }; // Tests for Number::as_i64 method #[test] fn test_as_i64() { let number = Number::from(42); assert_eq!(number.as_i64(), Some(42)); let number = Number::from(-42); assert_eq!(number.as_i64(), Some(-42)); let number = Number::from(std::f64::consts::PI); assert_eq!(number.as_i64(), None); } // Tests for Number::as_u64 method #[test] fn test_as_u64() { let number = Number::from(42); assert_eq!(number.as_u64(), Some(42)); let number = Number::from(-42); assert_eq!(number.as_u64(), None); let number = Number::from(std::f64::consts::PI); assert_eq!(number.as_u64(), None); } // Tests for Number::display method #[test] fn test_display() { let number = Number::from(42); assert_eq!(number.to_string(), "42"); let number = Number::from(-42); assert_eq!(number.to_string(), "-42"); let number = Number::from(f64::NAN); assert_eq!(number.to_string(), ".nan"); let number = Number::from(f64::INFINITY); assert_eq!(number.to_string(), ".inf"); let number = Number::from(-f64::INFINITY); assert_eq!(number.to_string(), "-.inf"); let number = Number::from(std::f64::consts::PI); assert!( (number.to_string().parse::().unwrap() - std::f64::consts::PI) .abs() < f64::EPSILON ); } // Tests for Number::as_f64 method #[test] fn test_as_f64() { let number = Number::from(42); assert_eq!(number.as_f64().unwrap(), 42.0); let number = Number::from(-42); assert_eq!(number.as_f64().unwrap(), -42.0); let number = Number::from(std::f64::consts::PI); assert!( (number.as_f64().unwrap() - std::f64::consts::PI).abs() < f64::EPSILON ); } // Tests for Number::from_str method #[test] fn test_from_str() { let number = Number::from_str("42").unwrap(); assert_eq!(number, Number::from(42)); let number = Number::from_str("-42").unwrap(); assert_eq!(number, Number::from(-42)); let number = Number::from(std::f64::consts::PI); assert_eq!(number, Number::from(std::f64::consts::PI)); let result = Number::from_str("invalid"); assert!(result.is_err()); } // Tests for Number::is_f64 method #[test] fn test_is_f64() { let number = Number::from(42); assert!(!number.is_f64()); let number = Number::from(-42); assert!(!number.is_f64()); let number = Number::from(std::f64::consts::PI); assert!(number.is_f64()); } // Tests for Number::is_i64 method #[test] fn test_is_i64() { let number = Number::from(42); assert!(number.is_i64()); let number = Number::from(-42); assert!(number.is_i64()); let number = Number::from(std::f64::consts::PI); assert!(!number.is_i64()); } // Tests for Number::is_infinite method #[test] fn test_is_infinite() { let number = Number::from(f64::INFINITY); assert!(number.is_infinite()); let number = Number::from(-f64::INFINITY); assert!(number.is_infinite()); let number = Number::from(42); assert!(!number.is_infinite()); let number = Number::from(std::f64::consts::PI); assert!(!number.is_infinite()); } // Tests for Number::is_nan method #[test] fn test_is_nan() { let number = Number::from(f64::NAN); assert!(number.is_nan()); let number = Number::from(42); assert!(!number.is_nan()); let number = Number::from(std::f64::consts::PI); assert!(!number.is_nan()); } // Tests for Number::is_u64 method #[test] fn test_is_u64() { let number = Number::from(42); assert!(number.is_u64()); let number = Number::from(-42); assert!(!number.is_u64()); let number = Number::from(std::f64::consts::PI); assert!(!number.is_u64()); } // Tests for PartialEq implementation #[test] fn test_partial_eq() { let number1 = Number::from(42); let number2 = Number::from(42); assert_eq!(number1, number2); let number1 = Number::from(-42); let number2 = Number::from(-42); assert_eq!(number1, number2); let number1 = Number::from(std::f64::consts::PI); let number2 = Number::from(std::f64::consts::PI); assert_eq!(number1, number2); let number1 = Number::from(42); let number2 = Number::from(-42); assert_ne!(number1, number2); let number1 = Number::from(42); let number2 = Number::from(std::f64::consts::PI); assert_ne!(number1, number2); } // Tests for PartialOrd implementation #[test] fn test_partial_ord() { let number1 = Number::from(42); let number2 = Number::from(42); assert_eq!( number1.partial_cmp(&number2), Some(Ordering::Equal) ); let number1 = Number::from(-42); let number2 = Number::from(42); assert_eq!(number1.partial_cmp(&number2), Some(Ordering::Less)); let number1 = Number::from(42); let number2 = Number::from(-42); assert_eq!( number1.partial_cmp(&number2), Some(Ordering::Greater) ); let number1 = Number::from(std::f64::consts::PI); let number2 = Number::from(std::f64::consts::PI); assert_eq!( number1.partial_cmp(&number2), Some(Ordering::Equal) ); let number1 = Number::from(std::f64::consts::PI); let number2 = Number::from(2.71); assert_eq!( number1.partial_cmp(&number2), Some(Ordering::Greater) ); let number1 = Number::from(f64::NAN); let number2 = Number::from(f64::NAN); assert_eq!( number1.partial_cmp(&number2), Some(Ordering::Equal) ); } // Tests for Hash implementation #[test] fn test_hash() { let mut hasher = DefaultHasher::new(); let number = Number::from(42); number.hash(&mut hasher); let hash1 = hasher.finish(); let mut hasher = DefaultHasher::new(); let number = Number::from(42); number.hash(&mut hasher); let hash2 = hasher.finish(); assert_eq!(hash1, hash2); } // Tests for serde serialization and deserialization #[test] fn test_ser_de() { let number = Number::from(42); let serialized = serde_yml::to_string(&number).unwrap(); let deserialized: Number = serde_yml::from_str(&serialized).unwrap(); assert_eq!(number, deserialized); let number = Number::from(-42); let serialized = serde_yml::to_string(&number).unwrap(); let deserialized: Number = serde_yml::from_str(&serialized).unwrap(); assert_eq!(number, deserialized); let number = Number::from(std::f64::consts::PI); let serialized = serde_yml::to_string(&number).unwrap(); let deserialized: Number = serde_yml::from_str(&serialized).unwrap(); assert_eq!(number, deserialized); } } serde_yml-0.0.12/tests/test_ser.rs000064400000000000000000001051111046102023000152260ustar 00000000000000#[cfg(test)] mod tests { use indoc::indoc; use serde::ser::{SerializeTuple, SerializeTupleStruct}; use serde::{ser::Serializer as _, Serialize}; use serde_yml::ser::SerializerConfig; use serde_yml::{ libyml::emitter::{Scalar, ScalarStyle}, Serializer, State, }; use std::{collections::BTreeMap, fmt::Write}; #[test] /// Tests the test scalar serialization. fn test_scalar_serialization() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test value", style: ScalarStyle::Plain, }; // Act serializer.emit_scalar(scalar_value).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "test value\n", "Serialized scalar value doesn't match expected output" ); } #[test] /// Tests the test sequence start serialization. fn test_sequence_start_serialization() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.emit_sequence_start().unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "", "Serialized sequence start doesn't match expected output" ); } #[test] /// Tests the test mapping start serialization. fn test_mapping_start_serialization() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.emit_mapping_start().unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "", "Serialized mapping start doesn't match expected output" ); } #[test] /// Tests the test flush mapping start. fn test_flush_mapping_start() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.emit_mapping_start().unwrap(); serializer.flush().unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "", "Flushed mapping start doesn't match expected output" ); } #[test] /// Tests the serialization of an empty map. fn test_serialize_empty_map() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let map: BTreeMap = BTreeMap::new(); // Act map.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "{}\n", "Serialized empty map doesn't match expected output" ); } #[test] /// Tests the test serialize simple map. fn test_serialize_simple_map() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let mut map = BTreeMap::new(); map.insert("key".to_string(), 42); // Act map.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "key: 42\n", "Serialized simple map doesn't match expected output" ); } #[test] /// Tests the test serialize nested map. fn test_serialize_nested_map() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let mut inner_map = BTreeMap::new(); inner_map .insert("inner_key".to_string(), "inner_value".to_string()); let mut outer_map = BTreeMap::new(); outer_map.insert("outer_key".to_string(), inner_map); // Act outer_map.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "outer_key:\n inner_key: inner_value\n", "Serialized nested map doesn't match expected output" ); } /// Tests serializing a struct with custom fields. #[derive(Serialize)] struct CustomStruct { field1: String, field2: i32, } #[test] /// Tests the test serialize custom struct. fn test_serialize_custom_struct() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let custom_struct = CustomStruct { field1: "value1".to_string(), field2: 42, }; // Act custom_struct.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "field1: value1\nfield2: 42\n", "Serialized custom struct doesn't match expected output" ); } #[test] // Test cases for taking tag with found tag state fn test_take_tag_with_found_tag_state() { // Arrange let mut serializer = Serializer::>::new(Vec::new()); serializer.state = State::FoundTag("test tag".to_owned()); // Act let tag = serializer.take_tag(); // Assert assert_eq!( tag, Some("!test tag".to_owned()), // Found tag should be prefixed with '!' "Tag extraction output doesn't match expected output" ); } #[test] // Test cases for taking tag with no state fn test_take_tag_with_no_state() { // Arrange let mut serializer = Serializer::>::new(Vec::new()); // Act let tag = serializer.take_tag(); // Assert assert_eq!( tag, None, // Since there was no specific state, tag extraction should return None "Tag extraction output doesn't match expected output" ); } #[test] // Test cases for converting into inner fn test_into_inner() { // Arrange let mut buffer = Vec::new(); let buffer_clone = buffer.clone(); let serializer = Serializer::new(&mut buffer); // Act let result = serializer.into_inner().unwrap(); // Assert assert_eq!(&*result, &buffer_clone); } #[test] // Test cases for serializing boolean values fn test_serialize_bool() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_bool(true).unwrap(); serializer.serialize_bool(false).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "true\n--- false\n", "Serialized boolean values don't match expected output" ); } #[test] /// Tests the test serialize i8. fn test_serialize_i8() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_i8(42).unwrap(); serializer.serialize_i8(-100).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- -100\n", "Serialized i8 values don't match expected output" ); } #[test] /// Tests the test serialize i16. fn test_serialize_i16() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_i16(42).unwrap(); serializer.serialize_i16(-100).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- -100\n", "Serialized i16 values don't match expected output" ); } #[test] /// Tests the test serialize i32. fn test_serialize_i32() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_i32(42).unwrap(); serializer.serialize_i32(-100).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- -100\n", "Serialized i32 values don't match expected output" ); } #[test] /// Tests the test serialize i64. fn test_serialize_i64() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_i64(42).unwrap(); serializer.serialize_i64(-100).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- -100\n", "Serialized i64 values don't match expected output" ); } #[test] /// Tests the test serialize i128. fn test_serialize_i128() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let u64_max = u64::MAX as i128; let u64_max_plus_one = u64_max + 1; let i64_min = i64::MIN as i128; let i64_min_minus_one = i64_min - 1; serializer.serialize_i128(42).unwrap(); serializer.serialize_i128(-100).unwrap(); serializer.serialize_i128(u64_max).unwrap(); serializer.serialize_i128(u64_max_plus_one).unwrap(); serializer.serialize_i128(i64_min).unwrap(); serializer.serialize_i128(i64_min_minus_one).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- -100\n--- 18446744073709551615\n--- 18446744073709551616\n--- -9223372036854775808\n--- -9223372036854775809\n", "Serialized i128 values don't match expected output" ); } #[test] /// Tests the test serialize f64. fn test_serialize_f64() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_f64(std::f64::consts::PI).unwrap(); serializer.serialize_f64(f64::INFINITY).unwrap(); serializer.serialize_f64(f64::NEG_INFINITY).unwrap(); serializer.serialize_f64(f64::NAN).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "3.141592653589793\n--- .inf\n--- -.inf\n--- .nan\n", "Serialized f64 values don't match expected output" ); } #[test] /// Tests the test serialize char. fn test_serialize_char() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act serializer.serialize_char('a').unwrap(); serializer.serialize_char('💻').unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "'a'\n--- '💻'\n", "Serialized char values don't match expected output" ); } #[test] /// Tests the test serialize bytes. fn test_serialize_bytes() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let bytes = vec![1, 2, 3, 4, 5]; let result = serializer.serialize_bytes(&bytes); // Assert assert!(result.is_err()); assert_eq!( result.unwrap_err().to_string(), "serialization and deserialization of bytes in YAML is not implemented", "Unexpected error message" ); } #[test] /// Tests the test serialize tuple. fn test_serialize_tuple() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let mut tuple_serializer = serializer.serialize_tuple(3).unwrap(); SerializeTuple::serialize_element(&mut tuple_serializer, &42) .unwrap(); SerializeTuple::serialize_element( &mut tuple_serializer, &"hello", ) .unwrap(); SerializeTuple::serialize_element(&mut tuple_serializer, &true) .unwrap(); SerializeTuple::end(tuple_serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "- 42\n- hello\n- true\n", "Serialized tuple doesn't match expected output" ); } #[test] /// Tests the test serialize tuple struct. fn test_serialize_tuple_struct() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let mut tuple_struct_serializer = serializer .serialize_tuple_struct("MyTupleStruct", 2) .unwrap(); SerializeTupleStruct::serialize_field( &mut tuple_struct_serializer, &42, ) .unwrap(); SerializeTupleStruct::serialize_field( &mut tuple_struct_serializer, &"hello", ) .unwrap(); SerializeTupleStruct::end(tuple_struct_serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "- 42\n- hello\n", "Serialized tuple struct doesn't match expected output" ); } #[test] /// Tests the test serialize option. fn test_serialize_option() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let some_value: Option = Some(42); let none_value: Option = None; // Act some_value.serialize(&mut serializer).unwrap(); none_value.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "42\n--- null\n", "Serialized Option values don't match expected output" ); } #[test] /// Tests the test serialize enum. fn test_serialize_enum() { // Arrange #[derive(Serialize)] enum MyEnum { A, B(i32), C { x: i32, y: i32 }, } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act MyEnum::A.serialize(&mut serializer).unwrap(); MyEnum::B(42).serialize(&mut serializer).unwrap(); MyEnum::C { x: 1, y: 2 }.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "A\n--- !B 42\n--- !C\nx: 1\n'y': 2\n", "Serialized enum values don't match expected output" ); } #[test] /// Test cases for serializing sequences fn test_serialize_sequence() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let sequence = vec!["42", "hello", "true"]; // Act sequence.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "- '42'\n- hello\n- 'true'\n", "Serialized sequence doesn't match expected output" ); } #[test] /// Tests the test serialize map. fn test_serialize_map() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let mut map = BTreeMap::new(); map.insert("name", "John"); map.insert("age", "30"); // Act map.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "age: '30'\nname: John\n", "Serialized map doesn't match expected output" ); } #[test] /// Tests the test serialize nested struct. fn test_serialize_nested_struct() { // Arrange #[derive(Serialize)] struct Person { name: String, age: u32, address: Address, } #[derive(Serialize)] struct Address { street: String, city: String, } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let person = Person { name: "Alice".to_string(), age: 25, address: Address { street: "123 Main St".to_string(), city: "Anytown".to_string(), }, }; person.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "name: Alice\nage: 25\naddress:\n street: '123 Main St'\n city: Anytown\n", "Serialized nested struct doesn't match expected output" ); } #[test] /// Tests the test serialize optional fields. fn test_serialize_optional_fields() { // Arrange #[derive(Serialize)] struct User { name: String, email: Option, age: Option, } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let user = User { name: "Bob".to_string(), email: Some("bob@example.com".to_string()), age: None, }; user.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "name: Bob\nemail: bob@example.com\nage: null\n", "Serialized optional fields don't match expected output" ); } #[test] /// Tests the test serialize tagged value. fn test_serialize_tagged_value() { // Arrange #[derive(Serialize)] struct TaggedValue { #[serde(rename = "!tag")] value: String, } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let tagged_value = TaggedValue { value: "example".to_string(), }; tagged_value.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "'!tag': example\n", "Serialized tagged value doesn't match expected output" ); } #[test] /// Tests the test serialize large data. fn test_serialize_large_data() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let large_sequence: Vec<_> = (0..1000).collect(); // Act large_sequence.serialize(&mut serializer).unwrap(); // Assert let mut expected_output = String::new(); // Create an empty String for i in &large_sequence { // Append to the String directly writeln!(&mut expected_output, "- {}", i).unwrap(); } assert_eq!( String::from_utf8(buffer).unwrap(), expected_output, "Serialized large data doesn't match expected output" ); } #[test] /// Tests the test serialize nested sequences. fn test_serialize_nested_sequences() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let nested_sequences = vec![ vec!["a", "b", "c"], vec!["d", "e", "f"], vec!["g", "h", "i"], ]; // Act nested_sequences.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "- - a\n - b\n - c\n- - d\n - e\n - f\n- - g\n - h\n - i\n", "Serialized nested sequences don't match expected output" ); } #[test] /// Tests the test serialize nested maps. fn test_serialize_nested_maps() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let mut nested_maps = BTreeMap::new(); let mut inner_map1 = BTreeMap::new(); inner_map1.insert("key1", "value1"); inner_map1.insert("key2", "value2"); let mut inner_map2 = BTreeMap::new(); inner_map2.insert("key3", "value3"); inner_map2.insert("key4", "value4"); nested_maps.insert("map1", inner_map1); nested_maps.insert("map2", inner_map2); // Act nested_maps.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "map1:\n key1: value1\n key2: value2\nmap2:\n key3: value3\n key4: value4\n", "Serialized nested maps don't match expected output" ); } #[test] /// Tests the test serialize mixed data types. fn test_serialize_mixed_data_types() { // Arrange #[derive(Serialize)] struct MixedData { name: String, age: u32, active: bool, scores: Vec, metadata: BTreeMap, } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let mixed_data = MixedData { name: "Alice".to_string(), age: 30, active: true, scores: vec![80, 90, 95], metadata: { let mut map = BTreeMap::new(); map.insert("key1".to_string(), "value1".to_string()); map.insert("key2".to_string(), "value2".to_string()); map }, }; mixed_data.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "name: Alice\nage: 30\nactive: true\nscores:\n- 80\n- 90\n- 95\nmetadata:\n key1: value1\n key2: value2\n", "Serialized mixed data types don't match expected output" ); } #[test] /// Tests the test serialize empty sequence and map. fn test_serialize_empty_sequence_and_map() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let empty_sequence: Vec = Vec::new(); let empty_map: BTreeMap = BTreeMap::new(); // Act empty_sequence.serialize(&mut serializer).unwrap(); empty_map.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "[]\n--- {}\n", "Serialized empty sequence and map don't match expected output" ); } #[test] /// Tests the test serialize special characters. fn test_serialize_special_characters() { // Arrange let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let special_string = "\"'\\n\t"; // Act special_string.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "\"\\\"'\\\\n\\t\"\n", "Serialized special characters don't match expected output" ); } #[test] /// Tests the test serialize custom serializer. fn test_serialize_custom_serializer() { // Arrange use serde::ser::SerializeMap; #[derive(Serialize)] struct CustomStruct { #[serde(serialize_with = "custom_serialize")] value: String, } fn custom_serialize( value: &String, serializer: S, ) -> Result where S: serde::Serializer, { let mut map = serializer.serialize_map(Some(1))?; map.serialize_entry( "custom_value", &format!("<<{}>>", value), )?; map.end() } let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); // Act let custom_struct = CustomStruct { value: "example".to_string(), }; custom_struct.serialize(&mut serializer).unwrap(); // Assert assert_eq!( String::from_utf8(buffer).unwrap(), "value:\n custom_value: <>\n", "Serialized custom serializer doesn't match expected output" ); } #[test] /// Tests the test default unit variants. fn test_default_unit_variants() { #[derive(Serialize)] enum Enum { Unit, } let mut buffer = vec![]; let mut ser = Serializer::new(&mut buffer); Enum::Unit.serialize(&mut ser).unwrap(); let output = String::from_utf8(buffer).unwrap(); let expected = indoc! {" Unit "}; assert_eq!(output, expected); } #[test] /// Tests the test tag unit variants. fn test_tag_unit_variants() { #[derive(Serialize)] enum Enum { Unit, } let mut buffer = vec![]; let mut ser = Serializer::new_with_config( &mut buffer, SerializerConfig { tag_unit_variants: true, }, ); Enum::Unit.serialize(&mut ser).unwrap(); let output = String::from_utf8(buffer).unwrap(); let expected = indoc! {" !Unit "}; assert_eq!(output, expected); } #[test] /// Tests the creation of a new Serializer with the default configuration. fn test_new() { let buffer = Vec::new(); let serializer = Serializer::new(buffer); assert!( serializer.depth == 0, "Expected depth to be 0 after initialization" ); } #[test] /// Tests the creation of a new Serializer with a custom configuration. /// /// Tests the test new with config. fn test_new_with_config() { let buffer = Vec::new(); let config = SerializerConfig::default(); let serializer = Serializer::new_with_config(buffer, config); assert!(serializer.depth == 0, "Expected depth to be 0 after initialization with custom config"); // Additional assertions can be added as needed. } #[test] /// Tests the flush function to ensure all buffered data is written. fn test_flush() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.flush().unwrap(); // Check if the buffer was properly flushed. assert!( buffer.is_empty(), "Buffer should be empty after flush" ); } #[test] /// Tests the emit_scalar function to serialize a scalar value. fn test_emit_scalar() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test value", style: ScalarStyle::Plain, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "test value\n", "Serialized scalar value doesn't match expected output" ); } #[test] /// Tests the emit_sequence_start function. This test accounts for the fact that starting a sequence may not immediately produce output. fn test_emit_sequence_start() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.emit_sequence_start().unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "item", style: ScalarStyle::Plain, }) .unwrap(); serializer.emit_sequence_end().unwrap(); assert!(!buffer.is_empty(), "Buffer should not be empty after emitting sequence start and a scalar"); } #[test] /// Tests the emit_sequence_end function. This test ensures proper sequence handling. fn test_emit_sequence_end() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.emit_sequence_start().unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "item", style: ScalarStyle::Plain, }) .unwrap(); serializer.emit_sequence_end().unwrap(); assert!(buffer.ends_with(b"item\n"), "Buffer should end with the scalar value and sequence end marker"); } #[test] /// Tests the emit_mapping_start function. Similar to sequences, starting a mapping might not produce immediate output. fn test_emit_mapping_start() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.emit_mapping_start().unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "key", style: ScalarStyle::Plain, }) .unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "value", style: ScalarStyle::Plain, }) .unwrap(); serializer.emit_mapping_end().unwrap(); assert!(!buffer.is_empty(), "Buffer should not be empty after emitting mapping start and key-value pair"); } #[test] /// Tests the emit_mapping_end function to ensure mappings are correctly finalized. fn test_emit_mapping_end() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.emit_mapping_start().unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "key", style: ScalarStyle::Plain, }) .unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "value", style: ScalarStyle::Plain, }) .unwrap(); serializer.emit_mapping_end().unwrap(); assert!( buffer.ends_with(b"value\n"), "Buffer should end with the value and mapping end marker" ); } #[test] /// Tests the value_end function with proper sequence start. fn test_value_end() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); serializer.value_start().unwrap(); serializer .emit_scalar(Scalar { tag: None, value: "scalar value", style: ScalarStyle::Plain, }) .unwrap(); serializer.value_end().unwrap(); assert!( serializer.depth == 0, "Expected depth to decrease to 0 after value end" ); } #[test] /// Tests the take_tag function to check if a tag can be taken from the state. fn test_take_tag() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let tag = serializer.take_tag(); assert!( tag.is_none(), "Expected no tag to be present initially" ); } #[test] /// Test emitting a scalar with a tag. fn test_emit_scalar_with_tag() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: Some("tag".to_string()), value: "test value", style: ScalarStyle::Plain, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "! test value\n", "Serialized scalar value with tag doesn't match expected output" ); } #[test] /// Test emitting a scalar with a single quoted style. fn test_emit_scalar_with_quoted_style() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test value", style: ScalarStyle::SingleQuoted, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "'test value'\n", "Serialized scalar value with quoted style doesn't match expected output" ); } #[test] /// Test emitting a scalar with a double quoted style. fn test_emit_scalar_with_double_quoted_style() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test value", style: ScalarStyle::DoubleQuoted, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "\"test value\"\n", "Serialized scalar value with double quoted style doesn't match expected output" ); } #[test] /// Test emitting a scalar with a literal style. /// The literal style is used for multi-line strings. fn test_emit_scalar_with_literal_style() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test\nvalue", style: ScalarStyle::Literal, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "|-\n test\n value\n", "Serialized scalar value with literal style doesn't match expected output" ); } #[test] /// Test emitting a scalar with a folded style. fn test_emit_scalar_with_folded_style() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test\nvalue", style: ScalarStyle::Folded, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), ">-\n test\n\n value\n", "Serialized scalar value with folded style doesn't match expected output" ); } #[test] /// Test emitting a scalar with a plain style. fn test_emit_scalar_with_plain_style() { let mut buffer = Vec::new(); let mut serializer = Serializer::new(&mut buffer); let scalar_value = Scalar { tag: None, value: "test value", style: ScalarStyle::Plain, }; serializer.emit_scalar(scalar_value).unwrap(); assert_eq!( String::from_utf8(buffer).unwrap(), "test value\n", "Serialized scalar value with plain style doesn't match expected output" ); } } serde_yml-0.0.12/tests/test_serde.rs000064400000000000000000000353431046102023000155500ustar 00000000000000#![allow( clippy::decimal_literal_representation, clippy::derive_partial_eq_without_eq, clippy::unreadable_literal, clippy::shadow_unrelated )] use indoc::indoc; use serde::ser::SerializeMap; use serde_derive::{Deserialize, Serialize}; use serde_yml::{Mapping, Number, Value}; use std::collections::BTreeMap; use std::fmt::Debug; use std::iter; fn test_serde(thing: &T, yaml: &str) where T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug, { let serialized = serde_yml::to_string(&thing).unwrap(); assert_eq!(yaml, serialized); let value = serde_yml::to_value(thing).unwrap(); let serialized = serde_yml::to_string(&value).unwrap(); assert_eq!(yaml, serialized); let deserialized: T = serde_yml::from_str(yaml).unwrap(); assert_eq!(*thing, deserialized); let value: Value = serde_yml::from_str(yaml).unwrap(); let deserialized = T::deserialize(&value).unwrap(); assert_eq!(*thing, deserialized); let deserialized: T = serde_yml::from_value(value).unwrap(); assert_eq!(*thing, deserialized); serde_yml::from_str::(yaml).unwrap(); } #[test] fn test_default() { assert_eq!(Value::default(), Value::Null); } #[test] fn test_int() { let thing = 256; let yaml = indoc! {" 256 "}; test_serde(&thing, yaml); } #[test] fn test_int_max_u64() { let thing = u64::MAX; let yaml = indoc! {" 18446744073709551615 "}; test_serde(&thing, yaml); } #[test] fn test_int_min_i64() { let thing = i64::MIN; let yaml = indoc! {" -9223372036854775808 "}; test_serde(&thing, yaml); } #[test] fn test_int_max_i64() { let thing = i64::MAX; let yaml = indoc! {" 9223372036854775807 "}; test_serde(&thing, yaml); } #[test] fn test_i128_small() { let thing: i128 = -256; let yaml = indoc! {" -256 "}; test_serde(&thing, yaml); } #[test] fn test_u128_small() { let thing: u128 = 256; let yaml = indoc! {" 256 "}; test_serde(&thing, yaml); } #[test] fn test_float() { let thing = 25.6; let yaml = indoc! {" 25.6 "}; test_serde(&thing, yaml); let thing = 25.; let yaml = indoc! {" 25.0 "}; test_serde(&thing, yaml); let thing = f64::INFINITY; let yaml = indoc! {" .inf "}; test_serde(&thing, yaml); let thing = f64::NEG_INFINITY; let yaml = indoc! {" -.inf "}; test_serde(&thing, yaml); let float: f64 = serde_yml::from_str(indoc! {" .nan "}) .unwrap(); assert!(float.is_nan()); } #[test] fn test_float32() { let thing: f32 = 25.5; let yaml = indoc! {" 25.5 "}; test_serde(&thing, yaml); let thing = f32::INFINITY; let yaml = indoc! {" .inf "}; test_serde(&thing, yaml); let thing = f32::NEG_INFINITY; let yaml = indoc! {" -.inf "}; test_serde(&thing, yaml); let single_float: f32 = serde_yml::from_str(indoc! {" .nan "}) .unwrap(); assert!(single_float.is_nan()); } #[test] fn test_char() { let ch = '.'; let yaml = indoc! {" '.' "}; assert_eq!(yaml, serde_yml::to_string(&ch).unwrap()); let ch = '#'; let yaml = indoc! {" '#' "}; assert_eq!(yaml, serde_yml::to_string(&ch).unwrap()); let ch = '-'; let yaml = indoc! {" '-' "}; assert_eq!(yaml, serde_yml::to_string(&ch).unwrap()); } #[test] fn test_vec() { let thing = vec![1, 2, 3]; let yaml = indoc! {" - 1 - 2 - 3 "}; test_serde(&thing, yaml); } #[test] fn test_map() { let mut thing = BTreeMap::new(); thing.insert("x".to_owned(), 1); thing.insert("y".to_owned(), 2); let yaml = indoc! {" x: 1 'y': 2 "}; test_serde(&thing, yaml); } #[test] fn test_map_key_value() { struct Map; impl serde::Serialize for Map { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { // Test maps which do not serialize using serialize_entry. let mut map = serializer.serialize_map(Some(1))?; map.serialize_key("k")?; map.serialize_value("v")?; map.end() } } let yaml = indoc! {" k: v "}; assert_eq!(yaml, serde_yml::to_string(&Map).unwrap()); } #[test] fn test_basic_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Basic { x: isize, y: String, z: bool, } let thing = Basic { x: -4, y: "hi\tquoted".to_owned(), z: true, }; let yaml = indoc! {r#" x: -4 'y': "hi\tquoted" z: true "#}; test_serde(&thing, yaml); } #[test] fn test_string_escapes() { let yaml = indoc! {" ascii "}; test_serde(&"ascii".to_owned(), yaml); let yaml = indoc! {r#" "\0\a\b\t\n\v\f\r\e\"\\\N\L\P" "#}; test_serde( &"\0\u{7}\u{8}\t\n\u{b}\u{c}\r\u{1b}\"\\\u{85}\u{2028}\u{2029}" .to_owned(), yaml, ); let yaml = indoc! {r#" "\x1F\uFEFF" "#}; test_serde(&"\u{1f}\u{feff}".to_owned(), yaml); let yaml = indoc! {" 🎉 "}; test_serde(&"\u{1f389}".to_owned(), yaml); } #[test] fn test_boolish_serialization() { // See https://yaml.org/type/bool.html let thing = vec![ Value::String("y".to_owned()), Value::String("Y".to_owned()), Value::String("yes".to_owned()), Value::String("Yes".to_owned()), Value::String("YES".to_owned()), Value::String("n".to_owned()), Value::String("N".to_owned()), Value::String("no".to_owned()), Value::String("No".to_owned()), Value::String("NO".to_owned()), Value::String("true".to_owned()), Value::String("True".to_owned()), Value::String("TRUE".to_owned()), Value::String("false".to_owned()), Value::String("False".to_owned()), Value::String("FALSE".to_owned()), Value::String("on".to_owned()), Value::String("On".to_owned()), Value::String("ON".to_owned()), Value::String("off".to_owned()), Value::String("Off".to_owned()), Value::String("OFF".to_owned()), Value::Bool(true), Value::Bool(false), ]; let yaml = indoc! {" - 'y' - 'Y' - 'yes' - 'Yes' - 'YES' - 'n' - 'N' - 'no' - 'No' - 'NO' - 'true' - 'True' - 'TRUE' - 'false' - 'False' - 'FALSE' - 'on' - 'On' - 'ON' - 'off' - 'Off' - 'OFF' - true - false "}; test_serde(&thing, yaml); } #[test] fn test_multiline_string() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Struct { trailing_newline: String, no_trailing_newline: String, } let thing = Struct { trailing_newline: "aaa\nbbb\n".to_owned(), no_trailing_newline: "aaa\nbbb".to_owned(), }; let yaml = indoc! {" trailing_newline: | aaa bbb no_trailing_newline: |- aaa bbb "}; test_serde(&thing, yaml); } #[test] fn test_strings_needing_quote() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Struct { boolean: String, integer: String, void: String, leading_zeros: String, } let thing = Struct { boolean: "true".to_owned(), integer: "1".to_owned(), void: "null".to_owned(), leading_zeros: "007".to_owned(), }; let yaml = indoc! {" boolean: 'true' integer: '1' void: 'null' leading_zeros: '007' "}; test_serde(&thing, yaml); } #[test] fn test_moar_strings_needing_quote() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Struct { s: String, } for s in &[ // Short hex values. "0x0", "0x1", // Long hex values that don't fit in a u64 need to be quoted. "0xffaed20B7B67e498A3bEEf97386ec1849EFeE6Ac", // "empty" strings. "", " ", // The norway problem https://hitchdev.com/strictyaml/why/implicit-typing-removed/ "NO", "no", "No", "Yes", "YES", "yes", "True", "TRUE", "true", "False", "FALSE", "false", "y", "Y", "n", "N", "on", "On", "ON", "off", "Off", "OFF", "0", "1", "null", "Null", "NULL", "nil", "Nil", "NIL", // https://hitchdev.com/strictyaml/why/implicit-typing-removed/#string-or-float "9.3", // https://github.com/dtolnay/serde_yml/pull/398#discussion_r1432944356 "2E234567", // https://yaml.org/spec/1.2.2/#1022-tag-resolution "0o7", "0x3A", "+12.3", "0.", "-0.0", "12e3", "-2E+05", "0", "-0", "3", "-19", ] { let thing = Struct { s: s.to_string() }; let yaml = format!("s: '{}'\n", s); test_serde(&thing, &yaml); } } #[test] fn test_nested_vec() { let thing = vec![vec![1, 2, 3], vec![4, 5, 6]]; let yaml = indoc! {" - - 1 - 2 - 3 - - 4 - 5 - 6 "}; test_serde(&thing, yaml); } #[test] fn test_nested_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Outer { inner: Inner, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Inner { v: u16, } let thing = Outer { inner: Inner { v: 512 }, }; let yaml = indoc! {" inner: v: 512 "}; test_serde(&thing, yaml); } #[test] fn test_nested_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Outer { Inner(Inner), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Inner { Unit, } let thing = Outer::Inner(Inner::Unit); let yaml = indoc! {" !Inner Unit "}; test_serde(&thing, yaml); } #[test] fn test_option() { let thing = vec![Some(1), None, Some(3)]; let yaml = indoc! {" - 1 - null - 3 "}; test_serde(&thing, yaml); } #[test] fn test_unit() { let thing = vec![(), ()]; let yaml = indoc! {" - null - null "}; test_serde(&thing, yaml); } #[test] fn test_unit_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo; let thing = Foo; let yaml = indoc! {" null "}; test_serde(&thing, yaml); } #[test] fn test_unit_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { First, Second, } let thing = Variant::First; let yaml = indoc! {" First "}; test_serde(&thing, yaml); } #[test] fn test_newtype_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct OriginalType { v: u16, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NewType(OriginalType); let thing = NewType(OriginalType { v: 1 }); let yaml = indoc! {" v: 1 "}; test_serde(&thing, yaml); } #[test] fn test_newtype_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Size(usize), } let thing = Variant::Size(127); let yaml = indoc! {" !Size 127 "}; test_serde(&thing, yaml); } #[test] fn test_tuple_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Rgb(u8, u8, u8), } let thing = Variant::Rgb(32, 64, 96); let yaml = indoc! {" !Rgb - 32 - 64 - 96 "}; test_serde(&thing, yaml); } #[test] fn test_struct_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Color { r: u8, g: u8, b: u8 }, } let thing = Variant::Color { r: 32, g: 64, b: 96, }; let yaml = indoc! {" !Color r: 32 g: 64 b: 96 "}; test_serde(&thing, yaml); } #[test] fn test_tagged_map_value() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Bindings { profile: Profile, } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Profile { ClassValidator { class_name: String }, } let thing = Bindings { profile: Profile::ClassValidator { class_name: "ApplicationConfig".to_owned(), }, }; let yaml = indoc! {" profile: !ClassValidator class_name: ApplicationConfig "}; test_serde(&thing, yaml); } #[test] fn test_value() { #[derive(Serialize, Deserialize, PartialEq, Debug)] pub(crate) struct GenericInstructions { #[serde(rename = "type")] pub(crate) typ: String, pub(crate) config: Value, } let thing = GenericInstructions { typ: "primary".to_string(), config: Value::Sequence(vec![ Value::Null, Value::Bool(true), Value::Number(Number::from(65535)), Value::Number(Number::from(0.54321)), Value::String("s".into()), Value::Mapping(Mapping::new()), ]), }; let yaml = indoc! {" type: primary config: - null - true - 65535 - 0.54321 - s - {} "}; test_serde(&thing, yaml); } #[test] fn test_mapping() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Data { pub(crate) substructure: Mapping, } let mut thing = Data { substructure: Mapping::new(), }; thing.substructure.insert( Value::String("a".to_owned()), Value::String("foo".to_owned()), ); thing.substructure.insert( Value::String("b".to_owned()), Value::String("bar".to_owned()), ); let yaml = indoc! {" substructure: a: foo b: bar "}; test_serde(&thing, yaml); } #[test] fn test_long_string() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Data { pub(crate) string: String, } let thing = Data { string: iter::repeat(["word", " "]) .flatten() .take(69) .collect(), }; let yaml = indoc! {" string: word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word "}; test_serde(&thing, yaml); } serde_yml-0.0.12/tests/test_tagged.rs000064400000000000000000000021671046102023000156770ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::{ value::{tagged::nobang, Tag, TaggedValue}, Value, }; /// Test for creating a new Tag. #[test] fn test_tag_new() { let tag = Tag::new("foo"); assert_eq!(tag.string, "foo"); } /// Test for converting bytes into a Tag. #[test] fn test_try_from_tag() { let tag = Tag::try_from(&b"foo"[..]).unwrap(); assert_eq!(tag.string, "foo"); } /// Test for copying a TaggedValue. #[test] fn test_tagged_value_copy() { let tag = Tag::new("foo"); let value = Value::String("bar".to_owned()); let tagged_value = TaggedValue { tag, value }; let copied = tagged_value.copy(); assert_eq!(tagged_value, copied); } /// Test for removing '!' from a string. #[test] fn test_nobang_with_bang() { let nobanged = nobang("!foo"); assert_eq!(nobanged, "foo"); } /// Test for removing '!' from a string without '!'. #[test] fn test_nobang_without_bang() { let nobanged = nobang("foo"); assert_eq!(nobanged, "foo"); } } serde_yml-0.0.12/tests/test_value.rs000064400000000000000000000073541046102023000155630ustar 00000000000000#![allow( clippy::derive_partial_eq_without_eq, clippy::eq_op, clippy::uninlined_format_args )] use indoc::indoc; use serde::{de::IntoDeserializer, Deserialize}; use serde_derive::Serialize; use serde_yml::{Number, Value}; #[test] fn test_nan() { let pos_nan = serde_yml::from_str::(".nan").unwrap(); assert!(pos_nan.is_f64()); assert_eq!(pos_nan, pos_nan); let neg_fake_nan = serde_yml::from_str::("-.nan").unwrap(); assert!(neg_fake_nan.is_string()); let significand_mask = 0xF_FFFF_FFFF_FFFF; let bits = (f64::NAN.copysign(1.0).to_bits() ^ significand_mask) | 1; let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits))); assert_eq!(pos_nan, different_pos_nan); } #[test] fn test_digits() { let num_string = serde_yml::from_str::("01").unwrap(); assert!(num_string.is_string()); } #[test] fn test_into_deserializer() { #[derive(Debug, Deserialize, PartialEq)] struct Test { first: String, second: u32, } let value = serde_yml::from_str::("xyz").unwrap(); let s = String::deserialize(value.into_deserializer()).unwrap(); assert_eq!(s, "xyz"); let value = serde_yml::from_str::("- first\n- second\n- third") .unwrap(); let arr = Vec::::deserialize(value.into_deserializer()).unwrap(); assert_eq!(arr, &["first", "second", "third"]); let value = serde_yml::from_str::("first: abc\nsecond: 99").unwrap(); let test = Test::deserialize(value.into_deserializer()).unwrap(); assert_eq!( test, Test { first: "abc".to_string(), second: 99 } ); } #[test] fn test_merge() { // From https://yaml.org/type/merge.html. let yaml = indoc! {" --- - &CENTER { x: 1, 'y': 2 } - &LEFT { x: 0, 'y': 2 } - &BIG { r: 10 } - &SMALL { r: 1 } # All the following maps are equal: - # Explicit keys x: 1 'y': 2 r: 10 label: center/big - # Merge one map << : *CENTER r: 10 label: center/big - # Merge multiple maps << : [ *CENTER, *BIG ] label: center/big - # Override << : [ *BIG, *LEFT, *SMALL ] x: 1 label: center/big "}; let mut value: Value = serde_yml::from_str(yaml).unwrap(); value.apply_merge().unwrap(); for i in 5..=7 { assert_eq!(value[4], value[i]); } } #[test] fn test_debug() { let yaml = indoc! {" 'Null': ~ Bool: true Number: 1 String: ... Sequence: - true EmptySequence: [] EmptyMapping: {} Tagged: !tag true "}; let value: Value = serde_yml::from_str(yaml).unwrap(); let debug = format!("{:#?}", value); let expected = indoc! {r#" Mapping { "Null": Null, "Bool": Bool(true), "Number": Number(1), "String": String("..."), "Sequence": Sequence [ Bool(true), ], "EmptySequence": Sequence [], "EmptyMapping": Mapping {}, "Tagged": TaggedValue { tag: !tag, value: Bool(true), }, }"# }; assert_eq!(debug, expected); } #[test] fn test_tagged() { #[derive(Serialize)] enum Enum { Variant(usize), } let value = serde_yml::to_value(Enum::Variant(0)).unwrap(); let deserialized: Value = serde_yml::from_value(value.clone()).unwrap(); assert_eq!(value, deserialized); let serialized = serde_yml::to_value(&value).unwrap(); assert_eq!(value, serialized); } serde_yml-0.0.12/tests/test_with.rs000064400000000000000000000436511046102023000154220ustar 00000000000000#[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use serde_yml::with::*; // Define the enum MyEnum #[derive(Serialize, Deserialize, PartialEq, Debug)] enum MyEnum { Unit, Newtype(usize), Tuple(usize, usize), Struct { value: usize }, } // Test serialization and deserialization using nested_singleton_map #[test] fn test_nested_singleton_map() { // Define enum InnerEnum and OuterEnum for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Variant1, Variant2(String), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OuterEnum { Variant1(InnerEnum), Variant2 { inner: InnerEnum }, } // Define struct TestStruct for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TestStruct { #[serde(with = "nested_singleton_map")] field: OuterEnum, } // Test serialization and deserialization for OuterEnum::Variant1(InnerEnum::Variant1) let test_struct = TestStruct { field: OuterEnum::Variant1(InnerEnum::Variant1), }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!(yaml, "field:\n Variant1: Variant1\n"); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); // Test serialization and deserialization for OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()) } let test_struct = TestStruct { field: OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()), }, }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!( yaml, "field:\n Variant2:\n inner:\n Variant2: value\n" ); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); } // Test serialization and deserialization using singleton_map_optional #[test] fn test_singleton_map_optional() { // Define struct TestStruct for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TestStruct { #[serde(with = "singleton_map_optional")] field: Option, } // Test serialization and deserialization for Some(MyEnum::Unit) and None let test_struct = TestStruct { field: Some(MyEnum::Unit), }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!(yaml, "field: Unit\n"); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); let test_struct = TestStruct { field: None }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!(yaml, "field: null\n"); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); } // Test serialization and deserialization using singleton_map_with #[test] fn test_singleton_map_with() { // Define struct TestStruct for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TestStruct { #[serde(with = "singleton_map_with")] field: MyEnum, } // Test serialization and deserialization for MyEnum::Unit let test_struct = TestStruct { field: MyEnum::Unit, }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!(yaml, "field: Unit\n"); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); } // Test nested_singleton_map serialization #[test] fn test_nested_singleton_map_serialization() { // Define enum InnerEnum and OuterEnum for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Variant1, Variant2(String), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OuterEnum { Variant1(InnerEnum), Variant2 { inner: InnerEnum }, } // Test serialization for OuterEnum::Variant1(InnerEnum::Variant1) let value = OuterEnum::Variant1(InnerEnum::Variant1); let mut serializer = serde_yml::Serializer::new(Vec::new()); nested_singleton_map::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Variant1: Variant1\n"); // Test serialization for OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()) } let value = OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()), }; let mut serializer = serde_yml::Serializer::new(Vec::new()); nested_singleton_map::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Variant2:\n inner:\n Variant2: value\n"); } // Test nested_singleton_map deserialization #[test] fn test_nested_singleton_map_deserialization() { // Define enum InnerEnum and OuterEnum for deserialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum InnerEnum { Variant1, Variant2(String), } #[derive(Serialize, Deserialize, PartialEq, Debug)] enum OuterEnum { Variant1(InnerEnum), Variant2 { inner: InnerEnum }, } // Test deserialization for OuterEnum::Variant1(InnerEnum::Variant1) let yaml = "Variant1: Variant1\n"; let deserialized: OuterEnum = nested_singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!( deserialized, OuterEnum::Variant1(InnerEnum::Variant1) ); // Test deserialization for OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()) } let yaml = "Variant2:\n inner:\n Variant2: value\n"; let deserialized: OuterEnum = nested_singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!( deserialized, OuterEnum::Variant2 { inner: InnerEnum::Variant2("value".to_string()) } ); } // Test serialization and deserialization using singleton_map_recursive #[test] fn test_singleton_map_recursive() { // Define enum NestedEnum and struct TestStruct for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant(MyEnum), } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TestStruct { #[serde(with = "singleton_map_recursive")] field: NestedEnum, } // Test serialization and deserialization for NestedEnum::Variant(MyEnum::Unit) let test_struct = TestStruct { field: NestedEnum::Variant(MyEnum::Unit), }; let yaml = serde_yml::to_string(&test_struct).unwrap(); assert_eq!(yaml, "field:\n Variant: Unit\n"); let deserialized: TestStruct = serde_yml::from_str(&yaml).unwrap(); assert_eq!(test_struct, deserialized); } // Test top-level singleton_map_recursive serialization and deserialization #[test] fn test_singleton_map_recursive_top_level() { // Test serialization and deserialization for MyEnum::Unit let value = MyEnum::Unit; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_recursive::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Unit\n"); let deserialized: MyEnum = singleton_map_recursive::deserialize( serde_yml::Deserializer::from_str(&yaml), ) .unwrap(); assert_eq!(value, deserialized); } // Test singleton_map serialization #[test] fn test_singleton_map_serialization() { // Test serialization for each variant of MyEnum let value = MyEnum::Unit; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Unit\n"); let value = MyEnum::Newtype(42); let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Newtype: 42\n"); let value = MyEnum::Tuple(1, 2); let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Tuple:\n- 1\n- 2\n"); let value = MyEnum::Struct { value: 42 }; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Struct:\n value: 42\n"); } // Test singleton_map deserialization #[test] fn test_singleton_map_deserialization() { // Test deserialization for each variant of MyEnum let yaml = "Unit\n"; let deserialized: MyEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Unit); let yaml = "Newtype: 42\n"; let deserialized: MyEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Newtype(42)); let yaml = "Tuple:\n- 1\n- 2\n"; let deserialized: MyEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Tuple(1, 2)); let yaml = "Struct:\n value: 42\n"; let deserialized: MyEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Struct { value: 42 }); } // Test singleton_map_optional serialization #[test] fn test_singleton_map_optional_serialization() { // Test serialization for Some(MyEnum::Unit) and None let value = Some(MyEnum::Unit); let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_optional::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Unit\n"); let value: Option = None; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_optional::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "null\n"); } // Test singleton_map_optional deserialization #[test] fn test_singleton_map_optional_deserialization() { // Test deserialization for Some(MyEnum::Unit) and None let yaml = "Unit\n"; let deserialized: Option = singleton_map_optional::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, Some(MyEnum::Unit)); let yaml = "null\n"; let deserialized: Option = singleton_map_optional::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, None); } // Test singleton_map_with serialization #[test] fn test_singleton_map_with_serialization() { // Test serialization for MyEnum::Unit let value = MyEnum::Unit; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_with::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Unit\n"); } // Test singleton_map_with deserialization #[test] fn test_singleton_map_with_deserialization() { // Test deserialization for MyEnum::Unit let yaml = "Unit\n"; let deserialized: MyEnum = singleton_map_with::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Unit); } // Test singleton_map_recursive serialization #[test] fn test_singleton_map_recursive_serialization() { // Define enum NestedEnum for serialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant(MyEnum), } // Test serialization for NestedEnum::Variant(MyEnum::Unit) let value = NestedEnum::Variant(MyEnum::Unit); let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_recursive::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Variant: Unit\n"); } // Test singleton_map_recursive deserialization #[test] fn test_singleton_map_recursive_deserialization() { // Define enum NestedEnum for deserialization #[derive(Serialize, Deserialize, PartialEq, Debug)] enum NestedEnum { Variant(MyEnum), } // Test deserialization for NestedEnum::Variant(MyEnum::Unit) let yaml = "Variant: Unit\n"; let deserialized: NestedEnum = singleton_map_recursive::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, NestedEnum::Variant(MyEnum::Unit)); } // Test top-level singleton_map_recursive serialization #[test] fn test_singleton_map_recursive_top_level_serialization() { // Test serialization for MyEnum::Unit let value = MyEnum::Unit; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map_recursive::serialize(&value, &mut serializer) .unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Unit\n"); } // Test top-level singleton_map_recursive deserialization #[test] fn test_singleton_map_recursive_top_level_deserialization() { // Test deserialization for MyEnum::Unit let yaml = "Unit\n"; let deserialized: MyEnum = singleton_map_recursive::deserialize( serde_yml::Deserializer::from_str(yaml), ) .unwrap(); assert_eq!(deserialized, MyEnum::Unit); } // Tests for error handling #[test] fn test_singleton_map_deserialization_error() { // Test deserialization error for invalid YAML input let yaml = "InvalidYAML"; let result: Result = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ); assert!(result.is_err()); } #[test] fn test_singleton_map_missing_field_error() { // Test deserialization error for missing field let yaml = "MissingField: 42"; let result: Result = singleton_map::deserialize( serde_yml::Deserializer::from_str(yaml), ); assert!(result.is_err()); } // Tests for edge cases #[test] fn test_empty_enum() { // Define an enum with a single variant #[derive(Serialize, Deserialize, PartialEq, Debug)] enum SingleVariantEnum { Variant, } // Test serialization and deserialization of the single-variant enum let value = SingleVariantEnum::Variant; let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Variant\n"); let deserialized: SingleVariantEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(&yaml), ) .unwrap(); assert_eq!(value, deserialized); } #[test] fn test_generic_enum() { // Define an enum with generic type parameters #[derive(Serialize, Deserialize, PartialEq, Debug)] enum GenericEnum { Variant(T), } // Test serialization and deserialization of the generic enum let value = GenericEnum::Variant(42); let mut serializer = serde_yml::Serializer::new(Vec::new()); singleton_map::serialize(&value, &mut serializer).unwrap(); let yaml = String::from_utf8(serializer.into_inner().unwrap()) .unwrap(); assert_eq!(yaml, "Variant: 42\n"); let deserialized: GenericEnum = singleton_map::deserialize( serde_yml::Deserializer::from_str(&yaml), ) .unwrap(); assert_eq!(value, deserialized); } } serde_yml-0.0.12/tests/value/mod.rs000064400000000000000000000011561046102023000152750ustar 00000000000000/// 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; /// The `test_tag` module contains tests for the `Tag` trait implementations. pub mod test_tag; serde_yml-0.0.12/tests/value/test_de.rs000064400000000000000000000402031046102023000161410ustar 00000000000000#[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)); } } serde_yml-0.0.12/tests/value/test_debug.rs000064400000000000000000000032151046102023000166410ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::mapping::Mapping; use serde_yml::value::{Number, Value}; #[test] fn test_debug_value_null() { let value = Value::Null; assert_eq!(format!("{:?}", value), "Null"); } #[test] fn test_debug_value_bool() { let value = Value::Bool(true); assert_eq!(format!("{:?}", value), "Bool(true)"); } #[test] fn test_debug_value_number() { let value = Value::Number(Number::from(42)); assert_eq!(format!("{:?}", value), "Number(42)"); } #[test] fn test_debug_value_string() { let value = Value::String("Hello, world!".to_string()); assert_eq!(format!("{:?}", value), "String(\"Hello, world!\")"); } #[test] fn test_debug_value_sequence() { let value = Value::Sequence(vec![Value::Null, Value::Bool(true)]); assert_eq!( format!("{:?}", value), "Sequence [Null, Bool(true)]" ); } #[test] fn test_debug_value_mapping() { let mut mapping = Mapping::new(); mapping.insert( Value::String("name".to_string()), Value::String("John".to_string()), ); mapping.insert( Value::String("age".to_string()), Value::Number(30.into()), ); let value = Value::Mapping(mapping); assert_eq!( format!("{:?}", value), "Mapping {\"name\": String(\"John\"), \"age\": Number(30)}" ); } #[test] fn test_debug_number() { let number = Number::from(42); assert_eq!(format!("{:?}", number), "Number(42)"); } } serde_yml-0.0.12/tests/value/test_from.rs000064400000000000000000000210011046102023000165070ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::value::{Mapping, Value}; use std::borrow::Cow; // Conversion tests for non-numeric types #[test] fn test_from_bool() { // Verify conversion from bool to Value // Given a bool value, let b = false; // When converting it to Value, let x: Value = b.into(); // Then it should be converted correctly. assert_eq!(x, Value::Bool(false)); } #[test] fn test_from_string() { // Verify conversion from String to Value // Given a String, let s: String = "lorem".to_string(); // When converting it to Value, let x: Value = s.into(); // Then it should be converted correctly. assert_eq!(x, Value::String("lorem".to_string())); } #[test] fn test_from_str() { // Verify conversion from &str to Value // Given a string slice, let s: &str = "lorem"; // When converting it to Value, let x: Value = s.into(); // Then it should be converted correctly. assert_eq!(x, Value::String("lorem".to_string())); } #[test] fn test_from_cow_borrowed() { // Verify conversion from Cow (borrowed) to Value // Given a borrowed Cow, let s: Cow<'_, str> = Cow::Borrowed("lorem"); // When converting it to Value, let x: Value = s.into(); // Then it should be converted correctly. assert_eq!(x, Value::String("lorem".to_string())); } #[test] fn test_from_cow_owned() { // Verify conversion from Cow (owned) to Value // Given an owned Cow, let s: Cow<'_, str> = Cow::Owned("lorem".to_string()); // When converting it to Value, let x: Value = s.into(); // Then it should be converted correctly. assert_eq!(x, Value::String("lorem".to_string())); } #[test] fn test_from_mapping() { // Verify conversion from Mapping to Value // Given a Mapping, let mut m = Mapping::new(); m.insert("Lorem".into(), "ipsum".into()); // When converting it to Value, let x: Value = m.into(); // Then it should be converted correctly. assert_eq!( x, Value::Mapping(Mapping::from_iter(vec![( "Lorem".into(), "ipsum".into() )])) ); } #[test] fn test_from_vec() { // Verify conversion from Vec to Value // Given a Vec, let v = vec!["lorem", "ipsum", "dolor"]; // When converting it to Value, let x: Value = v.into(); // Then it should be converted correctly. assert_eq!( x, Value::Sequence(vec![ "lorem".into(), "ipsum".into(), "dolor".into() ]) ); } #[test] fn test_from_slice() { // Verify conversion from slice to Value // Given a slice, let v: &[&str] = &["lorem", "ipsum", "dolor"]; // When converting it to Value, let x: Value = v.into(); // Then it should be converted correctly. assert_eq!( x, Value::Sequence(vec![ "lorem".into(), "ipsum".into(), "dolor".into() ]) ); } #[test] fn test_from_iterator() { // Verify conversion from iterator to Value // Given an iterator that repeats a value, let v = std::iter::repeat(42).take(5); // When collecting it into Value, let x: Value = v.collect(); // Then it should be converted correctly. assert_eq!( x, Value::Sequence(vec![ 42.into(), 42.into(), 42.into(), 42.into(), 42.into() ]) ); // Given a Vec, let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; // When converting it to Value, let x: Value = v.into_iter().collect(); // Then it should be converted correctly. assert_eq!( x, Value::Sequence(vec![ "lorem".into(), "ipsum".into(), "dolor".into() ]) ); // Given values to collect, let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); // Then they should be converted correctly. assert_eq!( x, Value::Sequence(vec![ "lorem".into(), "ipsum".into(), "dolor".into() ]) ); } // Conversion tests for numeric types #[test] fn test_from_number_i8() { // Verify conversion from i8 to Value // Given an i8 value, let n: i8 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_i16() { // Verify conversion from i16 to Value // Given an i16 value, let n: i16 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_i32() { // Verify conversion from i32 to Value // Given an i32 value, let n: i32 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_i64() { // Verify conversion from i64 to Value // Given an i64 value, let n: i64 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_isize() { // Verify conversion from isize to Value // Given an isize value, let n: isize = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_u8() { // Verify conversion from u8 to Value // Given a u8 value, let n: u8 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_u16() { // Verify conversion from u16 to Value // Given a u16 value, let n: u16 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_u32() { // Verify conversion from u32 to Value // Given a u32 value, let n: u32 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_u64() { // Verify conversion from u64 to Value // Given a u64 value, let n: u64 = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_usize() { // Verify conversion from usize to Value // Given a usize value, let n: usize = 42; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.into())); } #[test] fn test_from_number_f32() { // Verify conversion from f32 to Value // Given an f32 value, let n: f32 = 42.5; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.5.into())); } #[test] fn test_from_number_f64() { // Verify conversion from f64 to Value // Given an f64 value, let n: f64 = 42.5; // When converting it to Value, let x: Value = n.into(); // Then it should be converted correctly. assert_eq!(x, Value::Number(42.5.into())); } } serde_yml-0.0.12/tests/value/test_index.rs000064400000000000000000000602761046102023000166740ustar 00000000000000#[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 }) ); } } serde_yml-0.0.12/tests/value/test_partial_eq.rs000064400000000000000000000075051046102023000177020ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::Value; // Tests for equality comparison with owned string #[test] fn test_eq_string() { assert_eq!(Value::String("lorem".into()), *"lorem"); } // Tests for equality comparison with string literal #[test] fn test_eq_str() { assert_eq!(Value::String("lorem".into()), "lorem"); } // Tests for equality comparison with owned string #[test] fn test_eq_string_owned() { assert_eq!(Value::String("lorem".into()), "lorem".to_string()); } // Tests for equality comparison with boolean #[test] fn test_eq_bool() { assert_eq!(Value::Bool(true), true); } // Tests for equality comparison with i8 #[test] fn test_eq_i8() { assert_eq!(Value::Number(10.into()), 10i8); } // Tests for equality comparison with i16 #[test] fn test_eq_i16() { assert_eq!(Value::Number(10.into()), 10i16); } // Tests for equality comparison with i32 #[test] fn test_eq_i32() { assert_eq!(Value::Number(10.into()), 10i32); } // Tests for equality comparison with i64 #[test] fn test_eq_i64() { assert_eq!(Value::Number(10.into()), 10i64); } // Tests for equality comparison with isize #[test] fn test_eq_isize() { assert_eq!(Value::Number(10.into()), 10isize); } // Tests for equality comparison with u8 #[test] fn test_eq_u8() { assert_eq!(Value::Number(10.into()), 10u8); } // Tests for equality comparison with u16 #[test] fn test_eq_u16() { assert_eq!(Value::Number(10.into()), 10u16); } // Tests for equality comparison with u32 #[test] fn test_eq_u32() { assert_eq!(Value::Number(10.into()), 10u32); } // Tests for equality comparison with u64 #[test] fn test_eq_u64() { assert_eq!(Value::Number(10.into()), 10u64); } // Tests for equality comparison with usize #[test] fn test_eq_usize() { assert_eq!(Value::Number(10.into()), 10usize); } // Tests for equality comparison with f32 #[test] fn test_eq_f32() { assert_eq!(Value::Number(10.0.into()), 10.0f32); } // Tests for equality comparison with f64 #[test] fn test_eq_f64() { assert_eq!(Value::Number(10.0.into()), 10.0f64); } // Tests for inequality comparison with owned string #[test] fn test_ne_string() { assert_ne!(Value::String("lorem".into()), *"ipsum"); } // Tests for inequality comparison with boolean #[test] fn test_ne_bool() { assert_ne!(Value::Bool(true), false); } // Tests for inequality comparison with number #[test] fn test_ne_number() { assert_ne!(Value::Number(10.into()), 20i32); } // Tests for inequality comparison with incompatible types #[test] fn test_ne_incompatible_types() { assert_ne!(Value::String("lorem".into()), true); assert_ne!(Value::Bool(true), 10i32); assert_ne!(Value::Number(10.into()), "10"); } // Tests for equality comparison with reference #[test] fn test_eq_ref() { let v = Value::String("lorem".into()); assert_eq!(&v, "lorem"); } // Tests for equality comparison with mutable reference #[test] fn test_eq_mut_ref() { let mut v = Value::Number(10.into()); assert_eq!(&mut v, 10i32); } // Tests for equality comparison with minimum and maximum values #[test] fn test_eq_min_max() { assert_eq!(Value::Number(i64::MIN.into()), i64::MIN); assert_eq!(Value::Number(i64::MAX.into()), i64::MAX); assert_eq!(Value::Number(u64::MAX.into()), u64::MAX); assert_eq!(Value::Number(f64::MIN.into()), f64::MIN); assert_eq!(Value::Number(f64::MAX.into()), f64::MAX); } } serde_yml-0.0.12/tests/value/test_tag.rs000064400000000000000000000144031046102023000163270ustar 00000000000000#[cfg(test)] mod tests { use serde_yml::libyml::tag::{Tag, TagFormatError}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; /// Test the `Tag::new` function to ensure it correctly creates a `Tag` from a string. #[test] fn test_tag_new() { let tag = Tag::new("tag:yaml.org,2002:test"); assert_eq!(&*tag, b"tag:yaml.org,2002:test"); } /// Test the `Tag::starts_with` function to check if a tag starts with a given prefix. #[test] fn test_tag_starts_with() { let tag = Tag::new("tag:yaml.org,2002:test"); // Test positive case assert_eq!(tag.starts_with("tag:yaml.org"), Ok(true)); // Test negative case assert_eq!(tag.starts_with("tag:other.org"), Ok(false)); // Test error case assert_eq!( tag.starts_with("tag:yaml.org,2002:test:extra"), Err(TagFormatError) ); } /// Test the `PartialEq` implementation for `Tag` with a string. #[test] fn test_tag_partial_eq() { let tag = Tag::new("tag:yaml.org,2002:test"); // Test equality assert_eq!(tag, "tag:yaml.org,2002:test"); // Test inequality assert_ne!(tag, "tag:yaml.org,2002:other"); } /// Test the `Deref` implementation for `Tag`. #[test] fn test_tag_deref() { let tag = Tag::new("tag:yaml.org,2002:test"); let tag_bytes: &[u8] = &tag; assert_eq!(tag_bytes, b"tag:yaml.org,2002:test"); } /// Test the `Debug` implementation for `Tag`. #[test] fn test_tag_debug() { let tag = Tag::new("tag:yaml.org,2002:test"); let debug_str = format!("{:?}", tag); assert_eq!(debug_str, "\"tag:yaml.org,2002:test\""); } /// Test the predefined constant values for `Tag`. #[test] fn test_tag_constants() { assert_eq!(Tag::NULL, "tag:yaml.org,2002:null"); assert_eq!(Tag::BOOL, "tag:yaml.org,2002:bool"); assert_eq!(Tag::INT, "tag:yaml.org,2002:int"); assert_eq!(Tag::FLOAT, "tag:yaml.org,2002:float"); } /// Test the `Display` implementation for `TagFormatError`. #[test] fn test_tag_format_error_display() { let error = TagFormatError; let error_message = format!("{}", error); assert_eq!( error_message, "Error occurred while formatting tag" ); } /// Test the `PartialEq` implementation for `Tag` with `str`. #[test] fn test_tag_partial_eq_str() { let tag = Tag::new("tag:yaml.org,2002:test"); // Test equality with str assert!(tag == "tag:yaml.org,2002:test"); // Test inequality with str assert!(tag != "tag:yaml.org,2002:other"); } /// Test the `PartialEq` implementation for `Tag` with `&str`. #[test] fn test_tag_partial_eq_str_ref() { let tag = Tag::new("tag:yaml.org,2002:test"); // Test equality with &str assert!(tag == "tag:yaml.org,2002:test"); // Test inequality with &str assert!(tag != "tag:yaml.org,2002:other"); } /// Test the `Clone` implementation for `Tag`. #[test] fn test_tag_clone() { let tag = Tag::new("tag:yaml.org,2002:test"); let cloned_tag = tag.clone(); assert_eq!(tag, cloned_tag); } /// Test the `Hash` implementation for `Tag`. #[test] fn test_tag_hash() { let tag = Tag::new("tag:yaml.org,2002:test"); let mut hasher = DefaultHasher::new(); tag.hash(&mut hasher); let hash1 = hasher.finish(); let mut hasher = DefaultHasher::new(); tag.hash(&mut hasher); let hash2 = hasher.finish(); assert_eq!(hash1, hash2); } /// Tests the `Debug` implementation for `TagFormatError`. #[test] fn test_tag_format_error_debug() { let error = TagFormatError; let debug_str = format!("{:?}", error); assert_eq!(debug_str, "TagFormatError"); } /// Tests the `Error` trait implementation for `TagFormatError`. #[test] fn test_tag_format_error_error() { let error = TagFormatError; let error_message = error.to_string(); assert_eq!( error_message, "Error occurred while formatting tag" ); } /// Tests the error case when the prefix is longer than the tag in the `starts_with` method. #[test] fn test_tag_starts_with_error() { let tag = Tag::new("short"); let prefix = "longer_prefix"; assert_eq!(tag.starts_with(prefix), Err(TagFormatError)); } /// Tests the `PartialEq` implementation for `Tag` with `&str` slices. #[test] fn test_tag_partial_eq_str_slice() { let tag = Tag::new("tag:yaml.org,2002:test"); // Test equality with &str slice assert!(tag == "tag:yaml.org,2002:test"[..]); // Test inequality with &str slice assert!(tag != "tag:yaml.org,2002:other"[..]); } /// Test the behaviour of Tag::new with an empty string #[test] fn test_tag_new_empty_string() { let tag = Tag::new(""); assert_eq!(&*tag, b""); } /// Test the behaviour of Tag::starts_with with an empty prefix #[test] fn test_tag_starts_with_empty_prefix() { let tag = Tag::new("tag:yaml.org,2002:test"); assert_eq!(tag.starts_with(""), Ok(true)); } /// Test the behaviour of Tag::starts_with with an equal prefix #[test] fn test_tag_starts_with_equal_prefix() { let tag = Tag::new("tag:yaml.org,2002:test"); assert_eq!(tag.starts_with("tag:yaml.org,2002:test"), Ok(true)); } /// Test the behaviour of Tag::starts_with with a prefix that has a different case #[test] fn test_tag_starts_with_case_sensitive() { let tag = Tag::new("tag:yaml.org,2002:test"); assert_eq!(tag.starts_with("TAG:YAML.ORG"), Ok(false)); } /// Test the behaviour of PartialEq with an empty string #[test] fn test_tag_partial_eq_empty_string() { let tag = Tag::new("tag:yaml.org,2002:test"); assert!(tag != ""); } /// Test the behaviour of PartialEq with a non-ASCII string #[test] fn test_tag_partial_eq_non_ascii() { let tag = Tag::new("tag:yaml.org,2002:test"); assert!(tag != "tag:yaml.org,2002:tést"); } }