Skip to content

Commit

Permalink
refactor(serde_yml): 🎨 Add Config Serializer to tag unit variants and…
Browse files Browse the repository at this point in the history
… new unit tests
  • Loading branch information
sebastienrousseau committed Aug 24, 2024
1 parent afac2d5 commit f4e840e
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 109 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,26 @@ alt="Serde YML logo" width="66" align="right" />

# Serde YML (a fork of Serde YAML)

[![Made With Love][made-with-rust]][11] [![Crates.io][crates-badge]][07] [![lib.rs][libs-badge]][11] [![Docs.rs][docs-badge]][08] [![Codecov][codecov-badge]][09] [![Build Status][build-badge]][10] [![GitHub][github-badge]][06]
[![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`:
Expand Down Expand Up @@ -613,6 +629,7 @@ be dual licensed as above, without any additional terms or conditions.
[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"
Expand Down
3 changes: 2 additions & 1 deletion TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ alt="Serde YML logo" width="66" align="right" />

# Serde YML (a fork of Serde YAML)

[![Made With Love][made-with-rust]][11] [![Crates.io][crates-badge]][07] [![lib.rs][libs-badge]][11] [![Docs.rs][docs-badge]][08] [![Codecov][codecov-badge]][09] [![Build Status][build-badge]][10] [![GitHub][github-badge]][06]
[![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.

Expand All @@ -20,6 +20,7 @@ alt="Serde YML logo" width="66" align="right" />
[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"
Expand Down
128 changes: 57 additions & 71 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
//!# Serde YML (a fork of Serde YAML)
//!
//![![GitHub][github-badge]][06]
//![![Crates.io][crates-badge]][07]
//![![Docs.rs][docs-badge]][08]
//![![Codecov][codecov-badge]][09]
//![![Build Status][build-badge]][10]
//!
//!A Rust library for using the [Serde][01] serialization framework with data in [YAML][05] file format. This project, has been renamed to [Serde YML][00] to avoid confusion with the original Serde YAML crate which is now archived and no longer maintained.
//!
//!## Credits and Acknowledgements
//!
//!This library is a continuation of the excellent work done by [David Tolnay][03] and the maintainers of the [serde-yaml][02] library.
//!
//!While Serde YML started as a fork of serde-yaml, it has now evolved into a separate library with its own goals and direction in mind and does not intend to replace the original serde-yaml crate.
//!
//!If you are currently using serde-yaml in your projects, we recommend carefully evaluating your requirements and considering the stability and maturity of the original library as well as looking at the features and improvements offered by other YAML libraries in the Rust ecosystem.
//!
//!I would like to express my sincere gratitude to [David Tolnay][03] and the [serde-yaml][02] team for their valuable contributions to the Rust community and for inspiring this project.
//![![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
//!
Expand All @@ -35,46 +20,51 @@
//! - 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
//!
//! ## Rust Version Compatibility
//!## Installation
//!
//! This library is compatible with Rust 1.56.0 and above.
//!Add this to your `Cargo.toml`:
//!
//! ## Installation
//!```toml
//![dependencies]
//!serde = "1.0"
//!serde_yml = "0.0.12"
//!```
//!
//! Add the following dependency to your `Cargo.toml` file:
//!## Usage
//!
//! ```toml
//! [dependencies]
//! serde_yml = "0.0.12"
//! ```
//!Here's a quick example on how to use Serde YML to serialize and deserialize a struct to and from YAML:
//!
//! ## Usage
//!```rust
//!use serde::{Serialize, Deserialize};
//!
//! Serde YML offers a straightforward and intuitive API for working with YAML data in Rust. Here's a quick example of how to serialize and deserialize a Rust type:
//!#[derive(Debug, PartialEq, Serialize, Deserialize)]
//!struct Point {
//! x: f64,
//! y: f64,
//!}
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//!fn main() -> Result<(), serde_yml::Error> {
//! let point = Point { x: 1.0, y: 2.0 };
//!
//! #[derive(Serialize, Deserialize,Debug,PartialEq)]
//! struct Point {
//! x: f64,
//! y: f64,
//! }
//! // Serialize to YAML
//! let yaml = serde_yml::to_string(&point)?;
//! assert_eq!(yaml, "x: 1.0\n'y': 2.0\n");
//!
//! fn main() -> Result<(), serde_yml::Error> {
//! let point = Point { x: 1.0, y: 2.0 };
//! // Deserialize from YAML
//! let deserialized_point: Point = serde_yml::from_str(&yaml)?;
//! assert_eq!(point, deserialized_point);
//!
//! // Serialize to YAML
//! let yaml = serde_yml::to_string(&point)?;
//! assert_eq!(yaml, "x: 1.0\n'y': 2.0\n");
//! Ok(())
//!}
//!```
//!
//! // Deserialize from YAML
//! let deserialized_point: Point = serde_yml::from_str(&yaml)?;
//! assert_eq!(point, deserialized_point);
//!## Documentation
//!
//! Ok(())
//! }
//! ```
//!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
//!
Expand All @@ -88,33 +78,29 @@
//!
//! 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://github.com/sebastienrousseau/serde_yml/releases
//![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
//![build-badge]: https://img.shields.io/github/actions/workflow/status/sebastienrousseau/serde_yml/release.yml?branch=master&style=for-the-badge "Build Status"
//![codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/serde_yml?style=for-the-badge&token=Q9KJ6XXL67 "Codecov"
//![crates-badge]: https://img.shields.io/crates/v/serde_yml.svg?style=for-the-badge&color=fc8d62&logo=rust "Crates.io"
//![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"
//!
//! [serde-yml]: https://serdeyml.com "Serde YML"
//! [serde]: https://github.com/serde-rs/serde
//! [rust-lang]: https://www.rust-lang.org/ "Rust"
//! [dtolnay]: https://github.com/dtolnay "David Tolnay"
//! [serde-yaml]: https://github.com/dtolnay/serde-yaml "Serde YAML"
//! [crates-io]: https://crates.io/crates/serde_yml "Crates.io"
//! [lib-rs]: https://lib.rs/crates/serde_yml "Lib.rs"
//! [license]: https://opensource.org/license/apache-2-0/ "MIT or Apache License, Version 2.0"
//! [repo]: https://github.com/your-repo/serde_yml "Serde YML Repository"
//! [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",
Expand Down
10 changes: 10 additions & 0 deletions src/libyml/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ pub struct Scalar<'a> {
pub enum ScalarStyle {
/// Any scalar style.
Any,
/// Double quoted scalar style.
DoubleQuoted,
/// Folded scalar style.
Folded,
/// Plain scalar style.
Plain,
/// Single quoted scalar style.
Expand Down Expand Up @@ -221,6 +225,12 @@ impl<'a> Emitter<'a> {
ScalarStyle::Any => {
YamlScalarStyleT::YamlAnyScalarStyle
}
ScalarStyle::DoubleQuoted => {
YamlScalarStyleT::YamlDoubleQuotedScalarStyle
}
ScalarStyle::Folded => {
YamlScalarStyleT::YamlFoldedScalarStyle
}
ScalarStyle::Plain => {
YamlScalarStyleT::YamlPlainScalarStyle
}
Expand Down
32 changes: 31 additions & 1 deletion src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type Result<T, E = Error> = std::result::Result<T, E>;
/// ```
#[derive(Debug)]
pub struct Serializer<W> {
/// The configuration of the serializer.
pub config: SerializerConfig,
/// The depth of the current serialization.
pub depth: usize,
/// The current state of the serializer.
Expand All @@ -58,6 +60,13 @@ pub struct Serializer<W> {
pub writer: PhantomData<W>,
}

/// The configuration of the serializer.
#[derive(Copy, Clone, Debug, Default)]

Check warning on line 64 in src/ser.rs

View check run for this annotation

Codecov / codecov/patch

src/ser.rs#L64

Added line #L64 was not covered by tests
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,

Check warning on line 67 in src/ser.rs

View check run for this annotation

Codecov / codecov/patch

src/ser.rs#L67

Added line #L67 was not covered by tests
}

/// The state of the serializer.
#[derive(Debug)]
pub enum State {
Expand All @@ -79,6 +88,14 @@ where
{
/// 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 {
Expand All @@ -89,6 +106,7 @@ where
});
emitter.emit(Event::StreamStart).unwrap();
Serializer {
config,
depth: 0,
state: State::NothingInParticular,
emitter,
Expand Down Expand Up @@ -441,7 +459,19 @@ where
_variant_index: u32,
variant: &'static str,
) -> Result<()> {
self.serialize_str(variant)
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<T>(
Expand Down
Loading

0 comments on commit f4e840e

Please sign in to comment.