waddling-errors 0.7.3

Structured, secure-by-default diagnostic codes for distributed systems with no_std and role-based documentation
Documentation
//! no_std Compatibility Example
//!
//! This example demonstrates that waddling-errors works WITHOUT the standard library.
//! The core library is no_std by default - the "std" feature is ONLY needed for
//! documentation generation.
//!
//! ## Key Points
//!
//! - waddling-errors is **no_std by default**
//! - All error code functionality works without heap allocation
//! - The "std" feature is only for doc-gen (HTML/JSON generation)
//! - Perfect for embedded systems, WASM, and constrained environments
//!
//! ## Build Commands
//!
//! ```bash
//! # Regular build (demonstrates no_std compatibility)
//! cargo run --example no_std_example
//!
//! # Pure no_std for WASM
//! cargo build --example no_std_example --target wasm32-unknown-unknown
//!
//! # Pure no_std for embedded (ARM)
//! cargo build --example no_std_example --target thumbv7em-none-eabihf
//! ```

use waddling_errors::{Code, ComponentId, PrimaryId, Severity};
use waddling_errors::{critical, error, success, warning};

// ============================================================================
// Define Components (no_std compatible)
// ============================================================================

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Component {
    Sensor,
    Actuator,
    Network,
    Storage,
}

impl ComponentId for Component {
    fn as_str(&self) -> &'static str {
        match self {
            Component::Sensor => "SENSOR",
            Component::Actuator => "ACTUATOR",
            Component::Network => "NETWORK",
            Component::Storage => "STORAGE",
        }
    }
}

// ============================================================================
// Define Primaries (no_std compatible)
// ============================================================================

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Primary {
    Timeout,
    Invalid,
    NotFound,
    Corrupted,
}

impl PrimaryId for Primary {
    fn as_str(&self) -> &'static str {
        match self {
            Primary::Timeout => "TIMEOUT",
            Primary::Invalid => "INVALID",
            Primary::NotFound => "NOTFOUND",
            Primary::Corrupted => "CORRUPTED",
        }
    }
}

// ============================================================================
// Define Error Codes (const fn - zero runtime cost)
// ============================================================================

const ERR_SENSOR_TIMEOUT: Code<Component, Primary> = error(Component::Sensor, Primary::Timeout, 1);

const ERR_SENSOR_INVALID: Code<Component, Primary> = error(Component::Sensor, Primary::Invalid, 3);

const ERR_ACTUATOR_NOTFOUND: Code<Component, Primary> =
    error(Component::Actuator, Primary::NotFound, 21);

const WARN_NETWORK_TIMEOUT: Code<Component, Primary> =
    warning(Component::Network, Primary::Timeout, 17);

const CRIT_STORAGE_CORRUPTED: Code<Component, Primary> =
    critical(Component::Storage, Primary::Corrupted, 25);

const SUCCESS_OPERATION_COMPLETE: Code<Component, Primary> =
    success(Component::Storage, Primary::NotFound, 999);

// ============================================================================
// Test Functions (all work WITHOUT std)
// ============================================================================

/// Test error code creation and access
fn test_error_codes() {
    let code = ERR_SENSOR_TIMEOUT;

    // All these operations work without heap allocation
    assert_eq!(code.severity(), Severity::Error);
    assert_eq!(code.component(), Component::Sensor);
    assert_eq!(code.primary(), Primary::Timeout);
    assert_eq!(code.sequence(), 1);
    assert_eq!(code.code(), "E.SENSOR.TIMEOUT.001");
}

/// Test ComponentId trait
fn test_component_id() {
    let comp = Component::Sensor;
    assert_eq!(comp.as_str(), "SENSOR");
}

/// Test PrimaryId trait
fn test_primary_id() {
    let prim = Primary::Timeout;
    assert_eq!(prim.as_str(), "TIMEOUT");
}

/// Test severity levels and all their methods
fn test_severity() {
    // Error severity
    let err_sev = ERR_SENSOR_TIMEOUT.severity();
    assert_eq!(err_sev, Severity::Error);
    assert!(err_sev.is_blocking());
    assert!(err_sev.is_negative());
    assert!(!err_sev.is_positive());
    assert_eq!(err_sev.priority(), 8);
    assert_eq!(err_sev.as_char(), 'E');

    // Warning severity
    let warn_sev = WARN_NETWORK_TIMEOUT.severity();
    assert_eq!(warn_sev, Severity::Warning);
    assert!(!warn_sev.is_blocking());
    assert!(warn_sev.is_negative());
    assert_eq!(warn_sev.priority(), 5);
    assert_eq!(warn_sev.as_char(), 'W');

    // Critical severity
    let crit_sev = CRIT_STORAGE_CORRUPTED.severity();
    assert_eq!(crit_sev, Severity::Critical);
    assert!(!crit_sev.is_blocking());
    assert!(crit_sev.is_negative());
    assert_eq!(crit_sev.priority(), 6);

    // Success severity
    let success_sev = SUCCESS_OPERATION_COMPLETE.severity();
    assert_eq!(success_sev, Severity::Success);
    assert!(!success_sev.is_blocking());
    assert!(!success_sev.is_negative());
    assert!(success_sev.is_positive());
    assert_eq!(success_sev.priority(), 3);
}

/// Test Result types with error codes
fn test_result_handling() -> Result<(), Code<Component, Primary>> {
    fn read_sensor() -> Result<u32, Code<Component, Primary>> {
        Err(ERR_SENSOR_TIMEOUT)
    }

    match read_sensor() {
        Ok(_) => Ok(()),
        Err(code) => {
            assert_eq!(code.component(), Component::Sensor);
            assert_eq!(code.primary(), Primary::Timeout);
            assert_eq!(code.sequence(), 1);
            Err(code)
        }
    }
}

/// Test Copy and Clone traits
fn test_copy_clone() {
    let err1 = ERR_SENSOR_TIMEOUT;
    let err2 = err1; // Copy
    let err3 = err1; // Clone

    assert_eq!(err1, err2);
    assert_eq!(err2, err3);
}

/// Test equality
fn test_equality() {
    let err1 = ERR_SENSOR_TIMEOUT;
    let err2 = error(Component::Sensor, Primary::Timeout, 1);
    assert_eq!(err1, err2);

    let err3 = ERR_SENSOR_INVALID;
    assert_ne!(err1, err3);
}

/// Test const fn (compile-time evaluation)
const CONST_ERROR: Code<Component, Primary> = error(Component::Sensor, Primary::Timeout, 1);

const fn const_fn_test() -> Code<Component, Primary> {
    error(Component::Network, Primary::Timeout, 1)
}

fn test_const_fn() {
    let _ = CONST_ERROR;
    let _ = const_fn_test();
}

// ============================================================================
// Main Function
// ============================================================================

fn main() {
    println!("🦆 waddling-errors no_std Compatibility Example");
    println!("=================================================\n");

    println!("💡 KEY INSIGHT: waddling-errors is no_std by default!");
    println!("   The core library works WITHOUT the standard library.");
    println!("   The 'std' feature is ONLY for doc generation.\n");

    println!("📋 Running no_std-compatible tests:\n");

    test_error_codes();
    println!("   ✓ Error code creation and access");

    test_component_id();
    println!("   ✓ ComponentId trait");

    test_primary_id();
    println!("   ✓ PrimaryId trait");

    test_severity();
    println!("   ✓ Severity levels and all methods");

    match test_result_handling() {
        Ok(()) => println!("   ✓ Result handling (unexpected)"),
        Err(_) => println!("   ✓ Result handling with error codes"),
    }

    test_copy_clone();
    println!("   ✓ Copy and Clone traits");

    test_equality();
    println!("   ✓ Equality comparison");

    test_const_fn();
    println!("   ✓ Const fn usage (compile-time evaluation)");

    println!("\n📊 Example Error Codes (all work in no_std):\n");

    println!(
        "   {}  (priority: {})",
        ERR_SENSOR_TIMEOUT.code(),
        ERR_SENSOR_TIMEOUT.severity().priority()
    );

    println!(
        "   {}  (priority: {})",
        ERR_SENSOR_INVALID.code(),
        ERR_SENSOR_INVALID.severity().priority()
    );

    println!(
        "   {}  (priority: {})",
        ERR_ACTUATOR_NOTFOUND.code(),
        ERR_ACTUATOR_NOTFOUND.severity().priority()
    );

    println!(
        "   {}  (priority: {})",
        WARN_NETWORK_TIMEOUT.code(),
        WARN_NETWORK_TIMEOUT.severity().priority()
    );

    println!(
        "   {}  (priority: {})",
        CRIT_STORAGE_CORRUPTED.code(),
        CRIT_STORAGE_CORRUPTED.severity().priority()
    );

    println!("\n🎯 What Works in no_std:");
    println!("   ✓ Error code creation (const fn, zero cost)");
    println!("   ✓ Component and Primary traits");
    println!("   ✓ All severity levels with full API");
    println!("   ✓ Code formatting without heap allocation");
    println!("   ✓ Result<T, Code> error handling");
    println!("   ✓ Copy, Clone, PartialEq, Debug traits");
    println!("   ✓ All operations are zero-cost abstractions");

    println!("\n❌ What Requires 'std' Feature:");
    println!("   • Documentation generation (HTML/JSON)");
    println!("   • DocRegistry and renderers");
    println!("   • Auto-registration system");
    println!("   • File I/O for doc output");

    println!("\n📦 Build Commands:");
    println!("   Regular:   cargo run --example no_std_example");
    println!("   WASM:      cargo build --example no_std_example --target wasm32-unknown-unknown");
    println!("   Embedded:  cargo build --example no_std_example --target thumbv7em-none-eabihf");

    println!("\n📝 Feature Flags:");
    println!("   std        - Only for doc-gen (NOT for core functionality)");
    println!("   metadata   - Compile-time metadata (needs paste crate)");
    println!("   doc-gen    - HTML/JSON generation (requires std)");
    println!("   hash       - Base62 hash codes (no_std compatible with ahash)");
    println!("   serde      - Serialization (no_std compatible)");

    println!("\n✨ All tests passed! Core library is fully no_std compatible.");
}