# Former Macro: Architectural Limitations Analysis
This document provides a systematic analysis of the fundamental limitations preventing certain patterns from working with the Former crate. Each limitation is **experimentally verified** and includes workarounds where available.
## Quick Decision Tree: Will Former Work For My Use Case?
```
START: Want to use #[derive(Former)]
│
├─ Do you need borrowed data (&'a T)?
│ ├─ YES ─> ❌ Won't work (Lifetime Limitation)
│ │ Workaround: Use Arc<T>, Cow<'static, T>, or owned types
│ └─ NO ──> Continue ↓
│
├─ Is your type an enum with generic parameters?
│ ├─ YES ─> ❌ Won't work (Generic Enum Limitation)
│ │ Workaround: Use concrete types (String instead of T)
│ └─ NO ──> Continue ↓
│
├─ Is your enum multi-variant with complex patterns?
│ ├─ YES ─> ⚠️ May conflict (Trait Conflict Limitation)
│ │ Workaround: Use single-variant enums or split types
│ └─ NO ──> Continue ↓
│
└─> ✅ Former should work! Proceed with confidence.
```
## Workaround Quick Reference
| **Lifetimes** | `field: &'a str` | `field: String` or `field: Arc<str>` |
| **Lifetimes** | `field: &'a [u8]` | `field: Vec<u8>` or `field: Bytes` |
| **Lifetimes** | `headers: &'a HeaderMap` | `headers: Arc<HeaderMap>` |
| **Generic Enums** | `enum Msg<T> { Val(T) }` | `enum Msg { Val(String) }` |
| **Multi-Variant** | Complex enum with 5+ variants | Split into separate enums or use single variant |
---
## Detailed Analysis
This document provides a systematic analysis of the 4 fundamental limitations preventing certain tests from being enabled in the Former crate. Each limitation is **experimentally verified** and characterized using the Target Type Classification framework from the specification.
## Target Type Classification Context
According to the Former specification, the macro operates on two fundamental **Target Type Categories**:
- **Structs** - Regular Rust structs with named fields
- **Enums** - Rust enums with variants, subdivided by **Variant Structure Types** (Unit, Tuple, Named)
Each limitation affects these target types differently, as detailed in the analysis below.
## 1. Generic Enum Parsing Limitation ✅ TESTED
### Limitation Characteristics
- **Scope**: Enum Target Type Category only (Structs unaffected)
- **Severity**: Complete blocking - no generic enums supported
- **Behavioral Categories Affected**: All enum formers (Unit/Tuple/Named Variant Formers)
- **Variant Structure Types Affected**: All (Unit, Tuple, Named variants)
- **Root Cause**: Macro parser architecture limitation
- **Workaround Availability**: Full (concrete type replacement)
- **Future Compatibility**: Possible (requires major rewrite)
**What it means**: The macro cannot parse generic parameter syntax in enum declarations.
### ❌ This Breaks:
```rust
#[derive(Former)]
pub enum GenericEnum<T> { // <-- The <T> part breaks the macro
Variant(T),
}
```
**Verified Error**: `expected '::' found '>'` - macro parser fails on generic syntax
### ✅ This Works:
```rust
#[derive(Former)]
pub enum ConcreteEnum { // <-- No <T>, so it works
Variant(String),
}
// Usage: ConcreteEnum::variant()._0("hello".to_string()).form()
```
**The Technical Choice**: Simple token-based parser vs Full AST parser with generics
**Trade-off Details**:
- **Current approach**: Fast compilation, simple implementation
- **Alternative approach**: Slow compilation, complex parser supporting generics
- **Implementation cost**: Complete macro rewrite with full Rust AST parsing
- **Performance impact**: Significant compilation time increase
**Can Both Be Combined?** 🟡 **PARTIALLY**
- Technically possible but requires rewriting the entire macro parser
- Would need full Rust AST parsing instead of simple token matching
- Trade-off: Fast builds vs Generic enum support
---
## 2. Lifetime Constraint Limitation ✅ VERIFIED IN CODE
### Limitation Characteristics
- **Scope**: Both Target Type Categories (Structs and Enums)
- **Severity**: Fundamental blocking - no lifetime parameters supported
- **Behavioral Categories Affected**: All Former types with lifetime parameters
- **Variant Structure Types Affected**: N/A (applies to type-level generics)
- **Root Cause**: Rust language constraint (trait objects + lifetimes)
- **Workaround Availability**: Partial (owned data only)
- **Future Compatibility**: Impossible (fundamental Rust limitation)
**What it means**: Rust's memory safety rules fundamentally prevent borrowed data in Former storage due to trait object lifetime requirements.
### ❌ This Breaks:
```rust
// From parametrized_dyn_manual.rs:210 - real example
impl<'callback> StoragePreform for StylesFormerStorage<'callback> {
fn preform(self) -> Self::Preformed {
// ERROR E0521: borrowed data escapes outside of method
(&PhantomData::<&'callback dyn FilterCol>).maybe_default()
// `'callback` must outlive `'static`
}
}
```
### ✅ This Works:
```rust
#[derive(Former)]
pub struct OwnedStruct {
owned_data: String, // <-- Owned data is fine
numbers: Vec<i32>, // <-- Owned collections work
static_ref: &'static str // <-- Static references work
}
```
**The Technical Choice**: Trait object compatibility with memory safety vs Complex lifetime support
**Trade-off Details**:
- **Current approach**: Memory safety + trait objects work reliably
- **Alternative approach**: Complex lifetime tracking in all generated code
- **Fundamental constraint**: Trait objects require `'static` bounds for type erasure
- **Rust limitation**: Cannot allow borrowed data to escape method boundaries
**Can Both Be Combined?** 🔴 **NO**
- This is a hard Rust language constraint, not our design choice
- Trait objects fundamentally require `'static` bounds
- Even perfect implementation cannot overcome Rust's type system rules
---
## 3. Trait Conflict Limitation ✅ TESTED
### Limitation Characteristics
- **Scope**: Enum Target Type Category only (multi-variant enums)
- **Severity**: Selective blocking - single-variant enums work fine
- **Behavioral Categories Affected**: Mixed enum scenarios (Complex Scenario Formers)
- **Variant Structure Types Affected**: All when combined in single enum
- **Root Cause**: Duplicate trait implementation generation
- **Workaround Availability**: Full (single variant per enum)
- **Future Compatibility**: Possible (requires complex deduplication logic)
**What it means**: The macro generates conflicting trait implementations when multiple enum variants require the same traits.
### ❌ This Breaks:
```rust
#[derive(Former)]
pub enum MultiVariantEnum {
VariantA { field: String }, // <-- Each variant tries to
VariantB { other: i32 }, // <-- generate the same traits
VariantC, // <-- causing conflicts
}
```
**Verified Error E0119**: `conflicting implementations of trait EntityToStorage`
### ✅ This Works:
```rust
#[derive(Former)]
pub enum SingleVariantEnum {
OnlyVariant { field: String }, // <-- One variant = no conflicts
}
// Usage: SingleVariantEnum::only_variant().field("test".to_string()).form()
```
**The Technical Choice**: Simple per-enum trait generation vs Complex trait deduplication
**Trade-off Details**:
- **Current approach**: Simple code generation, one trait impl per enum
- **Alternative approach**: Sophisticated trait deduplication with variant-specific logic
- **Implementation complexity**: Exponential increase in generated code complexity
- **Maintenance burden**: Much harder to debug and maintain complex generation
**Can Both Be Combined?** 🟡 **YES, BUT VERY COMPLEX**
- Technically possible with sophisticated trait merging logic
- Requires tracking implementations across all variants
- Major increase in macro complexity and maintenance burden
- Cost/benefit analysis favors current simple approach
---
## Comprehensive Limitations Matrix
| **Generic Parsing** | Enums only | Complete blocking | All enum formers | 🟡 Possible (major rewrite) | ✅ Concrete types | High - affects API design |
| **Lifetime Constraints** | Structs + Enums | Fundamental blocking | All with lifetimes | 🔴 Impossible (Rust constraint) | 🟡 Owned data only | Critical - shapes data patterns |
| **Trait Conflicts** | Multi-variant enums | Selective blocking | Complex scenarios | 🟡 Possible (complex logic) | ✅ Single variants | Medium - affects enum design |
### Key Decision-Making Insights
**Architectural Impact Ranking**:
1. **Lifetime Constraints** - Most critical, shapes fundamental data patterns
2. **Generic Parsing** - High impact on API flexibility and user experience
3. **Trait Conflicts** - Medium impact, affects complex enum design strategies
4. **Compile-fail Tests** - Low impact, testing methodology only
**Workaround Effectiveness**:
- ✅ **Full workarounds available**: Generic Parsing, Trait Conflicts
- 🟡 **Partial workarounds**: Lifetime Constraints (owned data patterns)
- ❌ **No workarounds needed**: Compile-fail Tests (working as intended)
**Engineering Trade-offs**:
- **Generic Parsing**: Simple parser vs Universal enum support
- **Lifetime Constraints**: Memory safety vs Flexible borrowing patterns
- **Trait Conflicts**: Simple generation vs Complex multi-variant enums
- **Compile-fail Tests**: Error validation vs Maximum passing test count