Skip to main content

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::{UvsFrom, 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> = ConfReason::Uvs(UvsReason::from_logic());
301        assert_eq!(reason.sys_code(), 50001);
302    }
303
304    #[test]
305    fn test_conf_core_take_code() {
306        let reason: ConfReason<ConfCore> = ConfReason::_Take(PhantomData);
307        assert_eq!(reason.sys_code(), 50009);
308    }
309
310    // ConfReason<ConfFeature> tests
311    #[test]
312    fn test_conf_feature_syntax_code() {
313        let reason: ConfReason<ConfFeature> = ConfReason::Syntax("test".into());
314        assert_eq!(reason.sys_code(), 42202);
315        assert_eq!(reason.sys_tag(), "conf.feature");
316    }
317
318    #[test]
319    fn test_conf_feature_not_found_code() {
320        let reason: ConfReason<ConfFeature> = ConfReason::NotFound("missing".into());
321        assert_eq!(reason.sys_code(), 40402);
322    }
323
324    #[test]
325    fn test_conf_feature_uvs_code() {
326        let reason: ConfReason<ConfFeature> = ConfReason::Uvs(UvsReason::from_logic());
327        assert_eq!(reason.sys_code(), 50002);
328    }
329
330    // ConfReason<ConfDynamic> tests
331    #[test]
332    fn test_conf_dynamic_syntax_code() {
333        let reason: ConfReason<ConfDynamic> = ConfReason::Syntax("test".into());
334        assert_eq!(reason.sys_code(), 42203);
335        assert_eq!(reason.sys_tag(), "conf.dynamic");
336    }
337
338    #[test]
339    fn test_conf_dynamic_not_found_code() {
340        let reason: ConfReason<ConfDynamic> = ConfReason::NotFound("missing".into());
341        assert_eq!(reason.sys_code(), 40403);
342    }
343
344    #[test]
345    fn test_conf_dynamic_uvs_code() {
346        let reason: ConfReason<ConfDynamic> = ConfReason::Uvs(UvsReason::from_logic());
347        assert_eq!(reason.sys_code(), 50003);
348    }
349
350    // OMLCodeReason tests
351    #[test]
352    fn test_oml_syntax_code() {
353        let reason = OMLCodeReason::Syntax("parse error".into());
354        assert_eq!(reason.sys_code(), 42211);
355        assert_eq!(reason.sys_tag(), "parse.oml");
356    }
357
358    #[test]
359    fn test_oml_not_found_code() {
360        let reason = OMLCodeReason::NotFound("file.oml".into());
361        assert_eq!(reason.sys_code(), 40411);
362    }
363
364    #[test]
365    fn test_oml_uvs_code() {
366        let reason = OMLCodeReason::Uvs(UvsReason::from_logic());
367        assert_eq!(reason.sys_code(), 50011);
368    }
369
370    // DataErrKind tests
371    #[test]
372    fn test_data_err_format_error_code() {
373        let reason = DataErrKind::FormatError("bad format".into(), None);
374        assert_eq!(reason.sys_code(), 42212);
375        assert_eq!(reason.sys_tag(), "parse.data");
376    }
377
378    #[test]
379    fn test_data_err_not_complete_code() {
380        let reason = DataErrKind::NotComplete;
381        assert_eq!(reason.sys_code(), 42213);
382    }
383
384    #[test]
385    fn test_data_err_unparse_code() {
386        let reason = DataErrKind::UnParse("unparseable".into());
387        assert_eq!(reason.sys_code(), 40412);
388    }
389
390    #[test]
391    fn test_data_err_less_data_code() {
392        let reason = DataErrKind::LessData;
393        assert_eq!(reason.sys_code(), 42214);
394    }
395
396    #[test]
397    fn test_data_err_empty_data_code() {
398        let reason = DataErrKind::EmptyData;
399        assert_eq!(reason.sys_code(), 42215);
400    }
401
402    #[test]
403    fn test_data_err_less_stc_code() {
404        let reason = DataErrKind::LessStc("struct".into());
405        assert_eq!(reason.sys_code(), 42216);
406    }
407
408    #[test]
409    fn test_data_err_less_def_code() {
410        let reason = DataErrKind::LessDef("define".into());
411        assert_eq!(reason.sys_code(), 42217);
412    }
413
414    // SourceReason tests
415    #[test]
416    fn test_source_not_data_code() {
417        let reason = SourceReason::NotData;
418        assert_eq!(reason.sys_code(), 20401);
419        assert_eq!(reason.sys_tag(), "source");
420    }
421
422    #[test]
423    fn test_source_eof_code() {
424        let reason = SourceReason::EOF;
425        assert_eq!(reason.sys_code(), 20402);
426    }
427
428    #[test]
429    fn test_source_supplier_error_code() {
430        let reason = SourceReason::SupplierError("supplier failed".into());
431        assert_eq!(reason.sys_code(), 50201);
432    }
433
434    #[test]
435    fn test_source_disconnect_code() {
436        let reason = SourceReason::Disconnect("connection lost".into());
437        assert_eq!(reason.sys_code(), 49901);
438    }
439
440    #[test]
441    fn test_source_other_code() {
442        let reason = SourceReason::Other("unknown".into());
443        assert_eq!(reason.sys_code(), 50209);
444    }
445
446    // SinkReason tests
447    #[test]
448    fn test_sink_sink_code() {
449        let reason = SinkReason::Sink("sink failed".into());
450        assert_eq!(reason.sys_code(), 50211);
451        assert_eq!(reason.sys_tag(), "dist");
452    }
453
454    #[test]
455    fn test_sink_mock_code() {
456        let reason = SinkReason::Mock;
457        assert_eq!(reason.sys_code(), 50312);
458    }
459
460    #[test]
461    fn test_sink_stg_ctrl_code() {
462        let reason = SinkReason::StgCtrl;
463        assert_eq!(reason.sys_code(), 50311);
464    }
465
466    // KnowledgeReason tests
467    #[test]
468    fn test_knowledge_not_data_code() {
469        let reason = KnowledgeReason::NotData;
470        assert_eq!(reason.sys_code(), 50042);
471        assert_eq!(reason.sys_tag(), "knowledge");
472    }
473
474    #[test]
475    fn test_knowledge_uvs_code() {
476        let reason = KnowledgeReason::Uvs(UvsReason::from_logic());
477        assert_eq!(reason.sys_code(), 50041);
478    }
479
480    // RunReason tests
481    #[test]
482    fn test_run_dist_sink_error_code() {
483        let reason = RR::Dist(DistFocus::SinkError("error".into()));
484        assert_eq!(reason.sys_code(), 50211);
485        assert_eq!(reason.sys_tag(), "run");
486    }
487
488    #[test]
489    fn test_run_dist_stg_ctrl_code() {
490        let reason = RR::Dist(DistFocus::StgCtrl);
491        assert_eq!(reason.sys_code(), 50311);
492    }
493
494    #[test]
495    fn test_run_source_no_data_code() {
496        let reason = RR::Source(SourceFocus::NoData);
497        assert_eq!(reason.sys_code(), 20401);
498    }
499
500    #[test]
501    fn test_run_source_eof_code() {
502        let reason = RR::Source(SourceFocus::Eof);
503        assert_eq!(reason.sys_code(), 20402);
504    }
505
506    #[test]
507    fn test_run_source_supplier_error_code() {
508        let reason = RR::Source(SourceFocus::SupplierError("error".into()));
509        assert_eq!(reason.sys_code(), 50201);
510    }
511
512    #[test]
513    fn test_run_source_other_code() {
514        let reason = RR::Source(SourceFocus::Other("other".into()));
515        assert_eq!(reason.sys_code(), 50209);
516    }
517
518    #[test]
519    fn test_run_source_disconnect_code() {
520        let reason = RR::Source(SourceFocus::Disconnect("disconnect".into()));
521        assert_eq!(reason.sys_code(), 49901);
522    }
523
524    #[test]
525    fn test_run_uvs_code() {
526        let reason = RR::Uvs(UvsReason::from_logic());
527        assert_eq!(reason.sys_code(), 50041);
528    }
529}