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}
112
113impl BaseException {
114 pub fn new(code: ErrorCode, msg: impl Into<String>) -> Self {
116 Self {
117 code: code.as_i32(),
118 msg: msg.into(),
119 }
120 }
121
122 pub fn not_login(msg: impl Into<String>) -> Self {
124 Self::new(ErrorCode::NotLogin, msg)
125 }
126
127 pub fn user_not_found(msg: impl Into<String>) -> Self {
129 Self::new(ErrorCode::UserNotFound, msg)
130 }
131
132 pub fn user_disabled(msg: impl Into<String>) -> Self {
134 Self::new(ErrorCode::UserDisabled, msg)
135 }
136
137 pub fn failed(msg: impl Into<String>) -> Self {
139 Self::new(ErrorCode::Failed, msg)
140 }
141
142 pub fn forbidden(msg: impl Into<String>) -> Self {
144 Self::new(ErrorCode::Forbidden, msg)
145 }
146
147 pub fn not_found(msg: impl Into<String>) -> Self {
149 Self::new(ErrorCode::NotFound, msg)
150 }
151
152 pub fn validate_failed(msg: impl Into<String>) -> Self {
154 Self::new(ErrorCode::ValidateFailed, msg)
155 }
156
157 pub fn db_error(msg: impl Into<String>) -> Self {
159 Self::new(ErrorCode::DbError, msg)
160 }
161
162 pub fn to_json(&self) -> serde_json::Value {
164 serde_json::json!({
165 "code": self.code,
166 "msg": self.msg,
167 "data": {}
168 })
169 }
170}
171
172impl Default for BaseException {
173 fn default() -> Self {
174 Self {
175 code: ErrorCode::Failed.as_i32(),
176 msg: "invalid parameters".to_string(),
177 }
178 }
179}
180
181#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
191 fn test_error_code_values() {
192 assert_eq!(ErrorCode::Success.as_i32(), 1);
193 assert_eq!(ErrorCode::Failed.as_i32(), 0);
194 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
195 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
196 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
197 assert_eq!(ErrorCode::Forbidden.as_i32(), 403);
198 assert_eq!(ErrorCode::NotFound.as_i32(), 404);
199 assert_eq!(ErrorCode::ValidateFailed.as_i32(), 422);
200 assert_eq!(ErrorCode::DbError.as_i32(), 500);
201 }
202
203 #[test]
205 fn test_from_i32() {
206 assert_eq!(ErrorCode::from(1), ErrorCode::Success);
207 assert_eq!(ErrorCode::from(0), ErrorCode::Failed);
208 assert_eq!(ErrorCode::from(-1), ErrorCode::NotLogin);
209 assert_eq!(ErrorCode::from(-2), ErrorCode::UserNotFound);
210 assert_eq!(ErrorCode::from(-3), ErrorCode::UserDisabled);
211 assert_eq!(ErrorCode::from(999), ErrorCode::Failed); }
213
214 #[test]
216 fn test_http_status() {
217 assert_eq!(ErrorCode::Success.http_status(), 200);
218 assert_eq!(ErrorCode::Failed.http_status(), 200);
219 assert_eq!(ErrorCode::NotLogin.http_status(), 401);
220 assert_eq!(ErrorCode::UserNotFound.http_status(), 401);
221 assert_eq!(ErrorCode::UserDisabled.http_status(), 403);
222 assert_eq!(ErrorCode::Forbidden.http_status(), 403);
223 assert_eq!(ErrorCode::NotFound.http_status(), 404);
224 assert_eq!(ErrorCode::ValidateFailed.http_status(), 422);
225 assert_eq!(ErrorCode::DbError.http_status(), 500);
226 }
227
228 #[test]
230 fn test_default() {
231 let ex = BaseException::default();
232 assert_eq!(ex.code, 0);
233 assert_eq!(ex.msg, "invalid parameters");
234 }
235
236 #[test]
238 fn test_not_login() {
239 let ex = BaseException::not_login("not_login");
240 assert_eq!(ex.code, -1);
241 assert_eq!(ex.msg, "not_login");
242 }
243
244 #[test]
246 fn test_user_not_found() {
247 let ex = BaseException::user_not_found("没有找到用户信息");
248 assert_eq!(ex.code, -2);
249 assert_eq!(ex.msg, "没有找到用户信息");
250 }
251
252 #[test]
254 fn test_user_disabled() {
255 let ex = BaseException::user_disabled("您已离职,无权使用本系统!");
256 assert_eq!(ex.code, -3);
257 assert_eq!(ex.msg, "您已离职,无权使用本系统!");
258 }
259
260 #[test]
262 fn test_failed() {
263 let ex = BaseException::failed("操作失败");
264 assert_eq!(ex.code, 0);
265 assert_eq!(ex.msg, "操作失败");
266 }
267
268 #[test]
270 fn test_to_json() {
271 let ex = BaseException::not_login("not_login");
272 let json = ex.to_json();
273 assert_eq!(json["code"], -1);
274 assert_eq!(json["msg"], "not_login");
275 assert_eq!(json["data"], serde_json::json!({}));
276 }
277
278 #[test]
280 fn test_display() {
281 let ex = BaseException::not_login("not_login");
282 assert_eq!(format!("{}", ex), "[-1] not_login");
283 }
284
285 #[test]
288 fn test_php_error_codes_coverage() {
289 assert_eq!(ErrorCode::Success.as_i32(), 1);
291 assert_eq!(ErrorCode::Failed.as_i32(), 0);
293 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
295 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
297 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
299 }
300}