configurable_serde 0.1.1

A proc-macro to apply reusable serde configurations.
Documentation
//! # Configurable Serde
//!
//! A crate providing a procedural macro to apply reusable serde configurations.
//!
//! The core of this crate is the [`#[configure_serde]`](configure_serde) attribute macro, which
//! generates `#[serde(...)]` attributes for you.
//!
//! There is also a generator macro provided [`create_config!`], which builds a wrapper
//! to apply [`#[configure_serde]`](configure_serde) to all wrapped structs and enums.
//!
//! NOTE: While it is tested and working, this is an early stage of the project
//! so it lacks many possible configurable parameters and also may be incompatible
//! with more complicated structs and enums.
//!
//! ## TL;DR
//!
//! ```rust
//! use configurable_serde::create_config;
//! use serde::{Serialize, Deserialize};
//!
//! // Generate serde configuration applier:
//!
//! create_config! {
//!    my_api_models,
//!
//!    struct_rename_all = "camelCase",
//!    enum_rename_all = "SCREAMING_SNAKE_CASE",
//!    skip_if_none,
//!    deny_unknown_fields
//! }
//!
//! // Apply defined serde configuration to multiple structs or enums:
//!
//! my_api_models! {
//!     #[derive(Serialize, Deserialize)]
//!     struct User { // camelCase and deny_unknown_fields is applied here
//!         name: String,
//!         surname: Option<String>, // skip_if_none is applied here
//!         vehicle: Vehicle,
//!     }
//!
//!     #[derive(Serialize, Deserialize)]
//!     enum Vehicle { // SCREAMING_SNAKE_CASE is applied here
//!         Car,
//!         Bicycle,
//!         ElectricScooter,
//!     }
//! }
//! ```
//!
//! So this will be expanded to:
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize, Deserialize)]
//! #[serde(rename_all = "camelCase", deny_unknown_fields)]
//! struct User {
//!     name: String,
//!     #[serde(default, skip_serializing_if = "Option::is_none")]
//!     surname: Option<String>,
//!     vehicle: Vehicle,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! #[serde(rename_all = "SCREAMING_SNAKE_CASE", deny_unknown_fields)]
//! enum Vehicle {
//!     Car,
//!     Bicycle,
//!     ElectricScooter,
//! }
//! ```
//!
//! Note, that if you want to use your applier across a whole project, you need to place [`create_config!`]
//! before any `mod` directives for modules using the applier.
//! This is because the `#[macro_export]` term generated by the other macro is not recognized early enough.
//!
//! Also note this may confuse the rust analyzer too. To overcome this, place your configs in a separate file, f.ex.
//! `serde_configs.rs` and import it before any usage with `#[macro_use] mod serde_configs;`.
//!
//! ## Supported parameters
//!
//! * **`rename_all: Option<String>`**
//!
//!   A general rename rule for both structs and enums.
//!   Can be overridden by `struct_rename_all` or `enum_rename_all`.
//!
//! * **`struct_rename_all: Option<String>`**
//!
//!   A specific rename rule for struct fields.
//!
//! * **`enum_rename_all: Option<String>`**
//!
//!   A specific rename rule for enum variants.
//!
//! * **`skip_if_none: bool`**
//!
//!   If present, adds `#[serde(default, skip_serializing_if = "Option::is_none")]`
//!   to any field of type `Option<T>`.
//!
//! * **`deny_unknown_fields: bool`**
//!
//!   If present, adds `#[serde(deny_unknown_fields)]` to the container.
//!
//! ## Manual Usage of `configure_serde` macro
//!
//! ```rust
//! use configurable_serde::configure_serde;
//! use serde::{Serialize, Deserialize};
//!
//! #[configure_serde(rename_all = "camelCase", skip_if_none)]
//! #[derive(Serialize, Deserialize, Debug, PartialEq)]
//! struct User {
//!     user_id: String,
//!     display_name: Option<String>,
//! }
//!
//! // The struct will be serialized with camelCase fields, and `display_name`
//! // will be omitted if it is `None`.
//!
//! let user = User { user_id: "u-123".to_string(), display_name: None };
//! let json = serde_json::to_string(&user).unwrap();
//!
//! assert_eq!(json, r#"{"userId":"u-123"}"#);
//! ```
//!
//! ## Reusing Configurations without `create_config`
//!
//! You can define your own applier manually. It is just a declarative macro (`macro_rules!`) that applies the
//! [`#[configure_serde]`](configure_serde) attribute with your desired settings.
//!
//! ### Reusable configuration which wraps one item
//!
//! ```rust
//! use configurable_serde::configure_serde;
//! use serde::{Serialize, Deserialize};
//!
//! /// Defines a reusable configuration named `apply_api_config`:
//! macro_rules! apply_api_config {
//!     ($item:item) => {
//!         #[configure_serde(
//!             struct_rename_all = "camelCase",
//!             enum_rename_all = "SCREAMING_SNAKE_CASE",
//!             skip_if_none,
//!             deny_unknown_fields
//!         )]
//!         $item
//!     };
//! }
//!
//! // Now, apply this configuration to a struct.
//! apply_api_config! {
//!     #[derive(Serialize, Deserialize, Debug, PartialEq)]
//!     pub struct Product {
//!         product_id: String,
//!         stock_count: Option<u32>,
//!     }
//! }
//!
//! // And to an enum.
//! apply_api_config! {
//!     #[derive(Serialize, Deserialize, Debug, PartialEq)]
//!     pub enum Status {
//!         InStock,
//!         Backordered,
//!         Discontinued,
//!     }
//! }
//!
//! // Test the struct serialization
//! let product = Product {
//!     product_id: "prod-456".to_string(),
//!     stock_count: Some(50)
//! };
//!
//! let product_json = serde_json::to_string(&product).unwrap();
//! assert_eq!(product_json, r#"{"productId":"prod-456","stockCount":50}"#);
//!
//! // Test the enum serialization
//! let status = Status::InStock;
//!
//! let status_json = serde_json::to_string(&status).unwrap();
//! assert_eq!(status_json, r#""IN_STOCK""#);
//! ```
//!
//! ### Reusable configuration which wraps multiple items
//!
//! This is the same as what you get using the [`create_config!`] macro, but it let's you to place the definition
//! in any place in your crate (that is: `#[macro_export]` works).
//!
//! ```rust
//! #[macro_export]
//! macro_rules! my_api_models {
//!     ($($item:item)*) => {
//!         $(
//!             #[configurable_serde::configure_serde(
//!                 struct_rename_all = "camelCase",
//!                 enum_rename_all = "SCREAMING_SNAKE_CASE",
//!                 skip_if_none
//!             )]
//!             $item
//!         )*
//!     };
//! }
//! ```

/// Apply config manually to struct or enum.
pub use configurable_serde_macros::configure_serde;

/// Generate `configure_serde` applier to provide config to all wrapped items.
pub use configurable_serde_macros::create_config;