jsonforge 0.1.0

A Rust procedural macro for generating JSON schema validators from Rust types
Documentation
use syn::LitStr;

use crate::codegen::util::{to_camel_case, to_pascal_case, to_snake_case};

/// Specifies how JSON object keys map to Rust field names.
///
/// Used by both `json_forge!` (auto-generated structs) and `#[json_forge_typed]`
/// (user-defined structs) to bridge between JSON key naming conventions and
/// idiomatic snake_case Rust field names.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(clippy::enum_variant_names)]
pub enum RenameRule {
    /// JSON keys are already `snake_case` — no conversion (default).
    SnakeCase,
    /// JSON keys are `PascalCase`  (e.g. `"MyField"` ↔ Rust field `my_field`).
    PascalCase,
    /// JSON keys are `camelCase`   (e.g. `"myField"` ↔ Rust field `my_field`).
    CamelCase,
}

impl RenameRule {
    /// Parse a string literal from macro input (`"snake_case"`, `"PascalCase"`, `"camelCase"`).
    pub fn from_lit(lit: &LitStr) -> syn::Result<Self> {
        match lit.value().as_str() {
            "snake_case" => Ok(RenameRule::SnakeCase),
            "PascalCase" => Ok(RenameRule::PascalCase),
            "camelCase" => Ok(RenameRule::CamelCase),
            other => Err(syn::Error::new(
                lit.span(),
                format!(
                    "unknown rename rule `{other}`; \
                     expected `snake_case`, `PascalCase`, or `camelCase`"
                ),
            )),
        }
    }

    /// Convert a JSON key to the Rust field name it should use.
    ///
    /// Called when auto-generating structs with `json_forge!`.
    pub fn json_key_to_rust_name(self, key: &str) -> String {
        match self {
            RenameRule::SnakeCase => key.to_owned(),
            RenameRule::PascalCase | RenameRule::CamelCase => to_snake_case(key),
        }
    }

    /// Convert a snake_case Rust field name to the JSON key it maps to.
    ///
    /// Called when validating user-defined structs with `#[json_forge_typed]`.
    pub fn rust_name_to_json_key(self, name: &str) -> String {
        match self {
            RenameRule::SnakeCase => name.to_owned(),
            RenameRule::PascalCase => to_pascal_case(name),
            RenameRule::CamelCase => to_camel_case(name),
        }
    }
}