1use serde::Serialize;
26use thiserror::Error;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
30#[repr(i32)]
31pub enum ErrorCode {
32 Success = 1,
34 Failed = 0,
36 NotLogin = -1,
38 UserNotFound = -2,
40 UserDisabled = -3,
42 Forbidden = 403,
44 NotFound = 404,
46 ValidateFailed = 422,
48 DbError = 500,
50}
51
52impl ErrorCode {
53 pub fn as_i32(self) -> i32 {
55 self as i32
56 }
57
58 pub fn http_status(self) -> u16 {
60 match self {
61 ErrorCode::Success => 200,
62 ErrorCode::Failed => 200,
63 ErrorCode::NotLogin => 401,
64 ErrorCode::UserNotFound => 401,
65 ErrorCode::UserDisabled => 403,
66 ErrorCode::Forbidden => 403,
67 ErrorCode::NotFound => 404,
68 ErrorCode::ValidateFailed => 422,
69 ErrorCode::DbError => 500,
70 }
71 }
72}
73
74impl From<i32> for ErrorCode {
75 fn from(code: i32) -> Self {
76 match code {
77 1 => ErrorCode::Success,
78 0 => ErrorCode::Failed,
79 -1 => ErrorCode::NotLogin,
80 -2 => ErrorCode::UserNotFound,
81 -3 => ErrorCode::UserDisabled,
82 403 => ErrorCode::Forbidden,
83 404 => ErrorCode::NotFound,
84 422 => ErrorCode::ValidateFailed,
85 500 => ErrorCode::DbError,
86 _ => ErrorCode::Failed,
87 }
88 }
89}
90
91#[derive(Debug, Clone, Error)]
105#[error("[{code}] {msg}")]
106pub struct BaseException {
107 pub code: i32,
109 pub msg: String,
111 pub message_key: Option<String>,
116}
117
118impl BaseException {
119 pub fn new(code: ErrorCode, msg: impl Into<String>) -> Self {
121 Self {
122 code: code.as_i32(),
123 msg: msg.into(),
124 message_key: None,
125 }
126 }
127
128 pub fn with_message_key(mut self, key: impl Into<String>) -> Self {
130 self.message_key = Some(key.into());
131 self
132 }
133
134 pub fn message_key(&self) -> Option<&str> {
136 self.message_key.as_deref()
137 }
138
139 pub fn not_login(msg: impl Into<String>) -> Self {
141 Self::new(ErrorCode::NotLogin, msg)
142 }
143
144 pub fn user_not_found(msg: impl Into<String>) -> Self {
146 Self::new(ErrorCode::UserNotFound, msg)
147 }
148
149 pub fn user_disabled(msg: impl Into<String>) -> Self {
151 Self::new(ErrorCode::UserDisabled, msg)
152 }
153
154 pub fn failed(msg: impl Into<String>) -> Self {
156 Self::new(ErrorCode::Failed, msg)
157 }
158
159 pub fn forbidden(msg: impl Into<String>) -> Self {
161 Self::new(ErrorCode::Forbidden, msg)
162 }
163
164 pub fn not_found(msg: impl Into<String>) -> Self {
166 Self::new(ErrorCode::NotFound, msg)
167 }
168
169 pub fn validate_failed(msg: impl Into<String>) -> Self {
171 Self::new(ErrorCode::ValidateFailed, msg)
172 }
173
174 pub fn db_error(msg: impl Into<String>) -> Self {
176 Self::new(ErrorCode::DbError, msg)
177 }
178
179 pub fn to_json(&self) -> serde_json::Value {
181 serde_json::json!({
182 "code": self.code,
183 "msg": self.msg,
184 "data": {}
185 })
186 }
187}
188
189impl Default for BaseException {
190 fn default() -> Self {
191 Self {
192 code: ErrorCode::Failed.as_i32(),
193 msg: "invalid parameters".to_string(),
194 message_key: None,
195 }
196 }
197}
198
199#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
209 fn test_error_code_values() {
210 assert_eq!(ErrorCode::Success.as_i32(), 1);
211 assert_eq!(ErrorCode::Failed.as_i32(), 0);
212 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
213 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
214 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
215 assert_eq!(ErrorCode::Forbidden.as_i32(), 403);
216 assert_eq!(ErrorCode::NotFound.as_i32(), 404);
217 assert_eq!(ErrorCode::ValidateFailed.as_i32(), 422);
218 assert_eq!(ErrorCode::DbError.as_i32(), 500);
219 }
220
221 #[test]
223 fn test_from_i32() {
224 assert_eq!(ErrorCode::from(1), ErrorCode::Success);
225 assert_eq!(ErrorCode::from(0), ErrorCode::Failed);
226 assert_eq!(ErrorCode::from(-1), ErrorCode::NotLogin);
227 assert_eq!(ErrorCode::from(-2), ErrorCode::UserNotFound);
228 assert_eq!(ErrorCode::from(-3), ErrorCode::UserDisabled);
229 assert_eq!(ErrorCode::from(999), ErrorCode::Failed); }
231
232 #[test]
234 fn test_http_status() {
235 assert_eq!(ErrorCode::Success.http_status(), 200);
236 assert_eq!(ErrorCode::Failed.http_status(), 200);
237 assert_eq!(ErrorCode::NotLogin.http_status(), 401);
238 assert_eq!(ErrorCode::UserNotFound.http_status(), 401);
239 assert_eq!(ErrorCode::UserDisabled.http_status(), 403);
240 assert_eq!(ErrorCode::Forbidden.http_status(), 403);
241 assert_eq!(ErrorCode::NotFound.http_status(), 404);
242 assert_eq!(ErrorCode::ValidateFailed.http_status(), 422);
243 assert_eq!(ErrorCode::DbError.http_status(), 500);
244 }
245
246 #[test]
248 fn test_default() {
249 let ex = BaseException::default();
250 assert_eq!(ex.code, 0);
251 assert_eq!(ex.msg, "invalid parameters");
252 }
253
254 #[test]
256 fn test_not_login() {
257 let ex = BaseException::not_login("not_login");
258 assert_eq!(ex.code, -1);
259 assert_eq!(ex.msg, "not_login");
260 }
261
262 #[test]
264 fn test_user_not_found() {
265 let ex = BaseException::user_not_found("没有找到用户信息");
266 assert_eq!(ex.code, -2);
267 assert_eq!(ex.msg, "没有找到用户信息");
268 }
269
270 #[test]
272 fn test_user_disabled() {
273 let ex = BaseException::user_disabled("您已离职,无权使用本系统!");
274 assert_eq!(ex.code, -3);
275 assert_eq!(ex.msg, "您已离职,无权使用本系统!");
276 }
277
278 #[test]
280 fn test_failed() {
281 let ex = BaseException::failed("操作失败");
282 assert_eq!(ex.code, 0);
283 assert_eq!(ex.msg, "操作失败");
284 }
285
286 #[test]
288 fn test_to_json() {
289 let ex = BaseException::not_login("not_login");
290 let json = ex.to_json();
291 assert_eq!(json["code"], -1);
292 assert_eq!(json["msg"], "not_login");
293 assert_eq!(json["data"], serde_json::json!({}));
294 }
295
296 #[test]
298 fn test_display() {
299 let ex = BaseException::not_login("not_login");
300 assert_eq!(format!("{}", ex), "[-1] not_login");
301 }
302
303 #[test]
306 fn test_php_error_codes_coverage() {
307 assert_eq!(ErrorCode::Success.as_i32(), 1);
309 assert_eq!(ErrorCode::Failed.as_i32(), 0);
311 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
313 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
315 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
317 }
318}