# Technical Specification: The `former` Derive Macro
### 1. Introduction & Core Concepts
* **1.1. Problem Solved:** The `former` derive macro simplifies the implementation of the Builder pattern in Rust. It automates the generation of fluent, readable, and maintainable APIs for object initialization, reducing boilerplate code for complex `struct` and `enum` types.
* **1.2. Guiding Principles:**
* **Clarity over Brevity:** The generated code and public APIs should be easy to understand and predictable.
* **Composition over Configuration:** Favor nested builders (subformers) for complex data structures to maintain a clear, hierarchical construction flow.
* **Convention over Configuration:** Provide sensible defaults for common patterns (e.g., handling of `Option<T>`, default collection formers) while allowing explicit overrides for customization.
* **Dependencies: Prefer `macro_tools`:** The macro's internal implementation **must** prefer the abstractions provided by the `macro_tools` crate over direct usage of `syn`, `quote`, and `proc-macro2`.
* **1.3. Key Terminology (Ubiquitous Language):**
* **Former:** The builder struct generated by the `#[derive(Former)]` macro (e.g., `MyStructFormer`).
* **Storage:** An internal, temporary struct (`...FormerStorage`) that holds the intermediate state of the object being built.
* **Definition:** A configuration struct (`...FormerDefinition`) that defines the types and `End` condition for a forming process.
* **Subformer:** A `Former` instance used to build a part of a larger object.
### 2. Core Behavioral Specification
This section defines the core user-facing contract of the `former` macro. The following logic tables and attribute definitions are the single source of truth for its behavior.
#### 2.1. Enum Variant Constructor Logic
The macro generates a static constructor method on the enum for each variant. The type of constructor is determined by the variant's structure and attributes according to the following rules:
| **1a** | Unit: `V` | `#[scalar]` or Default | Direct constructor: `Enum::v() -> Enum` |
| **1b** | Tuple: `V()` | `#[scalar]` or Default | Direct constructor: `Enum::v() -> Enum` |
| **1c** | Struct: `V {}` | `#[scalar]` | Direct constructor: `Enum::v() -> Enum` |
| **1d** | Tuple: `V(T1)` | `#[scalar]` | Scalar constructor: `Enum::v(T1) -> Enum` |
| **1e** | Struct: `V {f1:T1}` | `#[scalar]` | Scalar constructor: `Enum::v{f1:T1} -> Enum` |
| **1f** | Tuple: `V(T1, T2)` | `#[scalar]` | Scalar constructor: `Enum::v(T1, T2) -> Enum` |
| **1g** | Struct: `V {f1:T1, f2:T2}` | `#[scalar]` | Scalar constructor: `Enum::v{f1:T1, f2:T2} -> Enum` |
| **2a** | Unit: `V` | `#[subform_scalar]` | **Compile Error** |
| **2b** | Tuple: `V()` | `#[subform_scalar]` | **Compile Error** |
| **2c** | Struct: `V {}` | `#[subform_scalar]` | **Compile Error** |
| **2d** | Tuple: `V(T1)` | `#[subform_scalar]` or Default | Subformer for inner type: `Enum::v() -> T1::Former` |
| **2e** | Struct: `V {f1:T1}` | `#[subform_scalar]` or Default | Implicit variant former: `Enum::v() -> VFormer` |
| **2f** | Tuple: `V(T1, T2)` | `#[subform_scalar]` | **Compile Error** |
| **2g** | Struct: `V {f1:T1, f2:T2}` | `#[subform_scalar]` or Default | Implicit variant former: `Enum::v() -> VFormer` |
| **3c** | Struct: `V {}` | Default | **Compile Error** (Requires `#[scalar]`) |
| **3f** | Tuple: `V(T1, T2)` | Default | **Implicit variant former: `Enum::v() -> VFormer`** |
**Note on Rule 3f:** This rule is updated to reflect the implemented and tested behavior. The previous specification incorrectly stated this case would generate a scalar constructor. The actual behavior is to generate a subformer for the variant itself.
#### 2.2. Standalone Constructor Behavior
When the `#[standalone_constructors]` attribute is applied to an item, the return type of the generated top-level function(s) is determined by the usage of `#[arg_for_constructor]` on its fields:
* **Rule SC-1 (Full Construction):** If **all** fields of a struct or enum variant are marked with `#[arg_for_constructor]`, the generated standalone constructor will take all fields as arguments and return the final, constructed instance (`Self`).
* **Rule SC-2 (Partial Construction):** If **some or none** of the fields of a struct or enum variant are marked with `#[arg_for_constructor]`, the generated standalone constructor will take only the marked fields as arguments and return an instance of the `Former` (`...Former`), pre-initialized with those arguments.
#### 2.3. Attribute Reference
The following attributes control the behavior defined in the logic tables above.
##### 2.3.1. Item-Level Attributes
| `#[storage_fields(..)]` | Defines extra fields exclusive to the `...FormerStorage` struct for intermediate calculations. |
| `#[mutator(custom)]` | Disables default `FormerMutator` implementation, requiring a manual `impl` block. |
| `#[perform(fn...)]` | Specifies a method on the original struct to be called by `.perform()` after forming. |
| `#[standalone_constructors]` | Generates top-level constructor functions. |
| `#[debug]` | Prints the macro's generated code to the console at compile time. |
##### 2.3.2. Field-Level / Variant-Level Attributes
| `#[former(default = ...)]` | Provides a default value for a field if its setter is not called. |
| `#[scalar]` | Forces the generation of a simple scalar setter (e.g., `.field(value)`). |
| `#[subform_scalar]` | Generates a method returning a subformer for a nested struct. The field's type must also derive `Former`. |
| `#[subform_collection]` | Generates a method returning a specialized collection subformer (e.g., `VectorFormer`). |
| `#[subform_entry]` | Generates a method returning a subformer for a single entry of a collection. |
| `#[arg_for_constructor]` | Marks a field as a required argument for a `#[standalone_constructors]` function. |
##### 2.3.3. Attribute Precedence and Interaction Rules
1. **Subform vs. Scalar:** Subform attributes (`#[subform_scalar]`, `#[subform_collection]`, `#[subform_entry]`) take precedence over `#[scalar]`. If both are present, the subform behavior is implemented, and a scalar setter is **not** generated unless explicitly requested via `#[scalar(setter = true)]`.
2. **Setter Naming:** If a `name` is provided (e.g., `#[scalar(name = new_name)]`), it overrides the default setter name derived from the field's identifier.
3. **Setter Disabling:** `setter = false` on any attribute (`scalar`, `subform_*`) will prevent the generation of that specific user-facing setter method. Internal helper methods (e.g., `_field_subform_entry()`) are still generated to allow for manual implementation of custom setters.
4. **`#[former(default = ...)]`:** This attribute is independent and can be combined with any setter type. It provides a fallback value if a field's setter is never called.
### 3. Generated Code Architecture
The `#[derive(Former)]` macro generates a consistent set of components to implement the behavior defined in Section 2.
* **`TFormer` (The Former)**
* **Purpose:** The public-facing builder.
* **Key Components:** A `storage` field, an `on_end` field, setter methods, and a `.form()` method.
* **`TFormerStorage` (The Storage)**
* **Purpose:** Internal state container.
* **Key Components:** A public, `Option`-wrapped field for each field in `T` and any `#[storage_fields]`.
* **`TFormerDefinition` & `TFormerDefinitionTypes` (The Definition)**
* **Purpose:** To make the forming process generic and customizable.
* **Key Associated Types:** `Storage`, `Context`, `Formed`, `End`.
### 4. Diagnostics & Debugging
* **Error Handling Strategy:** The macro must produce clear, concise, and actionable compile-time errors. Errors must be associated with the specific `span` of the code that caused the issue. The `trybuild` crate must be used to create a suite of compile-fail tests to verify error-handling behavior.
* **Debug Attribute Requirements:** Following the design principle "Proc Macros: Must Implement a 'debug' Attribute", the `#[debug]` item-level attribute must be provided with comprehensive debugging capabilities.
#### 4.1. Debug Attribute Specification
**Attribute Usage:**
```rust
// Standalone debug attribute
#[derive(Former)]
#[debug] // <-- Enables comprehensive debug output
pub struct MyStruct { field: String }
// Within #[former(...)] container
#[derive(Former)]
#[former(debug, standalone_constructors)] // <-- Debug with other attributes
pub struct MyStruct { field: String }
```
**Debug Output Requirements:**
When `#[debug]` is present and the `former_diagnostics_print_generated` feature is enabled, the macro must provide detailed information in four phases:
1. **Input Analysis Phase**:
- Target type information (name, kind, visibility)
- Generic parameters analysis (lifetimes, types, consts, where clauses)
- Field/variant analysis with types and attributes
- Complete attribute configuration breakdown
2. **Generic Classification Phase**:
- Classification results (lifetime-only, type-only, mixed, empty)
- Generated generic components (impl_generics, ty_generics, where_clause)
- Strategy explanation for code generation decisions
3. **Generated Components Analysis Phase**:
- Core component breakdown (FormerStorage, FormerDefinition, Former, etc.)
- Trait implementation overview
- Formation process workflow explanation
- Attribute-driven customizations impact
4. **Complete Generated Code Phase**:
- Final TokenStream output for compilation
- Integration points with existing code
**Feature Flag Integration:**
Debug output must be gated behind the `former_diagnostics_print_generated` feature flag to ensure zero impact on normal compilation.
**Development Workflow Integration:**
- Zero runtime cost (analysis only during compilation)
- Conditional compilation (debug code only with feature flag)
- IDE-friendly output format
- CI/CD pipeline compatibility
### 5. Lifecycle & Evolution
* **Versioning Strategy:** The `former` crate must adhere to Semantic Versioning 2.0.0.
* **Deprecation Strategy:** Features or attributes planned for removal must first be marked as deprecated via `#[deprecated]` for at least one minor release cycle before being removed in a subsequent major version.
### 6. Meta-Requirements
* **Ubiquitous Language:** All terms defined in the `Key Terminology` section must be used consistently.
* **Naming Conventions:** All generated asset names must use `snake_case`. Generated functions must follow a `noun_verb` pattern.
* **Single Source of Truth:** The Git repository is the single source of truth for all project artifacts.
### 7. Deliverables
* `specification.md`: This document.
* `spec_addendum.md`: A companion document for implementation-specific details.
### 8. Conformance Check Procedure
1. **Run Full Test Suite:** Execute `cargo test --workspace`.
2. **Check Linter:** Execute `cargo clippy --workspace --all-targets -- -D warnings`.
3. **Review Attribute Coverage:** Manually verify that every rule in the logic tables has a corresponding passing test.
4. **Review Documentation:** Manually verify that the `Readme.md` and `advanced.md` documents are consistent with this specification.
***
# Specification Addendum
### Purpose
This document is a companion to the main `specification.md`. It is intended to be completed by the **Developer** during the implementation of the `former` macro. While the main specification defines the "what" and "why" of the macro's public contract, this addendum captures the "how" of the final implementation.
### Instructions for the Developer
As you implement or modify the `former_meta` crate, please fill out the sections below with the relevant details. This creates a crucial record for future maintenance, debugging, and onboarding.
---
### Internal Module Overview
*A high-level description of the key modules within the `former_meta` crate and their responsibilities.*
| `derive_former` | Top-level entry point for the `#[derive(Former)]` macro. Dispatches to struct or enum handlers. |
| `derive_former::former_struct` | Contains the primary logic for generating all code components for `struct`s. |
| `derive_former::former_enum` | Contains the primary dispatch logic for `enum`s, routing to specific variant handlers based on the rules in the specification. |
| `derive_former::former_enum::*` | Individual handler modules for each combination of enum variant type and attribute (e.g., `unit_variant_handler`, `tuple_single_field_scalar`). |
| `derive_former::field_attrs` | Defines and parses all field-level and variant-level attributes (e.g., `#[scalar]`). |
| `derive_former::struct_attrs` | Defines and parses all item-level attributes (e.g., `#[storage_fields]`). |
### Key Internal Data Structures
*List the primary internal-only structs or enums used during the macro expansion process and their purpose.*
| `ItemAttributes` | `former_meta` | Holds the parsed attributes from the top-level `struct` or `enum`. |
| `FieldAttributes` | `former_meta` | Holds the parsed attributes for a single `struct` field or `enum` variant. |
| `FormerField` | `former_meta` | A unified representation of a field, combining its `syn::Field` data with parsed `FieldAttributes`. |
| `EnumVariantHandlerContext` | `former_meta` | A context object passed to enum variant handlers, containing all necessary information for code generation (AST nodes, attributes, generics, etc.). |
### Testing Strategy
*A description of the testing methodology for the macro.*
- **UI / Snapshot Testing (`trybuild`):** The `trybuild` crate is used to create a comprehensive suite of compile-fail tests. This ensures that invalid attribute combinations and incorrect usage patterns result in the expected compile-time errors, as defined in the specification.
- **Manual vs. Derive Comparison:** This is the primary strategy for verifying correctness. For each feature, a three-file pattern is used:
1. `_manual.rs`: A file containing a hand-written, correct implementation of the code that the macro *should* generate.
2. `_derive.rs`: A file that uses `#[derive(Former)]` on an identical data structure.
3. `_only_test.rs`: A file containing only `#[test]` functions that is `include!`d by both the `_manual.rs` and `_derive.rs` files. This guarantees that the exact same assertions are run against both the hand-written and macro-generated implementations, ensuring their behavior is identical.
### Finalized Library & Tool Versions
*List the critical libraries, frameworks, or tools used and their exact locked versions from `Cargo.lock`.*
- `rustc`: `1.78.0`
- `macro_tools`: `0.15.0`
- `convert_case`: `0.6.0`
---
## Development Best Practices and Common Pitfalls
*This section captures critical knowledge gained during implementation to prevent regression and maintain code quality.*
### Critical Development Pitfalls ⚠️
#### 1. Test Verification Trap
**Issue**: Assuming tests are fixed without proper compilation verification
- **Symptom**: Claiming tests work when they have compilation errors
- **Prevention**: Always run `cargo test --all-features --lib test_name --no-run` before marking fixes complete
- **Resolution**: Establish mandatory verification checkpoints in development workflow
#### 2. Commented-Out Derive Attributes
**Issue**: Tests appear blocked but just have commented `#[derive(Former)]` attributes
- **Detection**: Search for `// #[derive.*Former` patterns in test files
- **Resolution**: Uncomment derive attributes (90% of "blocked" test issues)
- **Prevention**: Use feature flags instead of commenting out derives during debugging
#### 3. Stale BLOCKED Comments
**Issue**: Comments claiming tests are blocked when they actually work with current macro
- **Detection**: Verify every BLOCKED comment by testing actual compilation
- **Resolution**: Update comments immediately when underlying issues are resolved
- **Prevention**: Regular audits of comment accuracy vs. reality
#### 4. Feature Gate Inconsistency
**Issue**: Inconsistent `#[cfg(...)]` patterns across test modules
- **Standard**: Use `#[cfg(any(not(feature = "no_std"), feature = "use_alloc"))]` consistently
- **Prevention**: Create standardized cfg templates for copy-paste
- **Resolution**: Audit and standardize all feature gate patterns
### Development Workflow Best Practices
#### Test Resolution Process
1. **Assessment**: `cargo test --all-features --lib test_name --no-run` (never trust old comments)
2. **Diagnosis**: `grep "// #\[derive.*Former" test_file.rs` (check for commented derives first)
3. **Fix**: Try derive macro first before manual implementation (90% success rate)
4. **Verification**: Compile → Execute → Full suite testing
5. **Documentation**: Update comments and specs immediately
#### Common Resolution Patterns
- **90%**: Simple derive attribute uncommented
- **5%**: Feature gate configuration fixed
- **5%**: Actual blocking issues requiring architectural changes
#### Manual vs. Derive Decision Tree
```rust
// 1. ALWAYS try derive macro first
#[derive(Debug, PartialEq, Former)]
pub struct MyStruct<T> { ... }
// 2. Only use manual implementation if derive fails with unfixable errors
// (Manual requires 20+ types and trait implementations)
```
### Testing Guidelines
#### Test Isolation Discipline
- Enable and verify ONE test at a time
- Never batch-enable multiple potentially broken tests
- Follow "one test at a time" verification process
- Maintain clear test state isolation
#### Verification Requirements
```bash
# Mandatory verification sequence
cargo test --all-features --lib test_name --no-run # Compilation
cargo test --all-features --lib test_name # Execution
cargo test --all-features --quiet # Full suite
```
### Documentation Maintenance
#### Comment Accuracy Requirements
- BLOCKED comments MUST reflect current reality
- Update documentation with every code change
- Document every pitfall encountered for future reference
- Maintain traceability between comments and actual test state
#### Knowledge Preservation Strategy
1. **Immediate Documentation**: Record every resolution as it happens
2. **Pattern Recognition**: Document recurring issue patterns
3. **Prevention Strategies**: Create templates and checklists
4. **Regular Audits**: Monthly review of all BLOCKED/TODO comments
### Architecture Guidelines
#### Derive Macro Capabilities
- Complex lifetime scenarios: Generally supported with proper syntax
- Generic constraints: Usually handled correctly by macro
- Hash+Eq requirements: Check trait bounds for HashMap-like collections
- Feature gate requirements: Must be properly configured for collection tests
#### Manual Implementation Indicators
Manual implementation only needed when:
- Derive macro fails with unfixable fundamental errors (rare)
- Custom forming logic required beyond standard patterns
- Complex HRTB (Higher-Ranked Trait Bounds) scenarios
- Architectural requirements prevent derive macro usage
### Maintenance Checklist
#### Pre-Release Verification
- [ ] All BLOCKED comments verified against actual test compilation
- [ ] Feature gate patterns standardized across all test modules
- [ ] Documentation updated to reflect current reality
- [ ] Full test suite passes with `cargo test --all-features --quiet`
- [ ] No commented-out derives in production test files
#### Regular Maintenance (Monthly)
- [ ] Audit all BLOCKED/TODO/xxx comments for accuracy
- [ ] Verify "blocked" tests still fail with current macro capabilities
- [ ] Update documentation for any resolved issues
- [ ] Review and update common pitfall documentation
This knowledge base prevents regression and ensures consistent development practices across the `former` crate ecosystem.
### Individual Issue Resolution Catalog
**📋 Comprehensive Documentation**: See `RESOLVED_ISSUES_CATALOG.md` for detailed documentation of **12 specific resolved issues**, each with:
- Exact error messages and root cause analysis
- Specific code changes applied
- Key insights and lessons learned
- Prevention strategies for each issue type
- Cross-issue pattern analysis and meta-insights
This catalog preserves the knowledge from each individual fix to prevent regression and guide future similar issues.