1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum ErrorCode {
8 Encrypted, Corrupt, Unsupported, Timeout, NativeCrash, Unknown,
14}
15
16impl ErrorCode {
17 pub fn as_str(&self) -> &'static str {
18 match self {
19 ErrorCode::Encrypted => "encrypted",
20 ErrorCode::Corrupt => "corrupt",
21 ErrorCode::Unsupported => "unsupported",
22 ErrorCode::Timeout => "timeout",
23 ErrorCode::NativeCrash => "native_crash",
24 ErrorCode::Unknown => "unknown",
25 }
26 }
27}
28
29impl fmt::Display for ErrorCode {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.write_str(self.as_str())
32 }
33}
34
35#[derive(Debug, Clone)]
37pub struct DocError {
38 pub code: ErrorCode,
39 pub message: String,
40 pub attempts: Vec<String>,
41}
42
43impl DocError {
44 pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
45 Self {
46 code,
47 message: message.into(),
48 attempts: Vec::new(),
49 }
50 }
51 pub fn encrypted(m: impl Into<String>) -> Self {
52 Self::new(ErrorCode::Encrypted, m)
53 }
54 pub fn corrupt(m: impl Into<String>) -> Self {
55 Self::new(ErrorCode::Corrupt, m)
56 }
57 pub fn unsupported(m: impl Into<String>) -> Self {
58 Self::new(ErrorCode::Unsupported, m)
59 }
60 pub fn timeout(m: impl Into<String>) -> Self {
61 Self::new(ErrorCode::Timeout, m)
62 }
63}
64
65impl fmt::Display for DocError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "[{}] {}", self.code, self.message)
68 }
69}
70
71impl std::error::Error for DocError {}
72
73pub type Result<T> = std::result::Result<T, DocError>;
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn code_display_and_constructors() {
81 assert_eq!(ErrorCode::Encrypted.as_str(), "encrypted");
82 assert_eq!(DocError::encrypted("x").code, ErrorCode::Encrypted);
83 assert_eq!(DocError::corrupt("x").code, ErrorCode::Corrupt);
84 assert_eq!(DocError::unsupported("x").code, ErrorCode::Unsupported);
85 assert_eq!(DocError::timeout("x").code, ErrorCode::Timeout);
86 assert_eq!(format!("{}", DocError::corrupt("bad")), "[corrupt] bad");
87 }
88
89 #[test]
90 fn error_is_send_and_boxable() {
91 let e: Box<dyn std::error::Error + Send> = Box::new(DocError::corrupt("x"));
92 assert!(e.to_string().contains("corrupt"));
93 }
94}