waddling-errors-hash 0.5.0

Hash computation utilities for waddling-errors (shared between runtime and proc-macros)
Documentation
# waddling-errors-hash


> Deterministic hash computation for waddling-errors diagnostic codes

This is a shared utility crate that provides hash computation functionality for the `waddling-errors` ecosystem. It exists to enable **compile-time hash embedding** in procedural macros while keeping the same hash algorithm available at runtime.

## Why Does This Crate Exist?


The `waddling-errors` system needs to compute short, deterministic hashes for error codes (e.g., `E.AUTH.TOKEN.001` → `hCF3I`). These hashes are used for:

- **Compact logging**: Save space in logs with 5-char identifiers
- **Network protocols**: Efficient error transmission
- **Quick lookups**: Fast error code search and correlation
- **URL-safe identifiers**: Safe for all systems (alphanumeric only)

### The Problem


Procedural macros (like `diag!`) run in a separate compilation context from your runtime code. They can't directly use your runtime library's functions. So if we want to compute hashes **at compile time** (for zero runtime cost), we need the hash logic in a place both can access.

### The Solution


`waddling-errors-hash` is a small, standalone crate that:
1. ✅ Can be used by proc macros at compile time
2. ✅ Can be used by the runtime library
3. ✅ Keeps the hash algorithm consistent between both
4. ✅ Has minimal dependencies (`ahash` only)
5. ✅ Is `no_std` compatible

## Architecture


```
┌─────────────────────────────────┐
│  waddling-errors-macros         │
│  (proc macro - compile time)    │
│                                 │
│  uses hash to embed constants   │
└────────────┬────────────────────┘
             │  depends on
┌─────────────────────────────────┐
│  waddling-errors-hash           │◄─────────┐
│  (pure computation)             │          │
│                                 │          │ depends on
│  • compute_hash()               │          │
│  • verify_hash()                │          │
└─────────────────────────────────┘          │
             ▲                               │
             │  depends on                   │
             │                               │
┌────────────┴────────────────────┐          │
│  waddling-errors                │──────────┘
│  (runtime library)              │
│                                 │
│  uses hash for doc generation   │
└─────────────────────────────────┘
```

## What Features Does This Give Users?


### 1. **Zero Runtime Cost Hashes**


```rust
use waddling_errors_macros::diag;

diag! {
    E.AUTH.TOKEN.001: {
        message: "Token expired",
    }
}

fn main() {
    // Hash was computed at compile time!
    println!("{}", E_AUTH_TOKEN_001_HASH); // "hCF3I"
    
    // No runtime computation needed ✅
    // No ahash dependency in binary (unless you enable hash feature)
}
```

**Benefit**: Every error code gets a hash constant for free, computed once at build time.

### 2. **Deterministic Across Builds**


The same error code always produces the same hash, regardless of:
- Platform (Windows, Linux, macOS)
- Rust version
- Build configuration
- Time of compilation

**Benefit**: Hashes can be used in documentation, APIs, and protocols without changing.

### 3. **Optional Runtime Verification**


```rust
#[cfg(feature = "hash")]

{
    use waddling_errors_hash::{compute_hash, verify_hash};
    
    // Verify hash matches code
    assert!(verify_hash("E.AUTH.TOKEN.001", "hCF3I"));
    
    // Compute new hash if needed
    let hash = compute_hash("E.AUTH.TOKEN.002");
}
```

**Benefit**: Can validate hashes at runtime if needed, but not required.

### 4. **Compact Error Representation**


```json
// Instead of sending full error in network protocol:
{
  "error": "E.AUTH.TOKEN.001",
  "message": "The JWT token has expired..."
}

// Send compact version:
{
  "h": "hCF3I",
  "f": { "user_id": 123 }
}
```

Client looks up the hash in a catalog to get full message/docs.

**Benefit**: Reduced bandwidth, i18n on client, security (no sensitive info in errors).

## What Burden Does This Put on Users?


### For End Users: **Zero Burden** 🎉


If you just use `waddling-errors`:
- ✅ Hash computation happens automatically at compile time
- ✅ Hash constants are always available (e.g., `E_AUTH_TOKEN_001_HASH`)
- ✅ No extra dependencies in your binary (unless you enable `hash` feature)
- ✅ No performance overhead
- ✅ Nothing to configure

Example:
```rust
use waddling_errors_macros::diag;

diag! {
    E.AUTH.TOKEN.001: { message: "Token expired" }
}

fn main() {
    println!("{}", E_AUTH_TOKEN_001_HASH); // Just works!
}
```

### For Library Maintainers: **Minimal** 


The only "burden" is having one extra crate in the workspace:

**Pros:**
- ✅ Clean separation of concerns
- ✅ Proc macros can compute hashes at compile time
- ✅ Runtime library can use same algorithm
- ✅ Easy to test in isolation
- ✅ Can be versioned independently if needed

**Cons:**
- ❌ One extra crate in workspace (adds ~200 lines of code)
- ❌ Slightly more complex dependency graph

But this complexity is **internal** - users never see it!

## Algorithm Details


- **Hash Function**: `ahash` with fixed seed (`"Waddling"`)
- **Output Length**: 5 characters
- **Character Set**: Base62 (0-9, A-Z, a-z)
- **Collision Space**: 916,132,832 combinations (62^5)
- **Deterministic**: Yes - same input always produces same output
- **Performance**: ~50ns per hash on modern CPUs

## Usage Examples

### In Proc Macros (Compile Time)


```rust
// In waddling-errors-macros/src/diag.rs
use waddling_errors_hash::compute_hash;

let code = "E.AUTH.TOKEN.001";
let hash = compute_hash(code); // Computed at compile time
let hash_const = quote! {
    pub const E_AUTH_TOKEN_001_HASH: &str = #hash;
};
```

### At Runtime


```rust
use waddling_errors_hash::compute_hash;

fn log_error(code: &str) {
    let hash = compute_hash(code);
    println!("[{}] Error: {}", hash, code);
}
```

### Verification


```rust
use waddling_errors_hash::verify_hash;

assert!(verify_hash("E.AUTH.TOKEN.001", "hCF3I"));
```

## Testing


```bash
# Run all tests

cargo test -p waddling-errors-hash

# Test with no_std

cargo test -p waddling-errors-hash --no-default-features
```

## Feature Flags


- `default = ["std"]`
- `std`: Enable standard library support (disable for `no_std`)

## License


MIT OR Apache-2.0

## See Also


- [`waddling-errors`]../waddling-errors/ - Main error handling library
- [`waddling-errors-macros`]../waddling-errors-macros/ - Procedural macros