api_response/error_code/
mod.rs1mod errpath;
2mod errtype;
3pub mod ety_grpc;
4pub mod tally;
5
6use std::{
7 fmt::Display,
8 ops::{Add, BitOr},
9 thread::LocalKey,
10};
11
12pub use errpath::*;
13pub use errtype::*;
14use getset2::Getset2;
15use serde::{Deserialize, Serialize};
16
17use crate::ApiError;
18
19#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize)]
20#[non_exhaustive]
21pub struct ErrDecl {
22 pub err_type: ErrType,
23 pub err_path: ErrPath,
24}
25
26impl ErrDecl {
27 #[inline]
28 pub const fn new(err_type: ErrType, err_path: ErrPath) -> Self {
29 Self { err_type, err_path }
30 }
31 #[inline]
32 pub const fn err_flag(&self) -> u32 {
33 self.err_type.flag() as u32
34 }
35 #[inline]
36 pub const fn err_path_flag(&self) -> u32 {
37 self.err_path.path_flag()
38 }
39 #[inline]
40 pub const fn text(&self) -> &'static str {
41 self.err_type.text()
42 }
43 pub const fn err_type(&self) -> &ErrType {
44 &self.err_type
45 }
46 pub const fn err_path(&self) -> &ErrPath {
47 &self.err_path
48 }
49 #[inline(always)]
50 pub const fn extract(&self) -> ErrBrief {
51 ErrBrief::new(self.err_type, &self.err_path)
52 }
53 #[inline(always)]
54 pub fn api_error(&self) -> ApiError {
55 self.extract().api_error()
56 }
57}
58
59impl Display for ErrDecl {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}, {}", self.extract(), self.err_path)
62 }
63}
64
65#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Getset2, Serialize, Deserialize)]
66#[getset2(get_copy(pub, const))]
67#[non_exhaustive]
68pub struct ErrBrief {
69 message: &'static str,
70 code: u32,
72}
73impl Display for ErrBrief {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 if self.message.is_empty() {
76 write!(f, "<no message> ErrCode({})", self.code)
77 } else {
78 write!(f, "{} ErrCode({})", self.message, self.code)
79 }
80 }
81}
82impl ErrBrief {
83 #[inline(always)]
84 pub const fn new(err_type: ErrType, err_path: &ErrPath) -> Self {
85 Self {
86 message: err_type.text(),
87 code: (err_type.flag() as u32 * 1000000) + err_path.path_flag(),
88 }
89 }
90 #[inline(always)]
91 pub fn api_error(&self) -> ApiError {
92 ApiError {
93 code: self.code,
94 message: self.message.to_owned(),
95 details: None,
96 source: None,
97 }
98 }
99}
100
101impl BitOr<&'static str> for ErrType {
102 type Output = ErrType;
103
104 #[inline(always)]
105 fn bitor(self, rhs: &'static str) -> Self::Output {
106 self.with_text(rhs)
107 }
108}
109
110impl Add<ErrPath> for ErrType {
111 type Output = ErrDecl;
112
113 #[inline(always)]
114 fn add(self, rhs: ErrPath) -> Self::Output {
115 self.declare(rhs)
116 }
117}
118impl Add<&ErrPath> for ErrType {
119 type Output = ErrDecl;
120
121 #[inline(always)]
122 fn add(self, rhs: &ErrPath) -> Self::Output {
123 self.declare(*rhs)
124 }
125}
126impl Add<&'static LocalKey<ErrPath>> for ErrType {
127 type Output = ErrDecl;
128
129 #[inline(always)]
130 fn add(self, rhs: &'static LocalKey<ErrPath>) -> Self::Output {
131 rhs.with(|v| self.declare(*v))
132 }
133}
134
135impl BitOr<&ErrPath> for ErrType {
136 type Output = ApiError;
137
138 #[inline(always)]
139 fn bitor(self, rhs: &ErrPath) -> Self::Output {
140 self.api_error(rhs)
141 }
142}
143impl BitOr<&'static LocalKey<ErrPath>> for ErrType {
144 type Output = ApiError;
145
146 #[inline(always)]
147 fn bitor(self, rhs: &'static LocalKey<ErrPath>) -> Self::Output {
148 rhs.with(|v| self.api_error(v))
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use std::cell::LazyCell;
155
156 use super::{ErrDecl, ErrPath, ErrPathParent, ErrPathRoot, ErrType};
157 use crate::ApiError;
158
159 #[test]
160 fn display() {
161 const ET: ErrType = ErrType::T1100("The operation was cancelled.");
162 const EP_LV1: ErrPathRoot = ErrPathRoot::X00("product");
163 const EP_LV2: ErrPathParent = EP_LV1.Y01("system");
164 const EP_LV3: ErrPath = EP_LV2.Z20("module");
165 const EC: ErrDecl = ErrDecl::new(ET, EP_LV3);
166 assert_eq!(
167 "The operation was cancelled. ErrCode(1100000120), X00(product)/Y01(system)/Z20(module)",
168 EC.to_string()
169 );
170
171 let api_error: ApiError = ET | &EP_LV3;
172 assert_eq!(EC.api_error().code(), api_error.code());
173 let mp: LazyCell<ErrPath> = LazyCell::new(|| EP_LV3);
174 let api_error: ApiError = ET | &*mp;
175 assert_eq!(EC.api_error().code(), api_error.code());
176 }
177
178 #[test]
179 fn min_max_code() {
180 let min_code: ErrDecl = ErrType::T1000("") + ErrPathRoot::X00("").Y00("").Z00("");
181 assert_eq!(
182 "<no message> ErrCode(1000000000), X00()/Y00()/Z00()",
183 min_code.to_string()
184 );
185
186 let max_code: ErrDecl = ErrType::T4293("") + ErrPathRoot::X99("").Y99("").Z99("");
187 assert_eq!(
188 "<no message> ErrCode(4293999999), X99()/Y99()/Z99()",
189 max_code.to_string()
190 );
191 }
192}