field_name 0.2.0

A proc-macro for exposing a struct's field names at runtime.
Documentation
//! # field_name
//!
//! A procedural macro crate that allows you to access struct field names and enum variant names
//! as compile-time string constants.
//!
//! ## Motivation
//!
//! When writing code that interacts with databases (like MongoDB), serialization formats (JSON),
//! or dynamic query builders, developers often hardcode field names as strings:
//!
//! ```rust,ignore
//! // ❌ Error-prone: if the struct field changes, this string becomes invalid.
//! let query = doc! { "userName": "alice" };
//! ```
//!
//! `field_name` solves this by generating associated constants for your types.
//! If you rename a field in your struct, your code will fail to compile, saving you from runtime errors.
//!
//! ```rust,ignore
//! // ✅ Type-safe: compiler ensures this field exists.
//! let query = doc! { User::USER_NAME: "alice" };
//! ```
//!
//! ## Features
//!
//! - **Struct Fields**: Generates `pub const FIELD_NAME` for every field.
//! - **Enum Variants**: Generates `pub const VARIANT_NAME` for every variant.
//! - **Renaming**: Support for mapping Rust field names to wire formats (e.g., `id` -> `_id`).
//! - **Skipping**: Exclude internal fields or variants from generation.
//! - **Lists**: Generates a `FIELDS` or `VARIANTS` array containing all valid names.
//!
//! ## Usage
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! field_name = "0.1"
//! ```
//!
//! ### Deriving Struct Field Names
//!
//! Use `#[derive(FieldNames)]` on named structs.
//!
//! ```rust
//! use field_name::FieldNames;
//!
//! #[derive(FieldNames)]
//! struct User {
//!     username: String,
//!     email: String,
//!
//!     #[field_name(rename = "_id")]
//!     id: u64,
//!
//!     #[field_name(skip)]
//!     internal_cache: String,
//! }
//!
//! fn main() {
//!     // Access individual field names as constants
//!     assert_eq!(User::USERNAME, "username");
//!     assert_eq!(User::EMAIL, "email");
//!     assert_eq!(User::ID, "_id");
//!
//!     // Access all fields as a list
//!     assert_eq!(User::FIELDS, ["username", "email", "_id"]);
//!
//!     // 'internal_cache' is skipped
//!     assert!(!User::FIELDS.contains(&"internal_cache"));
//! }
//! ```
//!
//! ### Deriving Enum Variant Names
//!
//! Use `#[derive(VariantNames)]` on enums.
//!
//! ```rust
//! use field_name::VariantNames;
//!
//! #[derive(VariantNames)]
//! enum ConnectionState {
//!     Connected,
//!
//!     #[variant_name(rename = "disconnected_by_server")]
//!     Disconnected,
//!
//!     Error(String),
//! }
//!
//! fn main() {
//!     assert_eq!(ConnectionState::CONNECTED, "Connected");
//!     assert_eq!(ConnectionState::DISCONNECTED, "disconnected_by_server");
//!     assert_eq!(ConnectionState::ERROR, "Error");
//!
//!     assert_eq!(ConnectionState::VARIANTS, ["Connected", "disconnected_by_server", "Error"]);
//! }
//! ```
//!
//! ## Configuration
//!
//! The macros can be configured using the `#[field_name(...)]` (for structs) and
//! `#[variant_name(...)]` (for enums) attributes.
//!
//! | Attribute | Description |
//! |-----------|-------------|
//! | `skip` | Excludes the field/variant from the `FIELDS`/`VARIANTS` array and does not generate a constant. |
//! | `rename = "name"` | Uses the provided string value instead of the Rust identifier. Useful for `_id` or `camelCase`. |

extern crate proc_macro;

use darling::FromDeriveInput;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

mod fields;
mod variants;

/// Derives associated constants and a `FIELDS` array for struct fields.
///
/// See the [crate-level documentation](crate) for usage examples.
#[proc_macro_derive(FieldNames, attributes(field_name))]
pub fn derive_field_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    fields::Receiver::from_derive_input(&parse_macro_input!(input as DeriveInput))
        .map(|receiver| quote!(#receiver))
        .unwrap_or_else(|err| err.write_errors())
        .into()
}

/// Derives associated constants and a `VARIANTS` array for enum variants.
///
/// See the [crate-level documentation](crate) for usage examples.
#[proc_macro_derive(VariantNames, attributes(variant_name))]
pub fn derive_variant_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    variants::Receiver::from_derive_input(&parse_macro_input!(input as DeriveInput))
        .map(|receiver| quote!(#receiver))
        .unwrap_or_else(|err| err.write_errors())
        .into()
}