use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorCode {
Encrypted, Corrupt, Unsupported, Timeout, NativeCrash, Unknown,
}
impl ErrorCode {
pub fn as_str(&self) -> &'static str {
match self {
ErrorCode::Encrypted => "encrypted",
ErrorCode::Corrupt => "corrupt",
ErrorCode::Unsupported => "unsupported",
ErrorCode::Timeout => "timeout",
ErrorCode::NativeCrash => "native_crash",
ErrorCode::Unknown => "unknown",
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone)]
pub struct DocError {
pub code: ErrorCode,
pub message: String,
pub attempts: Vec<String>,
}
impl DocError {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
attempts: Vec::new(),
}
}
pub fn encrypted(m: impl Into<String>) -> Self {
Self::new(ErrorCode::Encrypted, m)
}
pub fn corrupt(m: impl Into<String>) -> Self {
Self::new(ErrorCode::Corrupt, m)
}
pub fn unsupported(m: impl Into<String>) -> Self {
Self::new(ErrorCode::Unsupported, m)
}
pub fn timeout(m: impl Into<String>) -> Self {
Self::new(ErrorCode::Timeout, m)
}
}
impl fmt::Display for DocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}] {}", self.code, self.message)
}
}
impl std::error::Error for DocError {}
pub type Result<T> = std::result::Result<T, DocError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_display_and_constructors() {
assert_eq!(ErrorCode::Encrypted.as_str(), "encrypted");
assert_eq!(DocError::encrypted("x").code, ErrorCode::Encrypted);
assert_eq!(DocError::corrupt("x").code, ErrorCode::Corrupt);
assert_eq!(DocError::unsupported("x").code, ErrorCode::Unsupported);
assert_eq!(DocError::timeout("x").code, ErrorCode::Timeout);
assert_eq!(format!("{}", DocError::corrupt("bad")), "[corrupt] bad");
}
#[test]
fn error_is_send_and_boxable() {
let e: Box<dyn std::error::Error + Send> = Box::new(DocError::corrupt("x"));
assert!(e.to_string().contains("corrupt"));
}
}