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'