Skip to main content

cloudiful_docling_convert/
error.rs

1use std::error::Error;
2use std::fmt;
3
4#[derive(Debug)]
5pub enum PdfConvertError {
6    IoError {
7        context: String,
8        source: std::io::Error,
9    },
10
11    ApiError {
12        status_code: Option<u16>,
13        message: String,
14        source: Option<reqwest::Error>,
15    },
16
17    ParseError {
18        target: String,
19        message: String,
20    },
21
22    #[allow(dead_code)]
23    ValidationError {
24        parameter: String,
25        reason: String,
26    },
27
28    EnvError {
29        var_name: String,
30        message: String,
31    },
32
33    OperationError {
34        context: String,
35        message: String,
36    },
37}
38
39impl fmt::Display for PdfConvertError {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        match self {
42            PdfConvertError::IoError { context, source } => {
43                write!(f, "IO error while {}: {}", context, source)?;
44                let mut curr = source.source();
45                while let Some(src) = curr {
46                    write!(f, " caused by: {}", src)?;
47                    curr = src.source();
48                }
49                Ok(())
50            }
51            PdfConvertError::ApiError {
52                status_code,
53                message,
54                source,
55            } => {
56                if let Some(src) = source {
57                    write!(f, "{}", src)?;
58                    let mut curr = src.source();
59                    while let Some(cause) = curr {
60                        write!(f, " caused by: {}", cause)?;
61                        curr = cause.source();
62                    }
63                    Ok(())
64                } else if let Some(code) = status_code {
65                    write!(f, "HTTP {}: {}", code, message)
66                } else {
67                    write!(f, "{}", message)
68                }
69            }
70            PdfConvertError::ParseError { target, message } => {
71                write!(f, "Failed to parse {}: {}", target, message)
72            }
73            PdfConvertError::ValidationError { parameter, reason } => {
74                write!(f, "Validation error for '{}': {}", parameter, reason)
75            }
76            PdfConvertError::EnvError { var_name, message } => {
77                write!(
78                    f,
79                    "Environment variable error for '{}': {}",
80                    var_name, message
81                )
82            }
83            PdfConvertError::OperationError { context, message } => {
84                write!(f, "{}: {}", context, message)
85            }
86        }
87    }
88}
89
90impl std::error::Error for PdfConvertError {
91    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
92        match self {
93            PdfConvertError::IoError { source, .. } => Some(source),
94            PdfConvertError::ApiError { source, .. } => source
95                .as_ref()
96                .map(|e| e as &(dyn std::error::Error + 'static)),
97            _ => None,
98        }
99    }
100}
101
102pub type Result<T> = std::result::Result<T, PdfConvertError>;
103
104impl From<std::io::Error> for PdfConvertError {
105    fn from(err: std::io::Error) -> Self {
106        PdfConvertError::IoError {
107            context: "performing file operation".to_string(),
108            source: err,
109        }
110    }
111}
112
113impl From<reqwest::Error> for PdfConvertError {
114    fn from(err: reqwest::Error) -> Self {
115        let status_code = err.status().map(|s| s.as_u16());
116        let message = err.to_string();
117
118        PdfConvertError::ApiError {
119            status_code,
120            message,
121            source: Some(err),
122        }
123    }
124}
125
126impl From<serde_json::Error> for PdfConvertError {
127    fn from(err: serde_json::Error) -> Self {
128        PdfConvertError::ParseError {
129            target: "JSON".to_string(),
130            message: err.to_string(),
131        }
132    }
133}
134
135impl From<std::env::VarError> for PdfConvertError {
136    fn from(err: std::env::VarError) -> Self {
137        match err {
138            std::env::VarError::NotPresent => PdfConvertError::EnvError {
139                var_name: "unknown".to_string(),
140                message: "Environment variable not set".to_string(),
141            },
142            std::env::VarError::NotUnicode(_) => PdfConvertError::EnvError {
143                var_name: "unknown".to_string(),
144                message: "Environment variable contains invalid Unicode".to_string(),
145            },
146        }
147    }
148}
149
150impl PdfConvertError {
151    pub fn io_error(context: impl Into<String>, source: std::io::Error) -> Self {
152        PdfConvertError::IoError {
153            context: context.into(),
154            source,
155        }
156    }
157
158    pub fn api_error(status_code: Option<u16>, message: impl Into<String>) -> Self {
159        PdfConvertError::ApiError {
160            status_code,
161            message: message.into(),
162            source: None,
163        }
164    }
165
166    pub fn parse_error(target: impl Into<String>, message: impl Into<String>) -> Self {
167        PdfConvertError::ParseError {
168            target: target.into(),
169            message: message.into(),
170        }
171    }
172
173    #[allow(dead_code)]
174    pub fn validation_error(parameter: impl Into<String>, reason: impl Into<String>) -> Self {
175        PdfConvertError::ValidationError {
176            parameter: parameter.into(),
177            reason: reason.into(),
178        }
179    }
180
181    pub fn env_error(var_name: impl Into<String>, message: impl Into<String>) -> Self {
182        PdfConvertError::EnvError {
183            var_name: var_name.into(),
184            message: message.into(),
185        }
186    }
187
188    pub fn operation_error(context: impl Into<String>, message: impl Into<String>) -> Self {
189        PdfConvertError::OperationError {
190            context: context.into(),
191            message: message.into(),
192        }
193    }
194
195    pub fn api_task_failed(status: impl Into<String>, details: impl Into<String>) -> Self {
196        PdfConvertError::ApiError {
197            status_code: None,
198            message: format!(
199                "Task failed - Status: {}, Details: {}",
200                status.into(),
201                details.into()
202            ),
203            source: None,
204        }
205    }
206}