integration_thiserror/
integration_thiserror.rs

1//! **OPTIONAL INTEGRATION**: waddling-errors with thiserror
2//!
3//! This example demonstrates how to use waddling-errors with `thiserror`,
4//! a popular error handling crate. This integration is **completely optional**.
5//!
6//! waddling-errors works standalone or with ANY error handling approach:
7//! - Standalone (no dependencies)
8//! - With thiserror (shown here)
9//! - With anyhow
10//! - With your own Error enum
11//! - Direct Result<T, ErrorCode> returns
12//!
13//! Run with: cargo run --example integration_thiserror
14//!
15//! **Note**: This example shows thiserror patterns in comments since we don't
16//! want to add thiserror as a dependency. In your project, you would add:
17//! ```toml
18//! [dependencies]
19//! thiserror = "1.0"
20//! waddling-errors = { version = "0.1", default-features = false }
21//! ```
22
23use waddling_errors::{ErrorCode, Severity};
24
25// ============================================================================
26// IMPORTANT: This example shows OPTIONAL integration with thiserror
27// ============================================================================
28//
29// waddling-errors does NOT require thiserror! You can use error codes:
30// - Standalone: just return ErrorCode directly
31// - With thiserror: wrap in enum (shown below)
32// - With anyhow: use .context() with error codes
33// - DIY: build your own error type
34//
35// This example demonstrates thiserror patterns for users who choose that path.
36
37// Note: In a real project, add thiserror to Cargo.toml:
38// [dependencies]
39// thiserror = "1.0"
40// waddling-errors = { version = "0.1", default-features = false }
41
42// ============================================================================
43// Error Code Definitions
44// ============================================================================
45
46const ERR_INVALID_SALT: ErrorCode = ErrorCode::new(Severity::Error, "CRYPTO", "SALT", 1);
47const ERR_INVALID_KEY: ErrorCode = ErrorCode::new(Severity::Error, "CRYPTO", "KEY", 2);
48const ERR_MAC_FAILED: ErrorCode = ErrorCode::new(Severity::Error, "CRYPTO", "MAC", 3);
49
50const WARN_DEPRECATED: ErrorCode = ErrorCode::new(Severity::Warning, "API", "DEPR", 1);
51
52const CRIT_DATA_CORRUPT: ErrorCode = ErrorCode::new(Severity::Critical, "DATA", "CORRUPT", 1);
53
54// ============================================================================
55// Error Enum (would use thiserror in real code)
56// ============================================================================
57
58// In a real project, this would use #[derive(Error)] from thiserror:
59//
60// use thiserror::Error;
61//
62// #[derive(Error, Debug)]
63// pub enum CryptoError {
64//     #[error("[MYLIB.{0}] Invalid salt length: expected {1} bytes, got {2} bytes")]
65//     InvalidSaltLength(ErrorCode, usize, usize),
66//
67//     #[error("[MYLIB.{0}] Invalid key length: expected {1} bytes, got {2} bytes")]
68//     InvalidKeyLength(ErrorCode, usize, usize),
69//
70//     #[error("[MYLIB.{0}] MAC verification failed")]
71//     MacVerificationFailed(ErrorCode),
72// }
73
74#[derive(Debug)]
75pub enum CryptoError {
76    InvalidSaltLength(ErrorCode, usize, usize),
77    InvalidKeyLength(ErrorCode, usize, usize),
78    MacVerificationFailed(ErrorCode),
79}
80
81impl std::fmt::Display for CryptoError {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        match self {
84            CryptoError::InvalidSaltLength(code, expected, got) => {
85                write!(
86                    f,
87                    "[MYLIB.{}] Invalid salt length: expected {} bytes, got {} bytes",
88                    code.code(),
89                    expected,
90                    got
91                )
92            }
93            CryptoError::InvalidKeyLength(code, expected, got) => {
94                write!(
95                    f,
96                    "[MYLIB.{}] Invalid key length: expected {} bytes, got {} bytes",
97                    code.code(),
98                    expected,
99                    got
100                )
101            }
102            CryptoError::MacVerificationFailed(code) => {
103                write!(f, "[MYLIB.{}] MAC verification failed", code.code())
104            }
105        }
106    }
107}
108
109impl std::error::Error for CryptoError {}
110
111// ============================================================================
112// Usage Examples
113// ============================================================================
114
115fn validate_salt(salt: &[u8]) -> Result<(), CryptoError> {
116    const EXPECTED_LEN: usize = 32;
117    if salt.len() != EXPECTED_LEN {
118        return Err(CryptoError::InvalidSaltLength(
119            ERR_INVALID_SALT,
120            EXPECTED_LEN,
121            salt.len(),
122        ));
123    }
124    Ok(())
125}
126
127fn validate_key(key: &[u8]) -> Result<(), CryptoError> {
128    const EXPECTED_LEN: usize = 32;
129    if key.len() != EXPECTED_LEN {
130        return Err(CryptoError::InvalidKeyLength(
131            ERR_INVALID_KEY,
132            EXPECTED_LEN,
133            key.len(),
134        ));
135    }
136    Ok(())
137}
138
139fn verify_mac(data: &[u8], mac: &[u8]) -> Result<(), CryptoError> {
140    // Simulate MAC verification failure
141    if data.is_empty() || mac.len() != 32 {
142        return Err(CryptoError::MacVerificationFailed(ERR_MAC_FAILED));
143    }
144    Ok(())
145}
146
147fn main() {
148    println!("šŸ¦† Waddling-Errors + Thiserror Integration Demo šŸ¦†\n");
149
150    // Example 1: Invalid salt length
151    println!("Example 1: Invalid Salt Length");
152    println!("═══════════════════════════════════════════════════");
153    let short_salt = [0u8; 16];
154    match validate_salt(&short_salt) {
155        Ok(_) => println!("āœ“ Salt valid"),
156        Err(e) => {
157            println!("āœ— Error: {}", e);
158            println!("  Error code: E.CRYPTO.SALT.001");
159            println!("  Severity: Error");
160        }
161    }
162    println!();
163
164    // Example 2: Invalid key length
165    println!("Example 2: Invalid Key Length");
166    println!("═══════════════════════════════════════════════════");
167    let short_key = [0u8; 8];
168    match validate_key(&short_key) {
169        Ok(_) => println!("āœ“ Key valid"),
170        Err(e) => {
171            println!("āœ— Error: {}", e);
172            println!("  Error code: E.CRYPTO.KEY.002");
173            println!("  Severity: Error");
174        }
175    }
176    println!();
177
178    // Example 3: MAC verification failed
179    println!("Example 3: MAC Verification Failed");
180    println!("═══════════════════════════════════════════════════");
181    let data = b"";
182    let mac = [0u8; 32];
183    match verify_mac(data, &mac) {
184        Ok(_) => println!("āœ“ MAC valid"),
185        Err(e) => {
186            println!("āœ— Error: {}", e);
187            println!("  Error code: E.CRYPTO.MAC.003");
188            println!("  Severity: Error");
189        }
190    }
191    println!();
192
193    // Example 4: Demonstrating severity information
194    println!("Example 4: Severity Information");
195    println!("═══════════════════════════════════════════════════");
196    let codes = [
197        (ERR_INVALID_SALT, "Error - Invalid salt"),
198        (WARN_DEPRECATED, "Warning - Deprecated API"),
199        (CRIT_DATA_CORRUPT, "Critical - Data corruption"),
200    ];
201
202    for (code, desc) in &codes {
203        println!("Code: {} | {}", code.code(), desc);
204        println!("  Severity: {:?}", code.severity());
205        println!();
206    }
207
208    println!("Key Takeaways:");
209    println!("══════════════");
210    println!("āœ“ Error codes are const fn - zero runtime overhead");
211    println!("āœ“ Integrates cleanly with thiserror for professional errors");
212    println!("āœ“ Only ~500 bytes binary size overhead");
213    println!("āœ“ Error codes stable across versions (001, 002, 003...)");
214    println!("āœ“ Severity matrix enables nuanced error handling");
215    println!("\nšŸ¦† Happy error handling! šŸ¦†\n");
216}