waddling-errors 0.6.1

Ultra-minimal error code standard for the Waddling ecosystem
Documentation

waddling-errors 🦆

Type-safe diagnostic code system with structured error codes

Crates.io Documentation License


Overview

waddling-errors provides structured diagnostic codes with a consistent 4-part format:

SEVERITY.COMPONENT.PRIMARY.SEQUENCE
E.AUTH.TOKEN.001    // Error in Auth component, Token category, sequence 001
W.PARSER.SYNTAX.003 // Warning in Parser component, Syntax category, sequence 003
S.BUILD.DONE.999    // Success in Build component, Done category, sequence 999

Generated Documentation

Error Documentation Screenshot Auto-generated role-based error documentation with severity filtering, search, and detailed hints

Key Features

  • ✅ Type-safe - Define your own component/primary enums with compile-time checking
  • ✅ Zero runtime dependencies - Pure Rust with optional features (proc macros are compile-time only)
  • ✅ Semantic methods - is_blocking(), is_positive(), priority() for intelligent error handling
  • ✅ Documentation generation - Auto-generate JSON/HTML/Catalog docs with role-based filtering
  • ✅ Hash codes - Optional 5-character base62 hashes for compact logging
  • ✅ Network efficiency - Catalog renderer for 80% smaller payloads (IoT/mobile)
  • ✅ no_std compatible - Works in embedded and WASM environments

Installation

[dependencies]

# Default (no_std + alloc compatible, includes macros)

waddling-errors = "0.5"



# With documentation generation (requires std)

waddling-errors = { version = "0.5", features = ["std", "doc-gen", "hash", "serde"] }



# Pure no_std (no allocator)

waddling-errors = { version = "0.5", default-features = false }



# For procedural macros separately

waddling-errors-macros = "0.5"

Default features: ["macros"] - Works in no_std + alloc environments.

See docs/FEATURE_FLAGS.md for detailed feature information.


Quick Start

Macro Approach (Recommended)

Minimal boilerplate with automatic documentation generation:

use waddling_errors_macros::{component, primary, diag};

// Define your error structure
component! { Auth { value: "AUTH", docs: "Authentication" } }
primary! { Token { value: "TOKEN", docs: "Token errors" } }

// Define diagnostics with auto-registration
diag! {
    <json, html>,  // Auto-register for doc generation
    
    E.AUTH.TOKEN.EXPIRED: {
        message: "JWT token expired at {{timestamp}}",
        fields: [timestamp],
        
        'CR 'Pub description: "Your session has expired. Please log in again.",
        'CR 'Dev hints: ["Check token refresh logic", "Verify server time sync"],
        
        'R role: "Public",
        'R tags: ["auth", "security"],
    },
}

// Use in your code
let error = E_AUTH_TOKEN_EXPIRED;
println!("{}", error.runtime.full_code());  // "E.AUTH.TOKEN.EXPIRED"

See waddling-errors-macros for complete macro documentation.

Manual Approach (Full Control)

For maximum flexibility, use the core trait-based approach:

use waddling_errors::prelude::*;

// 1. Define your error structure
#[derive(Debug, Copy, Clone)]
enum Component { Auth, Parser, Database }

impl ComponentId for Component {
    fn as_str(&self) -> &'static str {
        match self {
            Component::Auth => "AUTH",
            Component::Parser => "PARSER",
            Component::Database => "DB",
        }
    }
}

#[derive(Debug, Copy, Clone)]
enum Primary { Token, Syntax, Connection }

impl PrimaryId for Primary {
    fn as_str(&self) -> &'static str {
        match self {
            Primary::Token => "TOKEN",
            Primary::Syntax => "SYNTAX",
            Primary::Connection => "CONN",
        }
    }
}

// 2. Create error codes
const ERR_TOKEN_MISSING: Code<Component, Primary> = 
    Code::error(Component::Auth, Primary::Token, 1);

// 3. Use them
fn authenticate(token: Option<&str>) -> Result<(), Code<Component, Primary>> {
    token.ok_or(ERR_TOKEN_MISSING)?;
    Ok(())
}

fn main() {
    println!("{}", ERR_TOKEN_MISSING.code());  // "E.AUTH.TOKEN.001"
    println!("Priority: {}", ERR_TOKEN_MISSING.severity().priority());  // 8
    println!("Blocking? {}", ERR_TOKEN_MISSING.severity().is_blocking());  // true
}

Severity Levels

Nine severity levels with semantic methods:

Severity Code Priority Blocking Use Case
Error E 8 Yes Invalid input, logic errors
Blocked B 7 Yes Deadlock, I/O wait, network down
Critical C 6 No Data corruption, resource exhaustion
Warning W 5 No Deprecated API, edge cases
Help H 4 No Helpful suggestions, tips
Success S 3 No Operation succeeded
Completed K 2 No Task/phase finished
Info I 1 No Events, milestones, status
Trace T 0 No Execution traces, probes, timing
let severity = Severity::Error;

severity.is_blocking();   // true - stops execution
severity.is_negative();   // true - indicates failure
severity.is_positive();   // false
severity.priority();      // 8 (0-8 scale)

Optional emoji/ANSI color support available with features. See FEATURE_FLAGS.md.


Documentation Generation

Generate searchable HTML and JSON documentation with automatic registration:

Step 1: Define Errors with Auto-Registration

// src/errors/mod.rs
use waddling_errors_macros::diag;

diag! {
    <json, html>,  // Auto-register when loaded
    
    E.AUTH.TOKEN.MISSING: {
        message: "JWT token missing",
        'CR 'Pub description: "Authorization header not found",
        'CR 'Dev hints: ["Include Authorization: Bearer <token>"],
        'R role: "Public",
    },
}

Step 2: Create Doc Generation Binary

// src/bin/doc_gen.rs
use my_app::errors::*;  // Loads errors, triggers auto-registration
use waddling_errors::doc_generator::{DocRegistry, HtmlRenderer, JsonRenderer};
use waddling_errors::registry;

fn main() {
    let mut doc_registry = DocRegistry::new(
        env!("CARGO_PKG_NAME"),
        env!("CARGO_PKG_VERSION")
    );
    
    // Auto-registered diagnostics are loaded into global registry
    registry::register_all_with_doc_gen(&mut doc_registry);
    
    // Generate documentation
    doc_registry.render_all_roles(
        vec![Box::new(HtmlRenderer::new()), Box::new(JsonRenderer)],
        "target/docs"
    ).unwrap();
    
    println!("✅ Documentation generated in target/docs/");
}

Step 3: Configure in Cargo.toml

[[bin]]

name = "doc-gen"

path = "src/bin/doc_gen.rs"

required-features = ["doc-gen", "auto-register"]

Step 4: Generate Documentation

cargo run --bin doc-gen --features doc-gen,auto-register

Generates:

  • myapp-pub.html, myapp-pub.json - Public documentation
  • myapp-dev.html, myapp-dev.json - Developer documentation
  • myapp-int.html, myapp-int.json - Internal documentation

Documentation Roles:

  • Role::Public - End-user facing errors (sanitized, safe)
  • Role::Developer - For contributors (debugging context)
  • Role::Internal - Full team visibility (sensitive details)

Key Benefits:

  • ✅ Zero boilerplate - auto-registration handles everything
  • ✅ Separate binary - no doc-gen overhead in production
  • ✅ Clean main - no error imports polluting your app

See docs/DOC_GENERATION_GUIDE.md for complete guide.


Network Efficiency (Catalog Renderer)

Generate compact catalogs for efficient error transmission:

use waddling_errors::doc_generator::{CatalogRenderer, CatalogFormat};

// Generate hash-to-error catalog
let catalog = CatalogRenderer::new(CatalogFormat::Compact);
registry.render(vec![Box::new(catalog)], "target/catalog")?;

// Server sends: {"h":"jGKFp","f":{"temp":"45.2"}}  (40 bytes)
// Client expands: "Temperature 45.2°C exceeds threshold"

Benefits:

  • 80% smaller network payloads for IoT/mobile
  • Multi-language support (same hash, different catalogs)
  • Offline-first apps (cache catalog locally)

See docs/CATALOG_GUIDE.md for complete guide.


no_std Support

The library is no_std compatible by default and works in embedded/WASM environments:

Default (no_std + alloc):

[dependencies]

waddling-errors = "0.5"  # Works with allocator

Pure no_std (no allocator):

[dependencies]

waddling-errors = { version = "0.5", default-features = false }

Example:

#![no_std]
extern crate alloc;

use waddling_errors::prelude::*;

// Works without std!
const ERR: Code<Component, Primary> = Code::error(Component::Auth, Primary::Token, 1);

For documentation generation (requires std):

waddling-errors = { version = "0.5", features = ["std", "doc-gen", "metadata"] }


Hash Codes

Enable 5-character base62 hashes for compact logging:

waddling-errors = { version = "0.5", features = ["hash"] }

const ERR: Code<Component, Primary> = Code::error(Component::Auth, Primary::Token, 1);

println!("{} → #{}", ERR.code(), ERR.hash());
// E.AUTH.TOKEN.001 → #jGKFp

// Use in logs for quick searches
log::error!("#{} Authentication failed", ERR.hash());

Sequence Conventions

Semantic sequence numbers provide consistency across projects:

Sequence Meaning Example
001 MISSING Required item not provided
003 INVALID Format/validation failed
007 DUPLICATE Rate limit or duplicate entry
008 DENIED Permission/access denied
021 NOTFOUND Resource not found
025 CORRUPTED Data corruption detected
999 COMPLETE Full completion

See docs/SEQUENCE-CONVENTIONS.md for the complete list.


Examples

Basic usage:

cargo run --example trait_based_enums

With documentation metadata:

cargo run --example trait_based_documented

Production pattern (6 components, 31 errors, role-based docs):

cargo run --example complete_system --features "doc-gen,hash"

HTML customization:

cargo run --example html_customization_demo --features "doc-gen,metadata"

no_std/WASM:

# Pure no_std

cargo build --example wasm_minimal --target wasm32-unknown-unknown --no-default-features


# With no_std example

cargo run --example no_std_example --no-default-features

See examples/ directory for all examples.


Documentation

User Guides

API Reference

Related Crates


License

Dual-licensed under MIT or Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.