#![allow(non_upper_case_globals)]
#[cfg(not(feature = "metadata"))]
compile_error!(
"\n\n\
โ This example requires the 'metadata' feature!\n\
\n\
The diag! macro generates DiagnosticRuntime structs that include\n\
role-gated fields (hints_runtime_gated, hints_both_gated, etc.)\n\
which are only compiled when the 'metadata' feature is enabled.\n\
\n\
Run this example with:\n\
\n\
cargo run --example no_std_wasm --features metadata\n\
\n\
Or use --all-features to enable everything:\n\
\n\
cargo run --example no_std_wasm --all-features\n\
"
);
#[cfg(feature = "metadata")]
use waddling_errors::{Code, Severity};
#[cfg(feature = "metadata")]
use waddling_errors_macros::{diag, setup};
#[cfg(feature = "metadata")]
pub mod components {
use waddling_errors_macros::component;
component! {
pub enum Component {
Sensor {
docs: "Sensor reading and monitoring",
tags: ["hardware", "io"],
},
Actuator {
docs: "Actuator control and feedback",
tags: ["hardware", "control"],
},
Network {
docs: "Network communication",
tags: ["Network", "communication"],
},
Storage {
docs: "Data persistence",
tags: ["Storage", "persistence"],
},
}
}
pub use Component::*;
}
#[cfg(feature = "metadata")]
pub mod primaries {
use waddling_errors_macros::primary;
primary! {
pub enum Primary {
Timeout {
description: "Operation timed out",
tags: ["Timeout", "async"],
},
Invalid {
description: "Invalid data or state",
tags: ["validation"],
},
NotFound {
description: "Resource not found",
tags: ["missing"],
},
Corrupted {
description: "Data corruption detected",
tags: ["integrity"],
},
}
}
pub use Primary::*;
}
#[cfg(feature = "metadata")]
pub mod sequences {
use waddling_errors_macros::sequence;
sequence! {
MISSING(1) {
description: "Sensor reading missing",
typical_severity: "Error",
hints: ["Check sensor connection"],
},
INVALID(2) {
description: "Sensor reading invalid",
typical_severity: "Error",
hints: ["Validate sensor data"],
},
TIMEOUT(3) {
description: "Sensor read timeout",
typical_severity: "Error",
hints: ["Increase timeout value"],
},
CALIBRATION(4) {
description: "Sensor calibration error",
typical_severity: "Warning",
hints: ["Run calibration procedure"],
},
}
}
#[cfg(feature = "metadata")]
setup! {
components = crate::components,
primaries = crate::primaries,
sequences = crate::sequences,
}
#[cfg(feature = "metadata")]
diag! {
strict(component, primary, sequence, naming, duplicates, sequence_values, string_values),
E.Sensor.Timeout.TIMEOUT: {
message: "Sensor read operation timed out after waiting",
hints: ["Increase timeout duration", "Check sensor connection"],
tags: ["hardware", "Timeout"],
},
}
#[cfg(feature = "metadata")]
diag! {
strict(component, primary, sequence, naming, duplicates, sequence_values, string_values),
E.Sensor.Invalid.INVALID: {
message: "Sensor returned invalid data",
hints: ["Check sensor calibration", "Verify sensor is operational"],
tags: ["hardware", "validation"],
},
}
#[cfg(feature = "metadata")]
diag! {
strict(component, primary, sequence, naming, duplicates, sequence_values, string_values),
W.Sensor.Timeout.MISSING: {
message: "Sensor data is missing but operation can continue",
hints: ["Sensor may be disconnected"],
tags: ["hardware", "warning"],
},
}
#[cfg(feature = "metadata")]
diag! {
strict(component, primary, sequence, naming, duplicates, sequence_values, string_values),
C.Network.Timeout.TIMEOUT: {
message: "Network connection timeout - critical service unavailable",
hints: ["Check network connectivity", "Verify service is running"],
tags: ["Network", "critical"],
},
}
#[cfg(feature = "metadata")]
diag! {
strict(component, primary, sequence, naming, duplicates, sequence_values, string_values),
E.Storage.Corrupted.CALIBRATION: {
message: "Storage data corruption detected",
hints: ["Run data integrity check", "Restore from backup"],
tags: ["Storage", "integrity"],
},
}
#[cfg(feature = "metadata")]
fn test_macro_generated_types() {
use crate::components::Component;
use crate::primaries::Primary;
use waddling_errors::{ComponentId, PrimaryId};
assert_eq!(Component::Sensor.as_str(), "Sensor");
assert_eq!(Component::Actuator.as_str(), "Actuator");
assert_eq!(Component::Network.as_str(), "Network");
assert_eq!(Component::Storage.as_str(), "Storage");
assert_eq!(Primary::Timeout.as_str(), "Timeout");
assert_eq!(Primary::Invalid.as_str(), "Invalid");
assert_eq!(Primary::NotFound.as_str(), "NotFound");
assert_eq!(Primary::Corrupted.as_str(), "Corrupted");
assert_eq!(sequences::MISSING, 1);
assert_eq!(sequences::INVALID, 2);
assert_eq!(sequences::TIMEOUT, 3);
assert_eq!(sequences::CALIBRATION, 4);
}
#[cfg(feature = "metadata")]
fn test_error_codes_with_macros() {
use crate::components::Component;
use crate::primaries::Primary;
use waddling_errors::{Code, error, warning};
let sensor_err: Code<Component, Primary> =
error(Component::Sensor, Primary::Timeout, sequences::TIMEOUT);
assert_eq!(sensor_err.code(), "E.Sensor.Timeout.003");
assert_eq!(sensor_err.severity(), Severity::Error);
assert_eq!(sensor_err.sequence(), 3);
let sensor_warn: Code<Component, Primary> =
warning(Component::Sensor, Primary::Invalid, sequences::INVALID);
assert_eq!(sensor_warn.code(), "W.Sensor.Invalid.002");
assert_eq!(sensor_warn.severity(), Severity::Warning);
}
#[cfg(feature = "metadata")]
fn test_diagnostic_constants() {
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.code, "E.Sensor.Timeout.TIMEOUT");
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.severity, Severity::Error);
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.component, "Sensor");
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.primary, "Timeout");
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.sequence, "TIMEOUT");
assert_eq!(
E_SENSOR_TIMEOUT_TIMEOUT.message,
"Sensor read operation timed out after waiting"
);
#[cfg(feature = "metadata")]
{
assert!(!E_SENSOR_TIMEOUT_TIMEOUT.hints_both_gated.is_empty());
assert_eq!(
E_SENSOR_TIMEOUT_TIMEOUT.hints_both_gated[0].0,
"Increase timeout duration"
);
}
#[cfg(feature = "metadata")]
{
assert!(!E_SENSOR_TIMEOUT_TIMEOUT.tags_gated.is_empty());
assert_eq!(E_SENSOR_TIMEOUT_TIMEOUT.tags_gated[0].0, "hardware");
}
assert_eq!(E_SENSOR_INVALID_INVALID.code, "E.Sensor.Invalid.INVALID");
assert_eq!(E_SENSOR_INVALID_INVALID.severity, Severity::Error);
assert_eq!(W_SENSOR_TIMEOUT_MISSING.code, "W.Sensor.Timeout.MISSING");
assert_eq!(W_SENSOR_TIMEOUT_MISSING.severity, Severity::Warning);
assert_eq!(C_NETWORK_TIMEOUT_TIMEOUT.code, "C.Network.Timeout.TIMEOUT");
assert_eq!(C_NETWORK_TIMEOUT_TIMEOUT.severity, Severity::Critical);
}
#[cfg(feature = "metadata")]
fn test_trait_implementations() {
use crate::components::Component;
use crate::primaries::Primary;
let comp1 = Component::Sensor;
let comp2 = comp1;
assert_eq!(comp1, comp2);
let prim1 = Primary::Timeout;
let prim2 = prim1;
assert_eq!(prim1, prim2);
assert_ne!(Component::Network, Component::Storage);
let _debug = format!("{:?}", Component::Sensor);
}
#[cfg(feature = "metadata")]
fn simulate_sensor_read() -> Result<u32, Code<components::Component, primaries::Primary>> {
use crate::components::Component;
use crate::primaries::Primary;
use waddling_errors::error;
Err(error(
Component::Sensor,
Primary::Timeout,
sequences::TIMEOUT,
))
}
#[cfg(feature = "metadata")]
fn test_result_handling() {
use crate::components::Component;
use crate::primaries::Primary;
match simulate_sensor_read() {
Ok(value) => println!(" Sensor value: {}", value),
Err(code) => {
assert_eq!(code.component(), Component::Sensor);
assert_eq!(code.primary(), Primary::Timeout);
assert_eq!(code.code(), "E.Sensor.Timeout.003");
println!(" โ Result handling with macro-generated types");
}
}
}
#[cfg(feature = "metadata")]
fn main() {
println!("๐ฆ waddling-errors-macros: Build-time std, Runtime no_std");
println!("===========================================================\n");
println!("๐ก KEY CONCEPT:");
println!(" โข Macros run at BUILD TIME with std (on your dev machine)");
println!(" โข Generated code runs at RUNTIME in no_std (embedded/WASM)");
println!(" โข This is how serde, embedded-hal, and many crates work!\n");
println!("๐ง What Happens at BUILD TIME (std environment):");
println!(" โ component! macro expands to enum + ComponentId impl");
println!(" โ primary! macro expands to enum + PrimaryId impl");
println!(" โ sequence! macro expands to const u16 values");
println!(" โ Doc generation (HTML/JSON) if doc-gen feature enabled");
println!(" โ Auto-registration if auto-register feature enabled");
println!(" โ All macro expansion happens with std available\n");
println!("๐ What Happens at RUNTIME (no_std compatible):");
println!(" โ Generated enums and consts (zero cost)");
println!(" โ ComponentId and PrimaryId trait impls");
println!(" โ Code<Component, Primary> error codes");
println!(" โ No heap allocations");
println!(" โ No std dependency");
println!(" โ Works in embedded/WASM/bare metal\n");
println!("๐ Running tests with macro-generated code:\n");
test_macro_generated_types();
println!(" โ Macro-generated Component and Primary enums");
println!(" โ Macro-generated sequence constants");
test_error_codes_with_macros();
println!(" โ Error codes with macro types");
test_diagnostic_constants();
println!(" โ Diagnostic constants from diag! macro");
test_trait_implementations();
println!(" โ Clone, Copy, PartialEq, Debug traits");
test_result_handling();
println!("\n๐ฏ Generated Code Structure:");
println!(" component! {{ Sensor {{ ... }} }}");
println!(" โ EXPANDS TO (at compile time):");
println!(" #[derive(Debug, Copy, Clone, PartialEq, Eq)]");
println!(" pub enum Component {{ Sensor, ... }}");
println!(" impl ComponentId for Component {{ ... }}");
println!(" โ RESULT (no_std compatible at runtime!)");
println!("\n diag! {{ E.Sensor.Timeout.TIMEOUT: {{ message: \"...\", ... }}, }}");
println!(" โ EXPANDS TO (at compile time):");
println!(" pub const E_SENSOR_TIMEOUT_TIMEOUT: DiagnosticRuntime = ...");
println!(" โ RESULT (no_std compatible DiagnosticRuntime constant!)");
println!("\nโจ Macros You Can Use:");
println!(" component! - Generate Component enum (no_std output)");
println!(" primary! - Generate Primary enum (no_std output)");
println!(" sequence! - Generate const u16 values (no_std output)");
println!(" diag! - Generate DiagnosticRuntime constants (no_std output)");
println!("\n๐ฆ For Embedded/WASM Deployment:");
println!(" 1. Use macros in your crate (they run at build time with std)");
println!(" 2. Mark your crate #![no_std] for runtime");
println!(" 3. Generated code works without std!");
println!(" 4. Optional: Enable doc-gen at build time for documentation");
println!("\n๐ฌ Example User Crate Pattern:");
println!(" // user_embedded_crate/src/lib.rs");
println!(" #![no_std] // Runtime is no_std!");
println!(" ");
println!(" use waddling_errors_macros::{{component, primary}};");
println!(" ");
println!(" // Macros run at build time (with std)");
println!(" component! {{ Motor {{ value: \"MOTOR\", ... }} }}");
println!(" ");
println!(" // Generated code works in no_std at runtime!");
println!(" fn read_motor() -> Result<u32, Code<Component, Primary>> {{ ... }}");
println!("\n๐ Build vs Runtime Separation:");
println!(" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
println!(" โ BUILD TIME (std on dev machine) โ");
println!(" โ โข Macros expand โ");
println!(" โ โข Doc generation (optional) โ");
println!(" โ โข Code generation โ");
println!(" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
println!(" โ");
println!(" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
println!(" โ RUNTIME (no_std on target device) โ");
println!(" โ โข Generated enums and consts โ");
println!(" โ โข Error codes (zero cost) โ");
println!(" โ โข No heap, no std โ");
println!(" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
println!("\nโ
All tests passed!");
println!(" Macro-generated code is fully no_std compatible at runtime!");
println!("\n๐งช WASM Testing:");
println!(" To actually test in WASM environment:");
println!(" 1. cargo build --example no_std_wasm --target wasm32-unknown-unknown");
println!(" 2. Use wasm-bindgen to create JS bindings");
println!(" 3. Run in browser or Node.js");
println!(" ");
println!(" Or for WASI (WASM with minimal system interface):");
println!(" cargo build --example no_std_wasm --target wasm32-wasi");
println!(" wasmtime target/wasm32-wasi/debug/examples/no_std_wasm.wasm");
}
#[cfg(all(target_family = "wasm", feature = "metadata"))]
#[unsafe(no_mangle)]
pub extern "C" fn run_tests() -> i32 {
test_macro_generated_types();
test_error_codes_with_macros();
test_diagnostic_constants();
test_trait_implementations();
0
}
#[cfg(not(feature = "metadata"))]
fn main() {}