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// Internal utilities for macros - Hygiene support
159#[doc(hidden)]
160pub mod internal {
161    #[cfg(feature = "auto-register")]
162    pub use ctor;
163}
164
165// Re-export procedural macros
166#[cfg(feature = "macros")]
167pub use waddling_errors_macros::*;
168
169pub use code::Code;
170pub use severity::Severity;
171pub use traits::{
172    ComponentId, ComponentIdDocumented, ErrorMetadata, FieldMeta, PrimaryId, PrimaryIdDocumented,
173    Role,
174};
175
176// Top-level convenience functions (generic over ComponentId/PrimaryId)
177
178/// Create an error code
179pub const fn error<C: ComponentId, P: PrimaryId>(
180    component: C,
181    primary: P,
182    sequence: u16,
183) -> Code<C, P> {
184    Code::error(component, primary, sequence)
185}
186
187/// Create a warning code
188pub const fn warning<C: ComponentId, P: PrimaryId>(
189    component: C,
190    primary: P,
191    sequence: u16,
192) -> Code<C, P> {
193    Code::warning(component, primary, sequence)
194}
195
196/// Create a critical code
197pub const fn critical<C: ComponentId, P: PrimaryId>(
198    component: C,
199    primary: P,
200    sequence: u16,
201) -> Code<C, P> {
202    Code::critical(component, primary, sequence)
203}
204
205/// Create a blocked code
206pub const fn blocked<C: ComponentId, P: PrimaryId>(
207    component: C,
208    primary: P,
209    sequence: u16,
210) -> Code<C, P> {
211    Code::blocked(component, primary, sequence)
212}
213
214/// Create a help code
215pub const fn help<C: ComponentId, P: PrimaryId>(
216    component: C,
217    primary: P,
218    sequence: u16,
219) -> Code<C, P> {
220    Code::help(component, primary, sequence)
221}
222
223/// Create a success code
224pub const fn success<C: ComponentId, P: PrimaryId>(
225    component: C,
226    primary: P,
227    sequence: u16,
228) -> Code<C, P> {
229    Code::success(component, primary, sequence)
230}
231
232/// Create a completed code
233pub const fn completed<C: ComponentId, P: PrimaryId>(
234    component: C,
235    primary: P,
236    sequence: u16,
237) -> Code<C, P> {
238    Code::completed(component, primary, sequence)
239}
240
241/// Create an info code
242pub const fn info<C: ComponentId, P: PrimaryId>(
243    component: C,
244    primary: P,
245    sequence: u16,
246) -> Code<C, P> {
247    Code::info(component, primary, sequence)
248}
249
250/// Create a trace code
251pub const fn trace<C: ComponentId, P: PrimaryId>(
252    component: C,
253    primary: P,
254    sequence: u16,
255) -> Code<C, P> {
256    Code::trace(component, primary, sequence)
257}
258
259// Prelude module
260
261/// Commonly used types and functions
262///
263/// ```rust
264/// use waddling_errors::prelude::*;
265///
266/// #[derive(Debug, Copy, Clone)]
267/// enum MyComponent { Auth, Database }
268///
269/// impl ComponentId for MyComponent {
270///     fn as_str(&self) -> &'static str {
271///         match self { MyComponent::Auth => "AUTH", MyComponent::Database => "DATABASE" }
272///     }
273/// }
274///
275/// #[derive(Debug, Copy, Clone)]
276/// enum MyPrimary { Token, Connection }
277///
278/// impl PrimaryId for MyPrimary {
279///     fn as_str(&self) -> &'static str {
280///         match self { MyPrimary::Token => "TOKEN", MyPrimary::Connection => "CONN" }
281///     }
282/// }
283///
284/// const ERR: Code<MyComponent, MyPrimary> = error(MyComponent::Auth, MyPrimary::Token, 1);
285/// ```
286/// Prelude module for convenient imports
287pub mod prelude {
288    pub use crate::{Code, Severity};
289    pub use crate::{ComponentId, PrimaryId};
290    pub use crate::{blocked, completed, critical, error, help, info, success, trace, warning};
291}