1use std::error::Error as StdError;
2use std::fmt::{Display, Formatter};
3use std::sync::Arc;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum InnerErrorCode {
7 Unknown = -1,
8 Success = 0,
10 RuntimeCreationFailedError = 101,
12
13 ParameterEmpty = 102,
14
15 DuplicateTaskError = 103,
17 EnqueueError = 104,
18
19 IoError = 105,
20 HttpError = 106,
21 ClientClosed = 107,
23 TaskNotFound = 108,
25 ResponseStatusError = 109,
26 MissingOrInvalidContentLengthFromHead = 110,
27 CommandSendFailed = 111,
29 CommandResponseFailed = 112,
31 ResponseParseError = 113,
33 InvalidRange = 114,
35 FileNotFound = 115,
37 ChecksumMismatch = 116,
39 InvalidTaskState = 117,
41 LockPoisoned = 118,
43 HttpClientBuildFailed = 119,
45}
46
47#[derive(Debug, Clone)]
48pub struct MeowError {
49 code: i32,
51 msg: String,
52 source: Option<Arc<dyn StdError + Send + Sync>>,
53}
54
55impl MeowError {
56 pub fn new(code: i32, msg: String) -> Self {
57 crate::log::emit_lazy(|| {
58 crate::log::Log::debug("error", format!("MeowError::new code={} msg={}", code, msg))
59 });
60 MeowError {
61 code,
62 msg,
63 source: None,
64 }
65 }
66
67 pub fn code(&self) -> i32 {
68 self.code
69 }
70
71 pub fn msg(&self) -> String {
72 self.msg.clone()
73 }
74
75 pub fn from_code1(code: InnerErrorCode) -> Self {
76 crate::log::emit_lazy(|| {
77 crate::log::Log::debug("error", format!("MeowError::from_code1 code={:?}", code))
78 });
79 MeowError {
80 code: code as i32,
81 msg: String::new(),
82 source: None,
83 }
84 }
85
86 pub fn from_code(code: InnerErrorCode, msg: String) -> Self {
87 crate::log::emit_lazy(|| {
88 crate::log::Log::debug(
89 "error",
90 format!("MeowError::from_code code={:?} msg={}", code, msg),
91 )
92 });
93 MeowError {
94 code: code as i32,
95 msg,
96 source: None,
97 }
98 }
99
100 pub fn from_code_str(code: InnerErrorCode, msg: &str) -> Self {
101 crate::log::emit_lazy(|| {
102 crate::log::Log::debug(
103 "error",
104 format!("MeowError::from_code_str code={:?} msg={}", code, msg),
105 )
106 });
107 MeowError {
108 code: code as i32,
109 msg: msg.to_string(),
110 source: None,
111 }
112 }
113
114 pub fn from_source<E>(code: InnerErrorCode, msg: impl Into<String>, source: E) -> Self
115 where
116 E: StdError + Send + Sync + 'static,
117 {
118 let msg = msg.into();
119 let source_preview = source.to_string();
120 crate::log::emit_lazy(|| {
121 crate::log::Log::debug(
122 "error",
123 format!(
124 "MeowError::from_source code={:?} msg={} source={}",
125 code, msg, source_preview
126 ),
127 )
128 });
129 MeowError {
130 code: code as i32,
131 msg,
132 source: Some(Arc::new(source)),
133 }
134 }
135}
136
137impl PartialEq for MeowError {
138 fn eq(&self, other: &Self) -> bool {
139 self.code == other.code && self.msg == other.msg
140 }
141}
142
143impl Eq for MeowError {}
144
145impl Display for MeowError {
146 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
147 if self.msg.is_empty() {
148 write!(f, "MeowError(code={})", self.code)
149 } else {
150 write!(f, "MeowError(code={}, msg={})", self.code, self.msg)
151 }
152 }
153}
154
155impl StdError for MeowError {
156 fn source(&self) -> Option<&(dyn StdError + 'static)> {
157 self.source
158 .as_deref()
159 .map(|e| e as &(dyn StdError + 'static))
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::{InnerErrorCode, MeowError};
166
167 #[test]
168 fn meow_error_display_contains_code_and_message() {
169 let err = MeowError::from_code_str(InnerErrorCode::InvalidRange, "bad range");
170 let s = format!("{err}");
171 assert!(s.contains("code="));
172 assert!(s.contains("bad range"));
173 }
174
175 #[test]
176 fn meow_error_source_is_accessible() {
177 let io = std::io::Error::other("disk io");
178 let err = MeowError::from_source(InnerErrorCode::IoError, "io failed", io);
179 assert!(std::error::Error::source(&err).is_some());
180 }
181}