diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4d6239a..c369691 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -21,4 +21,4 @@ jobs: - name: Build run: cargo build --verbose - name: Run tests - run: cargo test --verbose + run: cargo test --verbose --all-features diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7b2b22c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": "all" +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 37efb59..0312a3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,8 @@ version = "0.1.3" dependencies = [ "pest", "pest_derive", + "serde", + "serde_json", "thiserror", ] @@ -65,6 +67,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + [[package]] name = "libc" version = "0.2.174" @@ -139,6 +147,44 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.9" diff --git a/Cargo.toml b/Cargo.toml index 7aa6558..7732938 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ license = "GPL-3.0" rust-version = "1.85.0" [dependencies] +serde = { version = "1.0", features = ["derive"], optional = true } pest = "2.8.1" pest_derive = "2.8.1" thiserror = "2.0.12" + +[dev-dependencies] +serde_json = "1.0" diff --git a/README.md b/README.md index 7568788..4960e70 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,17 @@ Add the crate to your project: cargo add dyf ``` -## Examples +### Serde Support + +The `dyf` crate provides optional support for serialization and deserialization using the `serde` crate. +To enable this feature, add the `serde` feature when adding the crate to your project: + +```sh +cargo add dyf --features serde +``` + +Once the `serde` feature is enabled, the `FormatString` structure derives the `Serialize` and `Deserialize` traits. +This allows you to easily serialize and deserialize `FormatString` instances using the `serde` crate. ### Basic Formatting diff --git a/src/lib.rs b/src/lib.rs index 066a475..98f6d69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,17 @@ //! cargo add dyf //! ``` //! -//! ## Examples +//! ### Serde Support +//! +//! The `dyf` crate provides optional support for serialization and deserialization using the `serde` crate. +//! To enable this feature, add the `serde` feature when adding the crate to your project: +//! +//! ```sh +//! cargo add dyf --features serde +//! ``` +//! +//! Once the `serde` feature is enabled, the `FormatString` structure derives the `Serialize` and `Deserialize` traits. +//! This allows you to easily serialize and deserialize `FormatString` instances using the `serde` crate. //! //! ### Basic Formatting //! @@ -211,6 +221,9 @@ use std::{ use pest::{Parser, iterators::Pair}; use thiserror::Error; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + mod imp; mod parser; use parser::{FmtParser, Rule}; @@ -425,6 +438,7 @@ pub trait DynDisplay { /// } /// } /// ``` +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, Copy)] pub enum FmtType { /// Default formatting for the type. @@ -509,6 +523,7 @@ impl Display for FmtType { /// The [`Align`] enum determines how text should be aligned when a width is specified /// in a format specification. It controls whether the text is left-aligned, right-aligned, /// or centered within the allocated space. +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, Copy)] pub enum Align { /// Left-align the text within the field. @@ -551,6 +566,7 @@ impl Display for Align { /// In format strings, these correspond to: /// - `+` for `Sign::Positive` (show signs for both positive and negative numbers) /// - `-` for `Sign::Negative` (show signs only for negative numbers, default behavior) +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, Copy)] pub enum Sign { /// Always show the sign for numeric values. @@ -586,6 +602,7 @@ impl Display for Sign { /// /// A format specification in a string typically looks like: /// `:[fill][align][sign][#][0][width][.precision][type]` +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct FormatSpec { /// The fill character to use for padding. @@ -765,6 +782,7 @@ impl FormatSpec { } } +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] struct Format { start: usize, @@ -856,6 +874,7 @@ impl Format { /// let fmt_str = fmt.to_string_lossy(); /// let owned_str = fmt.into_string(); /// ``` +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct FormatString { s: String, @@ -1624,4 +1643,12 @@ mod tests { assert_eq!(format!("{arc}"), dformat_lit!("{}", arc).unwrap()); assert_eq!(format!("{cow_str}"), dformat_lit!("{}", cow_str).unwrap()); } + + #[test] + fn test_serde() { + let fs = FormatString::new_from_str("{}").unwrap(); + let js_fs = serde_json::to_string(&fs).unwrap(); + let fs: FormatString = serde_json::from_str(&js_fs).unwrap(); + assert_eq!(format!("{}", 42), dformat!(&fs, 42).unwrap()) + } }