waddling_errors/
lib.rs

1//! Ultra-minimal diagnostic code system for the Waddling ecosystem
2//!
3//! Provides a standardized 4-part diagnostic code format:
4//!
5//! **Format**: `SEVERITY.COMPONENT.PRIMARY.SEQUENCE`  `E.CRYPTO.SALT.001`
6//!
7//! # Quick Start
8//!
9//! ## Using Macros (Recommended)
10//!
11//! ```rust,ignore
12//! use waddling_errors_macros::{component, diag, primary, sequence, setup};
13//!
14//! pub mod components {
15//!     use waddling_errors_macros::component;
16//!     component! { Auth { docs: "Authentication" } }
17//! }
18//!
19//! pub mod primaries {
20//!     use waddling_errors_macros::primary;
21//!     primary! { Token { docs: "Token errors" } }
22//! }
23//!
24//! pub mod sequences {
25//!     use waddling_errors_macros::sequence;
26//!     sequence! { EXPIRED(17) { description: "Token expired" } }
27//! }
28//!
29//! setup! {
30//!     components = crate::components,
31//!     primaries = crate::primaries,
32//!     sequences = crate::sequences,
33//! }
34//!
35//! diag! {
36//!     <json, html>, // Auto-register for doc generation
37//!     E.Auth.Token.EXPIRED: {
38//!         message: "JWT token expired at {{timestamp}}",
39//!         fields: [timestamp],
40//!         'CR 'Pub description: "Session expired. Please log in again.",
41//!         'R role: "Public",
42//!     },
43//! }
44//! ```
45//!
46//! See [waddling-errors-macros](https://docs.rs/waddling-errors-macros) for complete macro documentation.
47//!
48//! ## Manual Approach (Full Control)
49//!
50//! Define your component and primary enums:
51//!
52//! ```rust
53//! use waddling_errors::prelude::*;
54//!
55//! #[derive(Debug, Copy, Clone)]
56//! enum Component { Crypto, Network }
57//!
58//! impl ComponentId for Component {
59//!     fn as_str(&self) -> &'static str {
60//!         match self {
61//!             Component::Crypto => "CRYPTO",
62//!             Component::Network => "NETWORK",
63//!         }
64//!     }
65//! }
66//!
67//! #[derive(Debug, Copy, Clone)]
68//! enum Primary { Salt, Key, Timeout }
69//!
70//! impl PrimaryId for Primary {
71//!     fn as_str(&self) -> &'static str {
72//!         match self {
73//!             Primary::Salt => "SALT",
74//!             Primary::Key => "KEY",
75//!             Primary::Timeout => "TIMEOUT",
76//!         }
77//!     }
78//! }
79//!
80//! const ERR_SALT: Code<Component, Primary> = error(Component::Crypto, Primary::Salt, 1);
81//! assert_eq!(ERR_SALT.code(), "E.CRYPTO.SALT.001");
82//! ```
83//!
84//! # Sequence Conventions
85//!
86//! The Waddling ecosystem uses semantic sequence numbers:
87//!
88//! | Sequence | Meaning    | Example                           |
89//! |----------|------------|-----------------------------------|
90//! | 001      | MISSING    | Required item not provided        |
91//! | 002      | MISMATCH   | Values don't match expected type  |
92//! | 003      | INVALID    | Format/validation failed          |
93//! | 021      | NOTFOUND   | Resource not found                |
94//! | 025      | CORRUPTED  | Data corruption detected          |
95//! | 031-897  | (project)  | Domain-specific sequences         |
96//! | 999      | COMPLETE   | Full completion                   |
97//!
98//! See `docs/SEQUENCE-CONVENTIONS.md` for complete list.
99//!
100//! # Error Registry Pattern
101//!
102//! ```rust
103//! // errors.rs - Project error registry
104//! use waddling_errors::prelude::*;
105//!
106//! #[derive(Debug, Copy, Clone)]
107//! pub enum Component { Crypto, Parse }
108//!
109//! impl ComponentId for Component {
110//!     fn as_str(&self) -> &'static str {
111//!         match self {
112//!             Component::Crypto => "CRYPTO",
113//!             Component::Parse => "PARSE",
114//!         }
115//!     }
116//! }
117//!
118//! #[derive(Debug, Copy, Clone)]
119//! pub enum Primary { Salt, Length, Depr }
120//!
121//! impl PrimaryId for Primary {
122//!     fn as_str(&self) -> &'static str {
123//!         match self {
124//!             Primary::Salt => "SALT",
125//!             Primary::Length => "LENGTH",
126//!             Primary::Depr => "DEPR",
127//!         }
128//!     }
129//! }
130//!
131//! pub const SALT_MISSING: Code<Component, Primary> = error(Component::Crypto, Primary::Salt, 1);
132//! pub const KEY_LENGTH: Code<Component, Primary> = error(Component::Crypto, Primary::Length, 2);
133//! pub const DEPRECATED_SYNTAX: Code<Component, Primary> = warning(Component::Parse, Primary::Depr, 1);
134//! ```
135
136#![no_std]
137#![forbid(unsafe_code)]
138
139#[cfg(feature = "std")]
140extern crate std;
141
142#[cfg(not(feature = "std"))]
143extern crate alloc;
144
145mod code;
146mod severity;
147pub mod traits;
148
149#[cfg(feature = "metadata")]
150pub mod metadata;
151
152#[cfg(all(feature = "metadata", feature = "std"))]
153pub mod registry;
154
155#[cfg(feature = "doc-gen")]
156pub mod doc_generator;
157
158// Re-export procedural macros
159#[cfg(feature = "macros")]
160pub use waddling_errors_macros::*;
161
162pub use code::Code;
163pub use severity::Severity;
164pub use traits::{
165    ComponentId, ComponentIdDocumented, ErrorMetadata, FieldMeta, PrimaryId, PrimaryIdDocumented,
166    Role,
167};
168
169// Top-level convenience functions (generic over ComponentId/PrimaryId)
170
171/// Create an error code
172pub const fn error<C: ComponentId, P: PrimaryId>(
173    component: C,
174    primary: P,
175    sequence: u16,
176) -> Code<C, P> {
177    Code::error(component, primary, sequence)
178}
179
180/// Create a warning code
181pub const fn warning<C: ComponentId, P: PrimaryId>(
182    component: C,
183    primary: P,
184    sequence: u16,
185) -> Code<C, P> {
186    Code::warning(component, primary, sequence)
187}
188
189/// Create a critical code
190pub const fn critical<C: ComponentId, P: PrimaryId>(
191    component: C,
192    primary: P,
193    sequence: u16,
194) -> Code<C, P> {
195    Code::critical(component, primary, sequence)
196}
197
198/// Create a blocked code
199pub const fn blocked<C: ComponentId, P: PrimaryId>(
200    component: C,
201    primary: P,
202    sequence: u16,
203) -> Code<C, P> {
204    Code::blocked(component, primary, sequence)
205}
206
207/// Create a help code
208pub const fn help<C: ComponentId, P: PrimaryId>(
209    component: C,
210    primary: P,
211    sequence: u16,
212) -> Code<C, P> {
213    Code::help(component, primary, sequence)
214}
215
216/// Create a success code
217pub const fn success<C: ComponentId, P: PrimaryId>(
218    component: C,
219    primary: P,
220    sequence: u16,
221) -> Code<C, P> {
222    Code::success(component, primary, sequence)
223}
224
225/// Create a completed code
226pub const fn completed<C: ComponentId, P: PrimaryId>(
227    component: C,
228    primary: P,
229    sequence: u16,
230) -> Code<C, P> {
231    Code::completed(component, primary, sequence)
232}
233
234/// Create an info code
235pub const fn info<C: ComponentId, P: PrimaryId>(
236    component: C,
237    primary: P,
238    sequence: u16,
239) -> Code<C, P> {
240    Code::info(component, primary, sequence)
241}
242
243/// Create a trace code
244pub const fn trace<C: ComponentId, P: PrimaryId>(
245    component: C,
246    primary: P,
247    sequence: u16,
248) -> Code<C, P> {
249    Code::trace(component, primary, sequence)
250}
251
252// Prelude module
253
254/// Commonly used types and functions
255///
256/// ```rust
257/// use waddling_errors::prelude::*;
258///
259/// #[derive(Debug, Copy, Clone)]
260/// enum MyComponent { Auth, Database }
261///
262/// impl ComponentId for MyComponent {
263///     fn as_str(&self) -> &'static str {
264///         match self { MyComponent::Auth => "AUTH", MyComponent::Database => "DATABASE" }
265///     }
266/// }
267///
268/// #[derive(Debug, Copy, Clone)]
269/// enum MyPrimary { Token, Connection }
270///
271/// impl PrimaryId for MyPrimary {
272///     fn as_str(&self) -> &'static str {
273///         match self { MyPrimary::Token => "TOKEN", MyPrimary::Connection => "CONN" }
274///     }
275/// }
276///
277/// const ERR: Code<MyComponent, MyPrimary> = error(MyComponent::Auth, MyPrimary::Token, 1);
278/// ```
279/// Prelude module for convenient imports
280pub mod prelude {
281    pub use crate::{Code, Severity};
282    pub use crate::{ComponentId, PrimaryId};
283    pub use crate::{blocked, completed, critical, error, help, info, success, trace, warning};
284}