waddling_errors/
severity.rs1use core::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[repr(u8)]
24pub enum Severity {
25 Error = b'E',
27 Warning = b'W',
29 Critical = b'C',
31 Blocked = b'B',
33 Success = b'S',
35 Completed = b'K',
37 Info = b'I',
39 Trace = b'T',
41}
42
43impl Severity {
44 pub const fn as_char(self) -> char {
46 self as u8 as char
47 }
48
49 pub const fn as_str(self) -> &'static str {
51 match self {
52 Severity::Error => "Error",
53 Severity::Warning => "Warning",
54 Severity::Critical => "Critical",
55 Severity::Blocked => "Blocked",
56 Severity::Success => "Success",
57 Severity::Completed => "Completed",
58 Severity::Info => "Info",
59 Severity::Trace => "Trace",
60 }
61 }
62
63 pub const fn description(self) -> &'static str {
65 match self {
66 Severity::Error => "Operation failed",
67 Severity::Warning => "Potential issue or caveat",
68 Severity::Critical => "Severe issue requiring attention",
69 Severity::Blocked => "Execution blocked or waiting",
70 Severity::Success => "Operation succeeded",
71 Severity::Completed => "Task or phase completed",
72 Severity::Info => "General informational events",
73 Severity::Trace => "Execution traces and instrumentation",
74 }
75 }
76
77 pub const fn priority(self) -> u8 {
85 match self {
86 Severity::Trace => 0,
87 Severity::Info => 1,
88 Severity::Completed => 2,
89 Severity::Success => 3,
90 Severity::Warning => 4,
91 Severity::Critical => 5,
92 Severity::Blocked => 6,
93 Severity::Error => 7,
94 }
95 }
96
97 pub const fn is_blocking(self) -> bool {
102 matches!(self, Severity::Error | Severity::Blocked)
103 }
104
105 pub const fn is_positive(self) -> bool {
107 matches!(self, Severity::Success | Severity::Completed)
108 }
109
110 pub const fn is_negative(self) -> bool {
112 matches!(
113 self,
114 Severity::Error | Severity::Warning | Severity::Critical | Severity::Blocked
115 )
116 }
117
118 pub const fn is_neutral(self) -> bool {
120 matches!(self, Severity::Info | Severity::Trace)
121 }
122
123 #[cfg(feature = "emoji")]
148 pub const fn emoji(self) -> &'static str {
149 match self {
150 Severity::Error => "â",
151 Severity::Blocked => "đĢ",
152 Severity::Critical => "đĨ",
153 Severity::Warning => "â ī¸",
154 Severity::Success => "â
",
155 Severity::Completed => "âī¸",
156 Severity::Info => "âšī¸",
157 Severity::Trace => "đ",
158 }
159 }
160
161 #[cfg(feature = "ansi-colors")]
176 pub const fn ansi_color(self) -> &'static str {
177 match self {
178 Severity::Error => "\x1b[1;31m", Severity::Blocked => "\x1b[31m", Severity::Critical => "\x1b[1;33m", Severity::Warning => "\x1b[33m", Severity::Success => "\x1b[1;32m", Severity::Completed => "\x1b[32m", Severity::Info => "\x1b[36m", Severity::Trace => "\x1b[2;34m", }
187 }
188
189 #[cfg(feature = "ansi-colors")]
191 pub const ANSI_RESET: &'static str = "\x1b[0m";
192}
193
194impl fmt::Display for Severity {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(f, "{}", self.as_char())
197 }
198}
199
200impl PartialOrd for Severity {
201 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
202 Some(self.cmp(other))
203 }
204}
205
206impl Ord for Severity {
207 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
208 self.priority().cmp(&other.priority())
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_severity_ordering() {
218 assert!(Severity::Trace.priority() < Severity::Error.priority());
219 assert!(Severity::Warning.priority() < Severity::Critical.priority());
220 }
221
222 #[test]
223 fn test_severity_comparison() {
224 assert!(Severity::Trace < Severity::Error);
225 assert!(Severity::Info < Severity::Warning);
226 assert!(Severity::Warning < Severity::Critical);
227 assert!(Severity::Critical < Severity::Blocked);
228 assert!(Severity::Blocked < Severity::Error);
229 }
230
231 #[test]
232 fn test_severity_blocking() {
233 assert!(Severity::Error.is_blocking());
235 assert!(Severity::Blocked.is_blocking());
236
237 assert!(!Severity::Critical.is_blocking());
239 assert!(!Severity::Warning.is_blocking());
240 assert!(!Severity::Success.is_blocking());
241 assert!(!Severity::Completed.is_blocking());
242 assert!(!Severity::Info.is_blocking());
243 assert!(!Severity::Trace.is_blocking());
244 }
245
246 #[test]
247 fn test_severity_categorization() {
248 assert!(Severity::Success.is_positive());
250 assert!(Severity::Completed.is_positive());
251
252 assert!(Severity::Error.is_negative());
254 assert!(Severity::Warning.is_negative());
255 assert!(Severity::Critical.is_negative());
256 assert!(Severity::Blocked.is_negative());
257
258 assert!(Severity::Info.is_neutral());
260 assert!(Severity::Trace.is_neutral());
261
262 assert!(!Severity::Error.is_positive());
264 assert!(!Severity::Success.is_negative());
265 assert!(!Severity::Info.is_positive());
266 assert!(!Severity::Info.is_negative());
267 }
268
269 #[test]
270 fn test_severity_metadata() {
271 assert_eq!(Severity::Error.as_str(), "Error");
272 assert_eq!(Severity::Warning.as_str(), "Warning");
273 assert_eq!(Severity::Critical.as_str(), "Critical");
274
275 assert_eq!(Severity::Error.description(), "Operation failed");
276 assert_eq!(Severity::Warning.description(), "Potential issue or caveat");
277
278 assert_eq!(Severity::Error.as_char(), 'E');
279 assert_eq!(Severity::Warning.as_char(), 'W');
280 }
281
282 #[test]
283 fn test_severity_positive() {
284 assert!(Severity::Success.is_positive());
285 assert!(Severity::Completed.is_positive());
286 assert!(!Severity::Error.is_positive());
287 assert!(!Severity::Warning.is_positive());
288 assert!(!Severity::Critical.is_positive());
289 assert!(!Severity::Blocked.is_positive());
290 assert!(!Severity::Info.is_positive());
291 assert!(!Severity::Trace.is_positive());
292 }
293
294 #[cfg(feature = "emoji")]
295 #[test]
296 fn test_emoji() {
297 assert_eq!(Severity::Error.emoji(), "â");
298 assert_eq!(Severity::Warning.emoji(), "â ī¸");
299 assert_eq!(Severity::Critical.emoji(), "đĨ");
300 assert_eq!(Severity::Success.emoji(), "â
");
301 assert_eq!(Severity::Completed.emoji(), "âī¸");
302 assert_eq!(Severity::Info.emoji(), "âšī¸");
303 assert_eq!(Severity::Trace.emoji(), "đ");
304 assert_eq!(Severity::Blocked.emoji(), "đĢ");
305 }
306
307 #[cfg(feature = "ansi-colors")]
308 #[test]
309 fn test_ansi_colors() {
310 assert_eq!(Severity::Error.ansi_color(), "\x1b[1;31m");
311 assert_eq!(Severity::Warning.ansi_color(), "\x1b[33m");
312 assert_eq!(Severity::Success.ansi_color(), "\x1b[1;32m");
313 assert_eq!(Severity::ANSI_RESET, "\x1b[0m");
314 }
315
316 #[cfg(feature = "serde")]
317 #[test]
318 fn test_serde() {
319 use serde_json;
320
321 let severity = Severity::Error;
322 let json = serde_json::to_string(&severity).unwrap();
323 let deserialized: Severity = serde_json::from_str(&json).unwrap();
324 assert_eq!(severity, deserialized);
325 }
326}