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}