#[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 strict_validation_demo --features metadata\n\
\n\
Or use --all-features to enable everything:\n\
\n\
cargo run --example strict_validation_demo --all-features\n\
"
);
use waddling_errors_macros::setup;
setup! {
components = crate::components,
primaries = crate::primaries,
sequences = crate::sequences,
}
pub mod sequences {
use waddling_errors_macros::sequence;
sequence! {
MISSING(1) {
description: "Required parameter is absent",
typical_severity: "Error",
hints: [
"Check if parameter was provided",
"Verify required fields are set",
],
},
INVALID(3) {
description: "Validation failed",
typical_severity: "Error",
hints: [
"Review validation rules",
"Check input format",
],
},
DENIED(8) {
description: "Access denied",
typical_severity: "Error",
hints: [
"Verify permissions",
"Check authorization",
],
},
EXPIRED(17) {
description: "Token or session expired",
typical_severity: "Error",
hints: [
"Refresh token",
"Re-authenticate",
],
},
NOT_FOUND(21) {
description: "Resource not found",
typical_severity: "Error",
hints: [
"Verify resource ID",
"Check if resource was deleted",
],
},
CONFLICT(23) {
description: "Concurrent modification conflict",
typical_severity: "Error",
hints: [
"Retry with latest version",
"Use optimistic locking",
],
},
EXHAUSTED(26) {
description: "Resource pool exhausted",
typical_severity: "Critical",
hints: [
"Scale up resources",
"Review capacity planning",
],
},
}
}
pub mod primaries {
use waddling_errors_macros::primary;
primary! {
pub enum Primary {
Token {
description: "Authentication token errors",
examples: [
"Missing JWT token",
"Invalid token signature",
"Expired token",
],
tags: ["authentication", "jwt", "security"],
related: ["Permission"],
},
Permission {
description: "Authorization and permission errors",
examples: [
"Insufficient permissions",
"Role not assigned",
"Scope not granted",
],
tags: ["authorization", "rbac", "security"],
related: ["Token"],
},
Connection {
description: "Database connection errors",
examples: [
"Connection pool exhausted",
"Connection timeout",
"Connection refused",
],
tags: ["database", "networking"],
},
Query {
description: "Database query errors",
examples: [
"Query timeout",
"Constraint violation",
"Deadlock detected",
],
tags: ["database", "sql"],
related: ["Connection"],
},
}
}
}
mod auth_component {
use waddling_errors_macros::component;
component! {
pub enum Component {
Auth {
docs: "Authentication and authorization system",
tags: ["security", "authentication"],
examples: [
"E.Auth.Token.001 - JWT token missing",
"E.Auth.Permission.008 - Access denied",
],
},
}
}
}
mod database_component {
use waddling_errors_macros::component;
component! {
pub enum Component {
Database {
docs: "Database operations and connections",
tags: ["database", "storage"],
examples: [
"E.Database.Connection.026 - Pool exhausted",
"E.Database.Query.023 - Conflict detected",
],
},
}
}
}
pub mod components {
pub use crate::auth_component::Auth;
pub use crate::database_component::Database;
}
mod full_strict_diagnostics {
use waddling_errors_macros::diag;
diag! {
strict(sequence, primary, component),
E.Auth.Token.MISSING: {
message: "JWT token missing from Authorization header",
description: "The request lacks a required JWT authentication token",
hints: [
"Add Authorization: Bearer <token> header",
"Verify token is included in request",
],
tags: ["authentication", "jwt"],
related_codes: ["E.Auth.Token.INVALID", "E.Auth.Token.EXPIRED"],
},
E.Auth.Token.INVALID: {
message: "JWT token signature validation failed",
description: "Token signature is invalid or corrupted",
hints: [
"Verify signing key is correct",
"Check token hasn't been tampered with",
],
tags: ["authentication", "jwt", "security"],
related_codes: ["E.Auth.Token.MISSING"],
},
E.Auth.Token.EXPIRED: {
message: "JWT token has expired",
description: "Token is past its expiration time",
hints: [
"Refresh authentication token",
"Use refresh token to obtain new access token",
],
tags: ["authentication", "jwt"],
related_codes: ["E.Auth.Token.MISSING"],
},
E.Auth.Permission.DENIED: {
message: "Insufficient permissions for operation",
description: "User lacks required permissions or role",
hints: [
"Verify user has required role",
"Check permission scopes",
"Contact administrator for access",
],
tags: ["authorization", "rbac"],
},
C.Database.Connection.EXHAUSTED: {
message: "Database connection pool exhausted",
description: "No available connections in the pool",
hints: [
"Scale up connection pool size",
"Review connection leak detection",
"Check for long-running transactions",
],
tags: ["database", "performance", "capacity"],
},
E.Database.Query.CONFLICT: {
message: "Concurrent modification detected",
description: "Version conflict or optimistic lock failure",
hints: [
"Retry operation with latest version",
"Implement exponential backoff",
"Review transaction isolation level",
],
tags: ["database", "concurrency"],
},
E.Database.Connection.NOT_FOUND: {
message: "Database connection not found",
description: "Requested connection ID does not exist",
hints: [
"Verify connection was established",
"Check if connection was closed",
],
tags: ["database"],
},
}
pub use C_DATABASE_CONNECTION_EXHAUSTED as FULL_CRIT_DB_EXHAUSTED;
pub use E_AUTH_TOKEN_INVALID as FULL_ERR_TOKEN_INVALID;
pub use E_AUTH_TOKEN_MISSING as FULL_ERR_TOKEN_MISSING;
}
mod sequence_only_diagnostics {
use waddling_errors_macros::diag;
diag! {
strict(sequence),
E.Auth.Token.MISSING: {
message: "JWT token missing (sequence-only validation)",
description: "This validates that MISSING exists in crate::sequences",
hints: ["Add Authorization header"],
},
E.Database.Query.CONFLICT: {
message: "Database conflict (sequence-only validation)",
description: "This validates that CONFLICT exists in crate::sequences",
hints: ["Retry with latest version"],
},
}
pub use E_AUTH_TOKEN_MISSING as SEQ_ONLY_TOKEN_MISSING;
pub use E_DATABASE_QUERY_CONFLICT as SEQ_ONLY_DB_CONFLICT;
}
mod sequence_primary_diagnostics {
use waddling_errors_macros::diag;
diag! {
strict(sequence, primary),
E.Auth.Token.EXPIRED: {
message: "Token expired (seq + primary validation)",
description: "Validates TOKEN in primaries and EXPIRED in sequences",
hints: ["Refresh token"],
},
E.Database.Connection.NOT_FOUND: {
message: "Connection not found (seq + primary validation)",
description: "Validates CONNECTION in primaries and NOT_FOUND in sequences",
hints: ["Verify connection was established"],
},
}
pub use E_AUTH_TOKEN_EXPIRED as SEQ_PRI_TOKEN_EXPIRED;
pub use E_DATABASE_CONNECTION_NOT_FOUND as SEQ_PRI_DB_NOT_FOUND;
}
mod relaxed_diagnostics {
use waddling_errors_macros::diag;
diag! {
relaxed,
E.Auth.Token.MISSING: {
message: "Token missing (relaxed mode)",
description: "This diagnostic doesn't validate references",
},
E.Database.Query.NOTFOUND: {
message: "Query result not found (relaxed mode)",
description: "Relaxed mode allows any sequence/primary/component names",
},
}
pub use E_AUTH_TOKEN_MISSING as RELAXED_TOKEN_MISSING;
pub use E_DATABASE_QUERY_NOTFOUND as RELAXED_QUERY_NOTFOUND;
}
fn main() {
println!("🦆 Granular Validation Demo");
println!("═══════════════════════════════════════════════════════════\n");
println!("📚 This example demonstrates:\n");
println!(" 1. ✅ Centralized sequences at crate::sequences");
println!(" 2. ✅ Centralized primaries at crate::primaries");
println!(" 3. ✅ Distributed components re-exported via crate::components");
println!(" 4. ✅ diag! granular validation - choose what to validate\n");
println!("═══════════════════════════════════════════════════════════");
println!("🔍 FULL VALIDATION: strict(sequence, primary, component)");
println!("═══════════════════════════════════════════════════════════\n");
println!("Validates all three at compile time:");
println!(" ✓ Sequences exist in crate::sequences");
println!(" ✓ Primaries exist in crate::primaries");
println!(" ✓ Components exist in crate::components\n");
use full_strict_diagnostics::*;
println!("Examples:");
println!(
" {} - {}",
FULL_ERR_TOKEN_MISSING.code, FULL_ERR_TOKEN_MISSING.message
);
println!(
" {} - {}",
FULL_ERR_TOKEN_INVALID.code, FULL_ERR_TOKEN_INVALID.message
);
println!(
" {} - {}",
FULL_CRIT_DB_EXHAUSTED.code, FULL_CRIT_DB_EXHAUSTED.message
);
println!();
println!("═══════════════════════════════════════════════════════════");
println!("🔢 SEQUENCE-ONLY: strict(sequence)");
println!("═══════════════════════════════════════════════════════════\n");
println!("Only validates sequences (most common use case):");
println!(" ✓ Catches typos in sequence numbers");
println!(" ✓ Ensures sequence constants exist");
println!(" ⊘ Skips primary and component validation\n");
use sequence_only_diagnostics::*;
println!("Examples:");
println!(
" {} - {}",
SEQ_ONLY_TOKEN_MISSING.code, SEQ_ONLY_TOKEN_MISSING.message
);
println!(
" {} - {}",
SEQ_ONLY_DB_CONFLICT.code, SEQ_ONLY_DB_CONFLICT.message
);
println!();
println!("═══════════════════════════════════════════════════════════");
println!("🎯 SEQUENCE + PRIMARY: strict(sequence, primary)");
println!("═══════════════════════════════════════════════════════════\n");
println!("Validates sequences and primaries:");
println!(" ✓ Validates sequence constants");
println!(" ✓ Validates primary constants");
println!(" ⊘ Skips component validation (useful for dynamic components)\n");
use sequence_primary_diagnostics::*;
println!("Examples:");
println!(
" {} - {}",
SEQ_PRI_TOKEN_EXPIRED.code, SEQ_PRI_TOKEN_EXPIRED.message
);
println!(
" {} - {}",
SEQ_PRI_DB_NOT_FOUND.code, SEQ_PRI_DB_NOT_FOUND.message
);
println!();
println!("═══════════════════════════════════════════════════════════");
println!("🔓 RELAXED MODE DIAGNOSTICS");
println!("═══════════════════════════════════════════════════════════\n");
println!("These diagnostics skip compile-time validation:");
println!(" 💡 No checks for sequence/primary existence");
println!(" 💡 Faster compilation, more flexible");
println!(" 💡 Useful when validation isn't needed or for dynamic scenarios\n");
use relaxed_diagnostics::*;
println!("Relaxed Diagnostics:");
println!(
" {} - {}",
RELAXED_TOKEN_MISSING.code, RELAXED_TOKEN_MISSING.message
);
println!(
" {} - {}",
RELAXED_QUERY_NOTFOUND.code, RELAXED_QUERY_NOTFOUND.message
);
println!();
println!("═══════════════════════════════════════════════════════════");
println!("✨ KEY TAKEAWAYS");
println!("═══════════════════════════════════════════════════════════\n");
println!("1. GRANULAR VALIDATION:");
println!(" ✅ strict(sequence, primary, component) - validate everything");
println!(" ✅ strict(sequence) - only validate sequences (most common)");
println!(" ✅ strict(sequence, primary) - sequences + primaries");
println!(" ✅ strict(component) - only components");
println!(" ✅ relaxed - no validation (maximum flexibility)\n");
println!("2. SEQUENCE HUB PATTERN:");
println!(" ✅ Define all sequences in crate::sequences module");
println!(" ✅ Use sequence! macro with imports for composition");
println!(" ✅ strict(sequence) validates crate::sequences::NAME exists\n");
println!("3. PRIMARY HUB PATTERN:");
println!(" ✅ Define all primaries in crate::primaries module");
println!(" ✅ primary! now generates constants (like sequence!)");
println!(" ✅ Example: pub const TOKEN: &str = \"TOKEN\";");
println!(" ✅ strict(primary) validates crate::primaries::NAME exists\n");
println!("4. COMPONENT HUB PATTERN:");
println!(" ✅ Define components in separate modules/files");
println!(" ✅ Re-export all through crate::components hub");
println!(" ✅ strict(component) validates crate::components::Name exists\n");
println!("5. WHEN TO USE EACH MODE:");
println!(" 📌 strict(sequence) → Most common, catches numeric typos");
println!(" 📌 strict(sequence, primary) → When both hubs are set up");
println!(" 📌 strict(sequence, primary, component) → Full validation");
println!(" 📌 relaxed → Prototyping, dynamic code, maximum flexibility\n");
println!("6. COMPILE-TIME SAFETY:");
println!(" If you reference a non-existent sequence/primary/component,");
println!(" the compiler will error immediately:");
println!(" \"cannot find value `TYPO` in module `crate::sequences`\"");
println!(" This catches errors at compile time, not runtime!\n");
println!("═══════════════════════════════════════════════════════════");
println!("🎯 RECOMMENDED PROJECT STRUCTURE");
println!("═══════════════════════════════════════════════════════════\n");
println!("src/");
println!(" sequences/");
println!(" mod.rs - Hub that imports/defines all sequences");
println!(" common.rs - Shared sequences (MISSING, INVALID, etc.)");
println!(" auth.rs - Auth-specific sequences");
println!(" database.rs - Database-specific sequences");
println!(" ");
println!(" primaries.rs - All primary categories (TOKEN, CONNECTION, etc.)");
println!(" ");
println!(" components/");
println!(" mod.rs - Hub that re-exports all components");
println!(" auth.rs - Auth component definition");
println!(" database.rs - Database component definition");
println!(" ");
println!(" errors/");
println!(" auth.rs - Auth error diagnostics (uses diag! strict)");
println!(" database.rs - Database error diagnostics (uses diag! strict)");
println!(" ");
println!(" lib.rs - Re-exports sequences, primaries, components\n");
println!("✅ Example complete! Check the source code for implementation details.");
}