1use core::fmt;
9
10#[cfg(test)]
11extern crate std;
12#[cfg(test)]
13use std::prelude::rust_2021::*;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct SequenceMeta {
21 pub number: u16,
23
24 pub name: &'static str,
26
27 pub docs: &'static str,
29
30 pub typical_severity: &'static str,
32
33 pub when_to_use: &'static str,
35
36 pub category: &'static str,
38
39 pub range: &'static str,
41}
42
43impl SequenceMeta {
44 pub const fn is_reserved(&self) -> bool {
46 self.number >= 1 && self.number <= 30
47 }
48
49 pub const fn is_success(&self) -> bool {
51 self.number >= 998 && self.number <= 999
52 }
53
54 pub const fn is_project_specific(&self) -> bool {
56 self.number >= 31 && self.number <= 897
57 }
58}
59
60impl fmt::Display for SequenceMeta {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "{:03} {} - {}", self.number, self.name, self.docs)
63 }
64}
65
66pub static ALL_SEQUENCES: &[SequenceMeta] = &[
70 SequenceMeta {
74 number: 1,
75 name: "MISSING",
76 docs: "Required data not provided",
77 typical_severity: "Error",
78 when_to_use: "Parameter missing, field empty, resource not supplied",
79 category: "Input/Data Validation",
80 range: "001-010",
81 },
82 SequenceMeta {
83 number: 2,
84 name: "MISMATCH",
85 docs: "Type or length mismatch",
86 typical_severity: "Error",
87 when_to_use: "Type error, size mismatch, format disagreement",
88 category: "Input/Data Validation",
89 range: "001-010",
90 },
91 SequenceMeta {
92 number: 3,
93 name: "INVALID",
94 docs: "Validation check failed",
95 typical_severity: "Error",
96 when_to_use: "Format invalid, checksum failed, constraint violated",
97 category: "Input/Data Validation",
98 range: "001-010",
99 },
100 SequenceMeta {
101 number: 4,
102 name: "OVERFLOW",
103 docs: "Value too large",
104 typical_severity: "Error",
105 when_to_use: "Buffer overflow, numeric overflow, size exceeded",
106 category: "Input/Data Validation",
107 range: "001-010",
108 },
109 SequenceMeta {
110 number: 5,
111 name: "UNDERFLOW",
112 docs: "Value too small",
113 typical_severity: "Error",
114 when_to_use: "Buffer underflow, numeric underflow, below minimum",
115 category: "Input/Data Validation",
116 range: "001-010",
117 },
118 SequenceMeta {
119 number: 6,
120 name: "OUT_OF_BOUNDS",
121 docs: "Outside valid range",
122 typical_severity: "Error",
123 when_to_use: "Index out of bounds, value outside range",
124 category: "Input/Data Validation",
125 range: "001-010",
126 },
127 SequenceMeta {
128 number: 7,
129 name: "DUPLICATE",
130 docs: "Duplicate entry",
131 typical_severity: "Error",
132 when_to_use: "Unique constraint violation, duplicate key",
133 category: "Input/Data Validation",
134 range: "001-010",
135 },
136 SequenceMeta {
137 number: 8,
138 name: "DENIED",
139 docs: "Permission denied",
140 typical_severity: "Error",
141 when_to_use: "Authorization failed, access forbidden",
142 category: "Input/Data Validation",
143 range: "001-010",
144 },
145 SequenceMeta {
146 number: 9,
147 name: "UNSUPPORTED",
148 docs: "Feature not supported",
149 typical_severity: "Error",
150 when_to_use: "Unsupported operation, not implemented",
151 category: "Input/Data Validation",
152 range: "001-010",
153 },
154 SequenceMeta {
155 number: 10,
156 name: "DEPRECATED",
157 docs: "Feature deprecated",
158 typical_severity: "Warning",
159 when_to_use: "Deprecated API, obsolete feature (warning)",
160 category: "Input/Data Validation",
161 range: "001-010",
162 },
163 SequenceMeta {
167 number: 11,
168 name: "UNINITIALIZED",
169 docs: "Not initialized",
170 typical_severity: "Error",
171 when_to_use: "Object not initialized, setup incomplete",
172 category: "State/Lifecycle",
173 range: "011-020",
174 },
175 SequenceMeta {
176 number: 12,
177 name: "ALREADY_INIT",
178 docs: "Already initialized",
179 typical_severity: "Error",
180 when_to_use: "Double initialization attempted",
181 category: "State/Lifecycle",
182 range: "011-020",
183 },
184 SequenceMeta {
185 number: 13,
186 name: "CLOSED",
187 docs: "Resource closed",
188 typical_severity: "Error",
189 when_to_use: "Connection closed, file closed, stream ended",
190 category: "State/Lifecycle",
191 range: "011-020",
192 },
193 SequenceMeta {
194 number: 14,
195 name: "CANCELLED",
196 docs: "Operation cancelled",
197 typical_severity: "Error",
198 when_to_use: "User cancelled, timeout cancelled, abort requested",
199 category: "State/Lifecycle",
200 range: "011-020",
201 },
202 SequenceMeta {
203 number: 15,
204 name: "IN_PROGRESS",
205 docs: "Already in progress",
206 typical_severity: "Blocked",
207 when_to_use: "Operation already running, duplicate action",
208 category: "State/Lifecycle",
209 range: "011-020",
210 },
211 SequenceMeta {
212 number: 16,
213 name: "NOT_READY",
214 docs: "Not ready",
215 typical_severity: "Error",
216 when_to_use: "Precondition not met, dependencies unavailable",
217 category: "State/Lifecycle",
218 range: "011-020",
219 },
220 SequenceMeta {
221 number: 17,
222 name: "TIMEOUT",
223 docs: "Operation timed out",
224 typical_severity: "Error",
225 when_to_use: "Deadline exceeded, response timeout",
226 category: "State/Lifecycle",
227 range: "011-020",
228 },
229 SequenceMeta {
230 number: 18,
231 name: "STALE",
232 docs: "Resource stale",
233 typical_severity: "Warning",
234 when_to_use: "Cache stale, data outdated, session expired",
235 category: "State/Lifecycle",
236 range: "011-020",
237 },
238 SequenceMeta {
242 number: 21,
243 name: "NOT_FOUND",
244 docs: "Resource not found",
245 typical_severity: "Error",
246 when_to_use: "File not found, record missing, endpoint 404",
247 category: "Resource/Storage",
248 range: "021-030",
249 },
250 SequenceMeta {
251 number: 22,
252 name: "ALREADY_EXISTS",
253 docs: "Resource already exists",
254 typical_severity: "Error",
255 when_to_use: "File exists, duplicate key, conflict 409",
256 category: "Resource/Storage",
257 range: "021-030",
258 },
259 SequenceMeta {
260 number: 23,
261 name: "CONFLICT",
262 docs: "Version or data conflict",
263 typical_severity: "Error",
264 when_to_use: "Optimistic lock failed, merge conflict",
265 category: "Resource/Storage",
266 range: "021-030",
267 },
268 SequenceMeta {
269 number: 24,
270 name: "LOCKED",
271 docs: "Resource locked",
272 typical_severity: "Blocked",
273 when_to_use: "File locked, row locked, mutex held",
274 category: "Resource/Storage",
275 range: "021-030",
276 },
277 SequenceMeta {
278 number: 25,
279 name: "CORRUPTED",
280 docs: "Data corrupted",
281 typical_severity: "Critical",
282 when_to_use: "Checksum failed, integrity error, malformed data",
283 category: "Resource/Storage",
284 range: "021-030",
285 },
286 SequenceMeta {
287 number: 26,
288 name: "EXHAUSTED",
289 docs: "Resource exhausted",
290 typical_severity: "Critical",
291 when_to_use: "Out of memory, disk full, quota exceeded",
292 category: "Resource/Storage",
293 range: "021-030",
294 },
295 SequenceMeta {
296 number: 27,
297 name: "UNAVAILABLE",
298 docs: "Temporarily unavailable",
299 typical_severity: "Error",
300 when_to_use: "Service down, maintenance mode, circuit breaker open",
301 category: "Resource/Storage",
302 range: "021-030",
303 },
304 SequenceMeta {
305 number: 28,
306 name: "UNREACHABLE",
307 docs: "Cannot reach resource",
308 typical_severity: "Error",
309 when_to_use: "Network unreachable, DNS failed, host down",
310 category: "Resource/Storage",
311 range: "021-030",
312 },
313 SequenceMeta {
314 number: 29,
315 name: "DISCONNECTED",
316 docs: "Connection lost",
317 typical_severity: "Error",
318 when_to_use: "Network dropped, peer disconnected",
319 category: "Resource/Storage",
320 range: "021-030",
321 },
322 SequenceMeta {
326 number: 998,
327 name: "PARTIAL",
328 docs: "Partial success",
329 typical_severity: "Success",
330 when_to_use: "Some items succeeded, some failed",
331 category: "Success/Completion",
332 range: "998-999",
333 },
334 SequenceMeta {
335 number: 999,
336 name: "COMPLETE",
337 docs: "Full success",
338 typical_severity: "Success",
339 when_to_use: "All operations completed successfully",
340 category: "Success/Completion",
341 range: "998-999",
342 },
343];
344
345pub fn get(number: u16) -> Option<&'static SequenceMeta> {
356 ALL_SEQUENCES.iter().find(|m| m.number == number)
357}
358
359pub fn get_by_name(name: &str) -> Option<&'static SequenceMeta> {
372 ALL_SEQUENCES
373 .iter()
374 .find(|m| m.name.eq_ignore_ascii_case(name))
375}
376
377#[cfg(test)]
393pub fn by_category(category: &str) -> Vec<&'static SequenceMeta> {
394 ALL_SEQUENCES
395 .iter()
396 .filter(|m| m.category == category)
397 .collect()
398}
399
400#[cfg(test)]
416pub fn by_range(range: &str) -> Vec<&'static SequenceMeta> {
417 ALL_SEQUENCES.iter().filter(|m| m.range == range).collect()
418}
419
420pub mod categories {
422 pub const INPUT_VALIDATION: &str = "Input/Data Validation";
424
425 pub const STATE_LIFECYCLE: &str = "State/Lifecycle";
427
428 pub const RESOURCE_STORAGE: &str = "Resource/Storage";
430
431 pub const SUCCESS_COMPLETION: &str = "Success/Completion";
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_get_metadata() {
441 let meta = get(1).unwrap();
442 assert_eq!(meta.name, "MISSING");
443 assert_eq!(meta.number, 1);
444 assert_eq!(meta.category, "Input/Data Validation");
445 }
446
447 #[test]
448 fn test_get_by_name() {
449 let meta = get_by_name("MISMATCH").unwrap();
450 assert_eq!(meta.number, 2);
451
452 let meta2 = get_by_name("mismatch").unwrap();
454 assert_eq!(meta2.number, 2);
455 }
456
457 #[test]
458 fn test_get_by_name_with_underscores() {
459 let meta = get_by_name("OUT_OF_BOUNDS").unwrap();
460 assert_eq!(meta.number, 6);
461
462 let meta2 = get_by_name("NOT_FOUND").unwrap();
463 assert_eq!(meta2.number, 21);
464 }
465
466 #[test]
467 fn test_all_sequences_unique() {
468 for (i, meta1) in ALL_SEQUENCES.iter().enumerate() {
469 for meta2 in ALL_SEQUENCES.iter().skip(i + 1) {
470 assert_ne!(meta1.number, meta2.number);
471 assert_ne!(meta1.name, meta2.name);
472 }
473 }
474 }
475
476 #[test]
477 fn test_by_category() {
478 let input = by_category(categories::INPUT_VALIDATION);
479 assert_eq!(input.len(), 10);
480
481 let state = by_category(categories::STATE_LIFECYCLE);
482 assert_eq!(state.len(), 8);
483
484 let resource = by_category(categories::RESOURCE_STORAGE);
485 assert_eq!(resource.len(), 9);
486
487 let success = by_category(categories::SUCCESS_COMPLETION);
488 assert_eq!(success.len(), 2);
489 }
490
491 #[test]
492 fn test_sequence_flags() {
493 let missing = get(1).unwrap();
494 assert!(missing.is_reserved());
495 assert!(!missing.is_success());
496 assert!(!missing.is_project_specific());
497
498 let complete = get(999).unwrap();
499 assert!(!complete.is_reserved());
500 assert!(complete.is_success());
501 assert!(!complete.is_project_specific());
502 }
503
504 #[test]
505 fn test_wdp6_sequences_present() {
506 use std::vec::Vec;
508 let expected = Vec::from([
509 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 998, 999, ]);
514
515 for num in expected {
516 assert!(get(num).is_some(), "Sequence {} should be present", num);
517 }
518 }
519}