wp_error/
codes.rs

1//! System-wide error code contract for wp-error.
2//! Provide a single place to convert domain reasons into stable numeric codes.
3
4/// Centralized plan for the 5-digit system error codes.
5///
6/// The first digit hints the HTTP mapping (2=NoContent, 4=Client, 5=Server), while the
7/// middle two digits reserve blocks per domain (20=conf, 21=parse, 22=source, 23=dist,
8/// 24=run, 25=knowledge, 26=security, etc.). The last two digits are scoped reasons.
9/// Keeping these constants together makes future assignments deliberate and visible.
10pub mod plan {
11    pub const DEFAULT_TAG: &str = "wp.err";
12
13    pub mod conf {
14        pub mod shared {
15            pub const TAKE: u16 = 50009;
16        }
17
18        pub mod core {
19            pub const TAG: &str = "conf.core";
20            pub const SYNTAX: u16 = 42201;
21            pub const NOT_FOUND: u16 = 40401;
22            pub const UVS: u16 = 50001;
23        }
24
25        pub mod feature {
26            pub const TAG: &str = "conf.feature";
27            pub const SYNTAX: u16 = 42202;
28            pub const NOT_FOUND: u16 = 40402;
29            pub const UVS: u16 = 50002;
30        }
31
32        pub mod dynamic {
33            pub const TAG: &str = "conf.dynamic";
34            pub const SYNTAX: u16 = 42203;
35            pub const NOT_FOUND: u16 = 40403;
36            pub const UVS: u16 = 50003;
37        }
38    }
39
40    pub mod security {
41        pub const SEC: u16 = 62001;
42        pub const UVS: u16 = 50003;
43    }
44
45    pub mod parse {
46        pub mod oml {
47            pub const TAG: &str = "parse.oml";
48            pub const SYNTAX: u16 = 42211;
49            pub const NOT_FOUND: u16 = 40411;
50            pub const UVS: u16 = 50011;
51        }
52
53        pub mod data {
54            pub const TAG: &str = "parse.data";
55            pub const FORMAT_ERROR: u16 = 42212;
56            pub const NOT_COMPLETE: u16 = 42213;
57            pub const UNPARSE: u16 = 40412;
58            pub const LESS_DATA: u16 = 42214;
59            pub const EMPTY_DATA: u16 = 42215;
60            pub const LESS_STC: u16 = 42216;
61            pub const LESS_DEF: u16 = 42217;
62        }
63    }
64
65    pub mod source {
66        pub const TAG: &str = "source";
67        pub const NOT_DATA: u16 = 20401;
68        pub const EOF: u16 = 20402;
69        pub const SUPPLIER_ERROR: u16 = 50201;
70        pub const DISCONNECT: u16 = 49901;
71        pub const OTHER: u16 = 50209;
72        pub const UVS: u16 = 50021;
73    }
74
75    pub mod dist {
76        pub const TAG: &str = "dist";
77        pub const SINK_ERROR: u16 = 50211;
78        pub const STG_CTRL: u16 = 50311;
79        pub const MOCK: u16 = 50312;
80        pub const UVS: u16 = 50031;
81    }
82
83    pub mod knowledge {
84        pub const TAG: &str = "knowledge";
85        pub const UVS: u16 = 50041;
86        pub const NOT_DATA: u16 = 50042;
87    }
88
89    pub mod run {
90        pub const TAG: &str = "run";
91
92        pub mod dist {
93            pub use super::super::dist::{SINK_ERROR, STG_CTRL};
94        }
95
96        pub mod source {
97            pub use super::super::source::{DISCONNECT, EOF, NOT_DATA, OTHER, SUPPLIER_ERROR};
98        }
99
100        pub const UVS: u16 = 50041;
101    }
102}
103
104pub trait SysErrorCode {
105    fn sys_code(&self) -> u16;
106    fn sys_tag(&self) -> &'static str {
107        plan::DEFAULT_TAG
108    }
109}
110
111use orion_sec::OrionSecReason;
112use wp_connector_api::{SinkReason, SourceReason};
113
114// ----------------- Config -----------------
115use crate::KnowledgeReason;
116use crate::config_error::{ConfCore, ConfDynamic, ConfFeature, ConfReason};
117use crate::parse_error::{DataErrKind, OMLCodeReason};
118
119impl SysErrorCode for ConfReason<ConfCore> {
120    fn sys_code(&self) -> u16 {
121        match self {
122            ConfReason::Syntax(_) => plan::conf::core::SYNTAX,
123            ConfReason::NotFound(_) => plan::conf::core::NOT_FOUND,
124            ConfReason::Uvs(_) => plan::conf::core::UVS,
125            ConfReason::_Take(_) => plan::conf::shared::TAKE,
126        }
127    }
128    fn sys_tag(&self) -> &'static str {
129        plan::conf::core::TAG
130    }
131}
132
133impl SysErrorCode for ConfReason<ConfFeature> {
134    fn sys_code(&self) -> u16 {
135        match self {
136            ConfReason::Syntax(_) => plan::conf::feature::SYNTAX,
137            ConfReason::NotFound(_) => plan::conf::feature::NOT_FOUND,
138            ConfReason::Uvs(_) => plan::conf::feature::UVS,
139            ConfReason::_Take(_) => plan::conf::shared::TAKE,
140        }
141    }
142    fn sys_tag(&self) -> &'static str {
143        plan::conf::feature::TAG
144    }
145}
146
147impl SysErrorCode for ConfReason<ConfDynamic> {
148    fn sys_code(&self) -> u16 {
149        match self {
150            ConfReason::Syntax(_) => plan::conf::dynamic::SYNTAX,
151            ConfReason::NotFound(_) => plan::conf::dynamic::NOT_FOUND,
152            ConfReason::Uvs(_) => plan::conf::dynamic::UVS,
153            ConfReason::_Take(_) => plan::conf::shared::TAKE,
154        }
155    }
156    fn sys_tag(&self) -> &'static str {
157        plan::conf::dynamic::TAG
158    }
159}
160
161impl SysErrorCode for OrionSecReason {
162    fn sys_code(&self) -> u16 {
163        match self {
164            OrionSecReason::Sec(_) => plan::security::SEC,
165            OrionSecReason::Uvs(_) => plan::security::UVS,
166        }
167    }
168}
169// ----------------- Parse / OML -----------------
170impl SysErrorCode for OMLCodeReason {
171    fn sys_code(&self) -> u16 {
172        match self {
173            OMLCodeReason::Syntax(_) => plan::parse::oml::SYNTAX,
174            OMLCodeReason::NotFound(_) => plan::parse::oml::NOT_FOUND,
175            OMLCodeReason::Uvs(_) => plan::parse::oml::UVS,
176        }
177    }
178    fn sys_tag(&self) -> &'static str {
179        plan::parse::oml::TAG
180    }
181}
182
183impl SysErrorCode for DataErrKind {
184    fn sys_code(&self) -> u16 {
185        match self {
186            DataErrKind::FormatError(_, _) => plan::parse::data::FORMAT_ERROR,
187            DataErrKind::NotComplete => plan::parse::data::NOT_COMPLETE,
188            DataErrKind::UnParse(_) => plan::parse::data::UNPARSE,
189            DataErrKind::LessData => plan::parse::data::LESS_DATA,
190            DataErrKind::EmptyData => plan::parse::data::EMPTY_DATA,
191            DataErrKind::LessStc(_) => plan::parse::data::LESS_STC,
192            DataErrKind::LessDef(_) => plan::parse::data::LESS_DEF,
193        }
194    }
195    fn sys_tag(&self) -> &'static str {
196        plan::parse::data::TAG
197    }
198}
199
200// ----------------- Source -----------------
201impl SysErrorCode for SourceReason {
202    fn sys_code(&self) -> u16 {
203        match self {
204            SourceReason::NotData => plan::source::NOT_DATA,
205            SourceReason::EOF => plan::source::EOF,
206            SourceReason::SupplierError(_) => plan::source::SUPPLIER_ERROR,
207            SourceReason::Disconnect(_) => plan::source::DISCONNECT,
208            SourceReason::Other(_) => plan::source::OTHER,
209            SourceReason::Uvs(_) => plan::source::UVS,
210        }
211    }
212    fn sys_tag(&self) -> &'static str {
213        plan::source::TAG
214    }
215}
216
217// ----------------- Dist -----------------
218impl SysErrorCode for SinkReason {
219    fn sys_code(&self) -> u16 {
220        match self {
221            SinkReason::Sink(_) => plan::dist::SINK_ERROR,
222            SinkReason::Mock => plan::dist::MOCK,
223            SinkReason::StgCtrl => plan::dist::STG_CTRL,
224            SinkReason::Uvs(_) => plan::dist::UVS,
225        }
226    }
227    fn sys_tag(&self) -> &'static str {
228        plan::dist::TAG
229    }
230}
231
232// ----------------- Dist -----------------
233impl SysErrorCode for KnowledgeReason {
234    fn sys_code(&self) -> u16 {
235        match self {
236            KnowledgeReason::Uvs(_) => plan::knowledge::UVS,
237            KnowledgeReason::NotData => plan::knowledge::NOT_DATA,
238        }
239    }
240    fn sys_tag(&self) -> &'static str {
241        plan::knowledge::TAG
242    }
243}
244
245// ----------------- Run (aggregate) -----------------
246use crate::run_error::{DistFocus, RunReason as RR, SourceFocus};
247impl SysErrorCode for RR {
248    fn sys_code(&self) -> u16 {
249        match self {
250            RR::Dist(DistFocus::SinkError(_)) => plan::run::dist::SINK_ERROR,
251            RR::Dist(DistFocus::StgCtrl) => plan::run::dist::STG_CTRL,
252            RR::Source(SourceFocus::NoData) => plan::run::source::NOT_DATA,
253            RR::Source(SourceFocus::Eof) => plan::run::source::EOF,
254            RR::Source(SourceFocus::SupplierError(_)) => plan::run::source::SUPPLIER_ERROR,
255            RR::Source(SourceFocus::Other(_)) => plan::run::source::OTHER,
256            RR::Source(SourceFocus::Disconnect(_)) => plan::run::source::DISCONNECT,
257            RR::Uvs(_) => plan::run::UVS,
258        }
259    }
260    fn sys_tag(&self) -> &'static str {
261        plan::run::TAG
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268    use orion_error::{UvsLogicFrom, UvsReason};
269    use std::marker::PhantomData;
270
271    #[test]
272    fn test_sys_error_code_default_tag() {
273        struct DummyReason;
274        impl SysErrorCode for DummyReason {
275            fn sys_code(&self) -> u16 {
276                12345
277            }
278        }
279        let dummy = DummyReason;
280        assert_eq!(dummy.sys_tag(), "wp.err");
281        assert_eq!(dummy.sys_code(), 12345);
282    }
283
284    // ConfReason<ConfCore> tests
285    #[test]
286    fn test_conf_core_syntax_code() {
287        let reason: ConfReason<ConfCore> = ConfReason::Syntax("test".into());
288        assert_eq!(reason.sys_code(), 42201);
289        assert_eq!(reason.sys_tag(), "conf.core");
290    }
291
292    #[test]
293    fn test_conf_core_not_found_code() {
294        let reason: ConfReason<ConfCore> = ConfReason::NotFound("missing".into());
295        assert_eq!(reason.sys_code(), 40401);
296    }
297
298    #[test]
299    fn test_conf_core_uvs_code() {
300        let reason: ConfReason<ConfCore> =
301            ConfReason::Uvs(UvsReason::from_logic("test".to_string()));
302        assert_eq!(reason.sys_code(), 50001);
303    }
304
305    #[test]
306    fn test_conf_core_take_code() {
307        let reason: ConfReason<ConfCore> = ConfReason::_Take(PhantomData);
308        assert_eq!(reason.sys_code(), 50009);
309    }
310
311    // ConfReason<ConfFeature> tests
312    #[test]
313    fn test_conf_feature_syntax_code() {
314        let reason: ConfReason<ConfFeature> = ConfReason::Syntax("test".into());
315        assert_eq!(reason.sys_code(), 42202);
316        assert_eq!(reason.sys_tag(), "conf.feature");
317    }
318
319    #[test]
320    fn test_conf_feature_not_found_code() {
321        let reason: ConfReason<ConfFeature> = ConfReason::NotFound("missing".into());
322        assert_eq!(reason.sys_code(), 40402);
323    }
324
325    #[test]
326    fn test_conf_feature_uvs_code() {
327        let reason: ConfReason<ConfFeature> =
328            ConfReason::Uvs(UvsReason::from_logic("test".to_string()));
329        assert_eq!(reason.sys_code(), 50002);
330    }
331
332    // ConfReason<ConfDynamic> tests
333    #[test]
334    fn test_conf_dynamic_syntax_code() {
335        let reason: ConfReason<ConfDynamic> = ConfReason::Syntax("test".into());
336        assert_eq!(reason.sys_code(), 42203);
337        assert_eq!(reason.sys_tag(), "conf.dynamic");
338    }
339
340    #[test]
341    fn test_conf_dynamic_not_found_code() {
342        let reason: ConfReason<ConfDynamic> = ConfReason::NotFound("missing".into());
343        assert_eq!(reason.sys_code(), 40403);
344    }
345
346    #[test]
347    fn test_conf_dynamic_uvs_code() {
348        let reason: ConfReason<ConfDynamic> =
349            ConfReason::Uvs(UvsReason::from_logic("test".to_string()));
350        assert_eq!(reason.sys_code(), 50003);
351    }
352
353    // OMLCodeReason tests
354    #[test]
355    fn test_oml_syntax_code() {
356        let reason = OMLCodeReason::Syntax("parse error".into());
357        assert_eq!(reason.sys_code(), 42211);
358        assert_eq!(reason.sys_tag(), "parse.oml");
359    }
360
361    #[test]
362    fn test_oml_not_found_code() {
363        let reason = OMLCodeReason::NotFound("file.oml".into());
364        assert_eq!(reason.sys_code(), 40411);
365    }
366
367    #[test]
368    fn test_oml_uvs_code() {
369        let reason = OMLCodeReason::Uvs(UvsReason::from_logic("test".to_string()));
370        assert_eq!(reason.sys_code(), 50011);
371    }
372
373    // DataErrKind tests
374    #[test]
375    fn test_data_err_format_error_code() {
376        let reason = DataErrKind::FormatError("bad format".into(), None);
377        assert_eq!(reason.sys_code(), 42212);
378        assert_eq!(reason.sys_tag(), "parse.data");
379    }
380
381    #[test]
382    fn test_data_err_not_complete_code() {
383        let reason = DataErrKind::NotComplete;
384        assert_eq!(reason.sys_code(), 42213);
385    }
386
387    #[test]
388    fn test_data_err_unparse_code() {
389        let reason = DataErrKind::UnParse("unparseable".into());
390        assert_eq!(reason.sys_code(), 40412);
391    }
392
393    #[test]
394    fn test_data_err_less_data_code() {
395        let reason = DataErrKind::LessData;
396        assert_eq!(reason.sys_code(), 42214);
397    }
398
399    #[test]
400    fn test_data_err_empty_data_code() {
401        let reason = DataErrKind::EmptyData;
402        assert_eq!(reason.sys_code(), 42215);
403    }
404
405    #[test]
406    fn test_data_err_less_stc_code() {
407        let reason = DataErrKind::LessStc("struct".into());
408        assert_eq!(reason.sys_code(), 42216);
409    }
410
411    #[test]
412    fn test_data_err_less_def_code() {
413        let reason = DataErrKind::LessDef("define".into());
414        assert_eq!(reason.sys_code(), 42217);
415    }
416
417    // SourceReason tests
418    #[test]
419    fn test_source_not_data_code() {
420        let reason = SourceReason::NotData;
421        assert_eq!(reason.sys_code(), 20401);
422        assert_eq!(reason.sys_tag(), "source");
423    }
424
425    #[test]
426    fn test_source_eof_code() {
427        let reason = SourceReason::EOF;
428        assert_eq!(reason.sys_code(), 20402);
429    }
430
431    #[test]
432    fn test_source_supplier_error_code() {
433        let reason = SourceReason::SupplierError("supplier failed".into());
434        assert_eq!(reason.sys_code(), 50201);
435    }
436
437    #[test]
438    fn test_source_disconnect_code() {
439        let reason = SourceReason::Disconnect("connection lost".into());
440        assert_eq!(reason.sys_code(), 49901);
441    }
442
443    #[test]
444    fn test_source_other_code() {
445        let reason = SourceReason::Other("unknown".into());
446        assert_eq!(reason.sys_code(), 50209);
447    }
448
449    #[test]
450    fn test_source_uvs_code() {
451        let reason = SourceReason::Uvs(UvsReason::from_logic("test".to_string()));
452        assert_eq!(reason.sys_code(), 50021);
453    }
454
455    // SinkReason tests
456    #[test]
457    fn test_sink_sink_code() {
458        let reason = SinkReason::Sink("sink failed".into());
459        assert_eq!(reason.sys_code(), 50211);
460        assert_eq!(reason.sys_tag(), "dist");
461    }
462
463    #[test]
464    fn test_sink_mock_code() {
465        let reason = SinkReason::Mock;
466        assert_eq!(reason.sys_code(), 50312);
467    }
468
469    #[test]
470    fn test_sink_stg_ctrl_code() {
471        let reason = SinkReason::StgCtrl;
472        assert_eq!(reason.sys_code(), 50311);
473    }
474
475    #[test]
476    fn test_sink_uvs_code() {
477        let reason = SinkReason::Uvs(UvsReason::from_logic("test".to_string()));
478        assert_eq!(reason.sys_code(), 50031);
479    }
480
481    // KnowledgeReason tests
482    #[test]
483    fn test_knowledge_not_data_code() {
484        let reason = KnowledgeReason::NotData;
485        assert_eq!(reason.sys_code(), 50042);
486        assert_eq!(reason.sys_tag(), "knowledge");
487    }
488
489    #[test]
490    fn test_knowledge_uvs_code() {
491        let reason = KnowledgeReason::Uvs(UvsReason::from_logic("test".to_string()));
492        assert_eq!(reason.sys_code(), 50041);
493    }
494
495    // RunReason tests
496    #[test]
497    fn test_run_dist_sink_error_code() {
498        let reason = RR::Dist(DistFocus::SinkError("error".into()));
499        assert_eq!(reason.sys_code(), 50211);
500        assert_eq!(reason.sys_tag(), "run");
501    }
502
503    #[test]
504    fn test_run_dist_stg_ctrl_code() {
505        let reason = RR::Dist(DistFocus::StgCtrl);
506        assert_eq!(reason.sys_code(), 50311);
507    }
508
509    #[test]
510    fn test_run_source_no_data_code() {
511        let reason = RR::Source(SourceFocus::NoData);
512        assert_eq!(reason.sys_code(), 20401);
513    }
514
515    #[test]
516    fn test_run_source_eof_code() {
517        let reason = RR::Source(SourceFocus::Eof);
518        assert_eq!(reason.sys_code(), 20402);
519    }
520
521    #[test]
522    fn test_run_source_supplier_error_code() {
523        let reason = RR::Source(SourceFocus::SupplierError("error".into()));
524        assert_eq!(reason.sys_code(), 50201);
525    }
526
527    #[test]
528    fn test_run_source_other_code() {
529        let reason = RR::Source(SourceFocus::Other("other".into()));
530        assert_eq!(reason.sys_code(), 50209);
531    }
532
533    #[test]
534    fn test_run_source_disconnect_code() {
535        let reason = RR::Source(SourceFocus::Disconnect("disconnect".into()));
536        assert_eq!(reason.sys_code(), 49901);
537    }
538
539    #[test]
540    fn test_run_uvs_code() {
541        let reason = RR::Uvs(UvsReason::from_logic("test".to_string()));
542        assert_eq!(reason.sys_code(), 50041);
543    }
544}