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<lopdf::Error> for PdfConvertError {
136    fn from(err: lopdf::Error) -> Self {
137        PdfConvertError::ParseError {
138            target: "PDF".to_string(),
139            message: err.to_string(),
140        }
141    }
142}
143
144impl From<std::env::VarError> for PdfConvertError {
145    fn from(err: std::env::VarError) -> Self {
146        match err {
147            std::env::VarError::NotPresent => PdfConvertError::EnvError {
148                var_name: "unknown".to_string(),
149                message: "Environment variable not set".to_string(),
150            },
151            std::env::VarError::NotUnicode(_) => PdfConvertError::EnvError {
152                var_name: "unknown".to_string(),
153                message: "Environment variable contains invalid Unicode".to_string(),
154            },
155        }
156    }
157}
158
159impl PdfConvertError {
160    pub fn io_error(context: impl Into<String>, source: std::io::Error) -> Self {
161        PdfConvertError::IoError {
162            context: context.into(),
163            source,
164        }
165    }
166
167    pub fn api_error(status_code: Option<u16>, message: impl Into<String>) -> Self {
168        PdfConvertError::ApiError {
169            status_code,
170            message: message.into(),
171            source: None,
172        }
173    }
174
175    pub fn parse_error(target: impl Into<String>, message: impl Into<String>) -> Self {
176        PdfConvertError::ParseError {
177            target: target.into(),
178            message: message.into(),
179        }
180    }
181
182    #[allow(dead_code)]
183    pub fn validation_error(parameter: impl Into<String>, reason: impl Into<String>) -> Self {
184        PdfConvertError::ValidationError {
185            parameter: parameter.into(),
186            reason: reason.into(),
187        }
188    }
189
190    pub fn env_error(var_name: impl Into<String>, message: impl Into<String>) -> Self {
191        PdfConvertError::EnvError {
192            var_name: var_name.into(),
193            message: message.into(),
194        }
195    }
196
197    pub fn operation_error(context: impl Into<String>, message: impl Into<String>) -> Self {
198        PdfConvertError::OperationError {
199            context: context.into(),
200            message: message.into(),
201        }
202    }
203
204    pub fn api_task_failed(status: impl Into<String>, details: impl Into<String>) -> Self {
205        PdfConvertError::ApiError {
206            status_code: None,
207            message: format!(
208                "Task failed - Status: {}, Details: {}",
209                status.into(),
210                details.into()
211            ),
212            source: None,
213        }
214    }
215}