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}