use std::error::Error as StdError;
use std::fmt::{Display, Formatter};
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InnerErrorCode {
Unknown = -1,
Success = 0,
RuntimeCreationFailedError = 101,
ParameterEmpty = 102,
DuplicateTaskError = 103,
EnqueueError = 104,
IoError = 105,
HttpError = 106,
ClientClosed = 107,
TaskNotFound = 108,
ResponseStatusError = 109,
MissingOrInvalidContentLengthFromHead = 110,
CommandSendFailed = 111,
CommandResponseFailed = 112,
ResponseParseError = 113,
InvalidRange = 114,
FileNotFound = 115,
ChecksumMismatch = 116,
InvalidTaskState = 117,
LockPoisoned = 118,
HttpClientBuildFailed = 119,
}
#[derive(Debug, Clone)]
pub struct MeowError {
code: i32,
msg: String,
source: Option<Arc<dyn StdError + Send + Sync>>,
}
impl MeowError {
pub fn new(code: i32, msg: String) -> Self {
crate::log::emit_lazy(|| {
crate::log::Log::debug("error", format!("MeowError::new code={} msg={}", code, msg))
});
MeowError {
code,
msg,
source: None,
}
}
pub fn code(&self) -> i32 {
self.code
}
pub fn msg(&self) -> String {
self.msg.clone()
}
pub fn from_code1(code: InnerErrorCode) -> Self {
crate::log::emit_lazy(|| {
crate::log::Log::debug("error", format!("MeowError::from_code1 code={:?}", code))
});
MeowError {
code: code as i32,
msg: String::new(),
source: None,
}
}
pub fn from_code(code: InnerErrorCode, msg: String) -> Self {
crate::log::emit_lazy(|| {
crate::log::Log::debug(
"error",
format!("MeowError::from_code code={:?} msg={}", code, msg),
)
});
MeowError {
code: code as i32,
msg,
source: None,
}
}
pub fn from_code_str(code: InnerErrorCode, msg: &str) -> Self {
crate::log::emit_lazy(|| {
crate::log::Log::debug(
"error",
format!("MeowError::from_code_str code={:?} msg={}", code, msg),
)
});
MeowError {
code: code as i32,
msg: msg.to_string(),
source: None,
}
}
pub fn from_source<E>(code: InnerErrorCode, msg: impl Into<String>, source: E) -> Self
where
E: StdError + Send + Sync + 'static,
{
let msg = msg.into();
let source_preview = source.to_string();
crate::log::emit_lazy(|| {
crate::log::Log::debug(
"error",
format!(
"MeowError::from_source code={:?} msg={} source={}",
code, msg, source_preview
),
)
});
MeowError {
code: code as i32,
msg,
source: Some(Arc::new(source)),
}
}
}
impl PartialEq for MeowError {
fn eq(&self, other: &Self) -> bool {
self.code == other.code && self.msg == other.msg
}
}
impl Eq for MeowError {}
impl Display for MeowError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.msg.is_empty() {
write!(f, "MeowError(code={})", self.code)
} else {
write!(f, "MeowError(code={}, msg={})", self.code, self.msg)
}
}
}
impl StdError for MeowError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.source
.as_deref()
.map(|e| e as &(dyn StdError + 'static))
}
}
#[cfg(test)]
mod tests {
use super::{InnerErrorCode, MeowError};
#[test]
fn meow_error_display_contains_code_and_message() {
let err = MeowError::from_code_str(InnerErrorCode::InvalidRange, "bad range");
let s = format!("{err}");
assert!(s.contains("code="));
assert!(s.contains("bad range"));
}
#[test]
fn meow_error_source_is_accessible() {
let io = std::io::Error::other("disk io");
let err = MeowError::from_source(InnerErrorCode::IoError, "io failed", io);
assert!(std::error::Error::source(&err).is_some());
}
}