waddling-errors-macros 0.7.3

Procedural macros for structured error codes with compile-time validation and taxonomy enforcement
Documentation
# Macro Crate Architecture

This document describes the architecture of `waddling-errors-macros`.

## Overview

The macro crate provides 7 procedural macros for defining WDP error codes with rich metadata.

---

## Macro Dependency Chain

Macros must be used in a specific order:

```
┌─────────────────────────────────────────────────────────────────────┐
│                                                                      │
│     setup!          component!         primary!         sequence!    │
│        │                │                  │                │        │
│        │  (configures   │  (defines        │  (defines      │        │
│        │   path         │   Component      │   Primary      │        │
│        │   resolution)  │   enum)          │   enum)        │        │
│        │                │                  │                │        │
│        └────────────────┴──────────────────┴────────────────┘        │
│                                    │                                 │
│                                    ▼                                 │
│                               diag!                                  │
│                          (uses all above)                            │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Order: setup! → component! → primary! → sequence! → diag!
```

---

## The 7 Macros

| Macro | Type | Purpose |
|-------|------|---------|
| `setup!` | proc-macro | Configure path resolution for diag! |
| `component!` | proc-macro | Define Component enum + traits |
| `primary!` | proc-macro | Define Primary enum + traits |
| `sequence!` | proc-macro | Define sequence constants (001-999) |
| `diag!` | proc-macro | Define full error codes with metadata |
| `component_location!` | proc-macro | Register file/folder as belonging to component |
| `#[in_component]` | attribute | Mark modules as belonging to component |

---

## Data Flow

### Phase 1: Setup

```rust
setup! {
    components = crate::my_components,
    primaries = crate::my_primaries,
    sequences = crate::my_sequences,
}
```

**Generates:**
```rust
#[doc(hidden)]
pub mod __wd_paths {
    pub use crate::my_components as components;
    pub use crate::my_primaries as primaries;
    pub use crate::my_sequences as sequences;
}
```

This allows `diag!` to find definitions regardless of where they're placed.

### Phase 2: Building Blocks (parallel)

**component!**
```rust
component! {
    Auth { description: "Authentication" },
    Database,
}
```
**Generates:**
```rust
pub enum Component { Auth, Database }
impl ComponentId for Component { ... }
impl ComponentIdDocumented for Component { ... }
```

**primary!**
```rust
primary! {
    Token { description: "Token errors" },
    Query,
}
```
**Generates:**
```rust
pub enum Primary { Token, Query }
impl PrimaryId for Primary { ... }
impl PrimaryIdDocumented for Primary { ... }
```

**sequence!**
```rust
sequence! {
    MISSING(001) { description: "Item missing" },
    EXPIRED(031),
}
```
**Generates:**
```rust
pub const MISSING: u16 = 1;
pub const EXPIRED: u16 = 31;
// + SequenceMeta structs for doc generation
```

### Phase 3: Error Definition

```rust
diag! {
    <json, html>,  // Auto-register for doc generation
    E.Auth.Token.MISSING: {
        message: "Token missing",
        hints: ["Check Authorization header"],
    },
}
```

**Processing:**
1. **Parse**: Split `E.Auth.Token.MISSING` into parts
2. **Resolve**: Look up `Auth` in components, `Token` in primaries, `MISSING` in sequences
3. **Validate**: Check all exist and sequence is 1-999
4. **Hash**: Compute WDP hash at compile time via `waddling-errors-hash`
5. **Generate**: Const definition + metadata + optional doc registration

---

## File Structure

```
waddling-errors-macros/src/
├── lib.rs                 # Macro exports (entry points)
├── setup.rs               # setup! implementation
├── component.rs           # component! implementation
├── primary.rs             # primary! implementation
├── sequence.rs            # sequence! implementation
├── diag.rs                # diag! implementation (largest file)
├── in_component.rs        # #[in_component] attribute
├── component_location.rs  # component_location! macro
├── doc_gen_attr.rs        # Doc generation attribute parsing
└── doc_gen_macro.rs       # Doc generation helpers
```

### Key Types by File

| File | Key Types |
|------|-----------|
| `setup.rs` | `SetupInput` |
| `component.rs` | `ComponentInput`, `ComponentVariant`, `ComponentMetadata` |
| `primary.rs` | `PrimaryInput`, `PrimaryVariant`, `PrimaryMetadata` |
| `sequence.rs` | `SequenceInput`, `SequenceItem`, `SequenceMetadata` |
| `diag.rs` | `DiagInput`, `DiagEntry`, `FieldVisibility`, `FieldRole` |

---

## diag! Field System

The `diag!` macro supports a rich marker system for fields:

### Visibility Markers

Controls where the field appears:

| Marker | Meaning | Use Case |
|--------|---------|----------|
| `'C` | Compile-time only | Documentation, not in binary |
| `'R` | Runtime only | In binary, not in docs |
| `'CR` | Both (default) | Everywhere |

### Role Markers

Controls who sees the field:

| Marker | Meaning | Audience |
|--------|---------|----------|
| `'Pub` | Public (default) | End users |
| `'Dev` | Developer | Internal developers |
| `'Int` | Internal | SRE/Operations |

### Combined Example

```rust
diag! {
    E.Auth.Token.001: {
        // Both contexts, public (default)
        message: "Token is missing",
        
        // Docs only, public
        'C 'Pub description: "The authentication token was not found in the request",
        
        // Docs only, developer
        'C 'Dev hints: ["Check the Authorization header format"],
        
        // Both contexts, developer
        'CR 'Dev debug_info: "Token parsing failed at step 1",
    },
}
```

---

## Supported diag! Fields

| Field | Type | Description |
|-------|------|-------------|
| `message` | String | Primary error message (supports `{{field}}` interpolation) |
| `description` | String | Detailed explanation |
| `hints` | [String] | Array of helpful hints |
| `tags` | [String] | Category tags |
| `see_also` | [String] | Related error codes |
| `related_codes` | [String] | Alternative error codes |
| `examples` | [String] | Usage examples |
| `code_snippets` | [Snippet] | Wrong/correct code examples |
| `introduced` | String | Version introduced |
| `deprecated` | String | Deprecation notice |
| `role` | Ident | Default role for error |
| `fields` | [Ident] | Message template fields |

---

## Hash Computation

Hashes are computed at **compile time** using `waddling-errors-hash`:

```
diag! input: "E.Auth.Token.001"
┌─────────────────────────────────┐
│ waddling_errors_hash            │
│                                 │
│ 1. Format: "E.AUTH.TOKEN.001"   │
│ 2. xxHash3 with WDP seed        │
│ 3. Extract 40 bits              │
│ 4. Base62 encode                │
│                                 │
│ Output: "V6a0B" (5 chars)       │
└─────────────────────────────────┘
Generated: const HASH: &str = "V6a0B";
```

No runtime cost - hash is a string literal in the binary.

---

## Location Tracking

Two macros for associating code locations with components:

### #[in_component(Auth)]

Attribute on modules:
```rust
#[in_component(Auth)]
mod auth_handlers {
    // ...
}
```

### component_location!(Auth)

Standalone macro:
```rust
// Mark this file as Auth component
component_location!(Auth);

// With role
component_location!(Auth, role = developer);
```

Both generate metadata that can be collected for documentation.

---

## Extension Points

### Custom Metadata Fields

The parsing is extensible - new fields can be added to `diag.rs` by:
1. Adding to the field enum
2. Adding parsing logic
3. Adding code generation

### Integration with Doc Generator

When `<json, html>` is specified:
```rust
diag! {
    <json, html>,
    E.Auth.Token.001: { ... },
}
```

The macro generates registration calls:
```rust
// Auto-generated
inventory::submit! {
    ErrorDocRegistration { ... }
}
```

These are collected at link time by the doc generator.

---

## Related Documents

- [MACRO_GUIDE.md]MACRO_GUIDE.md - Complete usage guide for all macros
- [../DESIGN_RATIONALE.md]../../DESIGN_RATIONALE.md - Why design decisions were made
- [../../waddling-errors/docs/ARCHITECTURE.md]../../waddling-errors/docs/ARCHITECTURE.md - Core library architecture