1use std::error;
7use std::fmt;
8use std::io;
9use std::str::Utf8Error;
10use std::sync::Arc;
11
12#[derive(Clone, Debug)]
14pub enum Error {
15 Api {
17 status_code: u16,
19 error_type: Option<String>,
21 message: String,
23 request_id: Option<String>,
25 },
26
27 Authentication {
29 message: String,
31 },
32
33 Permission {
35 message: String,
37 },
38
39 NotFound {
41 message: String,
43 resource_type: Option<String>,
45 resource_id: Option<String>,
47 },
48
49 RateLimit {
51 message: String,
53 retry_after: Option<u64>,
55 },
56
57 BadRequest {
59 message: String,
61 param: Option<String>,
63 },
64
65 Timeout {
67 message: String,
69 duration: Option<f64>,
71 },
72
73 Abort {
75 message: String,
77 },
78
79 Connection {
81 message: String,
83 source: Option<Arc<dyn error::Error + Send + Sync>>,
85 },
86
87 InternalServer {
89 message: String,
91 request_id: Option<String>,
93 },
94
95 ServiceUnavailable {
97 message: String,
99 retry_after: Option<u64>,
101 },
102
103 Serialization {
105 message: String,
107 source: Option<Arc<dyn error::Error + Send + Sync>>,
109 },
110
111 Io {
113 message: String,
115 source: Arc<io::Error>,
117 },
118
119 HttpClient {
121 message: String,
123 source: Option<Arc<dyn error::Error + Send + Sync>>,
125 },
126
127 Validation {
129 message: String,
131 param: Option<String>,
133 },
134
135 Url {
137 message: String,
139 source: Option<url::ParseError>,
141 },
142
143 Streaming {
145 message: String,
147 source: Option<Arc<dyn error::Error + Send + Sync>>,
149 },
150
151 Encoding {
153 message: String,
155 source: Option<Arc<dyn error::Error + Send + Sync>>,
157 },
158
159 Unknown {
161 message: String,
163 },
164
165 ToDo {
167 message: String,
169 },
170}
171
172impl Error {
173 pub fn api(
175 status_code: u16,
176 error_type: Option<String>,
177 message: String,
178 request_id: Option<String>,
179 ) -> Self {
180 Error::Api { status_code, error_type, message, request_id }
181 }
182
183 pub fn authentication(message: impl Into<String>) -> Self {
185 Error::Authentication { message: message.into() }
186 }
187
188 pub fn permission(message: impl Into<String>) -> Self {
190 Error::Permission { message: message.into() }
191 }
192
193 pub fn not_found(
195 message: impl Into<String>,
196 resource_type: Option<String>,
197 resource_id: Option<String>,
198 ) -> Self {
199 Error::NotFound { message: message.into(), resource_type, resource_id }
200 }
201
202 pub fn rate_limit(message: impl Into<String>, retry_after: Option<u64>) -> Self {
204 Error::RateLimit { message: message.into(), retry_after }
205 }
206
207 pub fn bad_request(message: impl Into<String>, param: Option<String>) -> Self {
209 Error::BadRequest { message: message.into(), param }
210 }
211
212 pub fn timeout(message: impl Into<String>, duration: Option<f64>) -> Self {
214 Error::Timeout { message: message.into(), duration }
215 }
216
217 pub fn abort(message: impl Into<String>) -> Self {
219 Error::Abort { message: message.into() }
220 }
221
222 pub fn connection(
224 message: impl Into<String>,
225 source: Option<Box<dyn error::Error + Send + Sync>>,
226 ) -> Self {
227 Error::Connection { message: message.into(), source: source.map(Arc::from) }
228 }
229
230 pub fn internal_server(message: impl Into<String>, request_id: Option<String>) -> Self {
232 Error::InternalServer { message: message.into(), request_id }
233 }
234
235 pub fn service_unavailable(message: impl Into<String>, retry_after: Option<u64>) -> Self {
237 Error::ServiceUnavailable { message: message.into(), retry_after }
238 }
239
240 pub fn serialization(
242 message: impl Into<String>,
243 source: Option<Box<dyn error::Error + Send + Sync>>,
244 ) -> Self {
245 Error::Serialization { message: message.into(), source: source.map(Arc::from) }
246 }
247
248 pub fn io(message: impl Into<String>, source: io::Error) -> Self {
250 Error::Io { message: message.into(), source: Arc::new(source) }
251 }
252
253 pub fn http_client(
255 message: impl Into<String>,
256 source: Option<Box<dyn error::Error + Send + Sync>>,
257 ) -> Self {
258 Error::HttpClient { message: message.into(), source: source.map(Arc::from) }
259 }
260
261 pub fn validation(message: impl Into<String>, param: Option<String>) -> Self {
263 Error::Validation { message: message.into(), param }
264 }
265
266 pub fn url(message: impl Into<String>, source: Option<url::ParseError>) -> Self {
268 Error::Url { message: message.into(), source }
269 }
270
271 pub fn streaming(
273 message: impl Into<String>,
274 source: Option<Box<dyn error::Error + Send + Sync>>,
275 ) -> Self {
276 Error::Streaming { message: message.into(), source: source.map(Arc::from) }
277 }
278
279 pub fn encoding(
281 message: impl Into<String>,
282 source: Option<Box<dyn error::Error + Send + Sync>>,
283 ) -> Self {
284 Error::Encoding { message: message.into(), source: source.map(Arc::from) }
285 }
286
287 pub fn unknown(message: impl Into<String>) -> Self {
289 Error::Unknown { message: message.into() }
290 }
291
292 pub fn todo(message: impl Into<String>) -> Self {
294 Error::ToDo { message: message.into() }
295 }
296
297 pub fn is_authentication(&self) -> bool {
299 matches!(self, Error::Authentication { .. })
300 }
301
302 pub fn is_permission(&self) -> bool {
304 matches!(self, Error::Permission { .. })
305 }
306
307 pub fn is_not_found(&self) -> bool {
309 matches!(self, Error::NotFound { .. })
310 }
311
312 pub fn is_rate_limit(&self) -> bool {
314 matches!(self, Error::RateLimit { .. })
315 }
316
317 pub fn is_bad_request(&self) -> bool {
319 matches!(self, Error::BadRequest { .. })
320 }
321
322 pub fn is_timeout(&self) -> bool {
324 matches!(self, Error::Timeout { .. })
325 }
326
327 pub fn is_abort(&self) -> bool {
329 matches!(self, Error::Abort { .. })
330 }
331
332 pub fn is_connection(&self) -> bool {
334 matches!(self, Error::Connection { .. })
335 }
336
337 pub fn is_server_error(&self) -> bool {
339 matches!(self, Error::InternalServer { .. } | Error::ServiceUnavailable { .. })
340 }
341
342 pub fn is_retryable(&self) -> bool {
344 match self {
345 Error::Api { status_code, .. } => {
346 matches!(status_code, 408 | 409 | 429 | 500..=599)
347 }
348 Error::Timeout { .. } => true,
349 Error::Connection { .. } => true,
350 Error::RateLimit { .. } => true,
351 Error::ServiceUnavailable { .. } => true,
352 Error::InternalServer { .. } => true,
353 _ => false,
354 }
355 }
356
357 pub fn is_todo(&self) -> bool {
359 matches!(self, Error::ToDo { .. })
360 }
361
362 pub fn is_validation(&self) -> bool {
364 matches!(self, Error::Validation { .. })
365 }
366
367 pub fn request_id(&self) -> Option<&str> {
369 match self {
370 Error::Api { request_id, .. } => request_id.as_deref(),
371 Error::InternalServer { request_id, .. } => request_id.as_deref(),
372 _ => None,
373 }
374 }
375
376 pub fn status_code(&self) -> Option<u16> {
378 match self {
379 Error::Api { status_code, .. } => Some(*status_code),
380 _ => None,
381 }
382 }
383}
384
385impl fmt::Display for Error {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 match self {
388 Error::Api { message, error_type, request_id, .. } => {
389 if let Some(error_type) = error_type {
390 if let Some(request_id) = request_id {
391 write!(f, "{error_type}: {message} (Request ID: {request_id})")
392 } else {
393 write!(f, "{error_type}: {message}")
394 }
395 } else if let Some(request_id) = request_id {
396 write!(f, "API error: {message} (Request ID: {request_id})")
397 } else {
398 write!(f, "API error: {message}")
399 }
400 }
401 Error::Authentication { message } => {
402 write!(f, "Authentication error: {message}")
403 }
404 Error::Permission { message } => {
405 write!(f, "Permission error: {message}")
406 }
407 Error::NotFound { message, resource_type, resource_id } => {
408 let prefix = if let Some(resource_type) = resource_type {
409 format!("Resource not found ({resource_type})")
410 } else {
411 "Resource not found".to_string()
412 };
413
414 let suffix = if let Some(resource_id) = resource_id {
415 format!(" [ID: {resource_id}]")
416 } else {
417 "".to_string()
418 };
419
420 write!(f, "{prefix}: {message}{suffix}")
421 }
422 Error::RateLimit { message, retry_after } => {
423 if let Some(retry_after) = retry_after {
424 write!(f, "Rate limit exceeded: {message} (retry after {retry_after} seconds)")
425 } else {
426 write!(f, "Rate limit exceeded: {message}")
427 }
428 }
429 Error::BadRequest { message, param } => {
430 if let Some(param) = param {
431 write!(f, "Bad request: {message} (parameter: {param})")
432 } else {
433 write!(f, "Bad request: {message}")
434 }
435 }
436 Error::Timeout { message, duration } => {
437 if let Some(duration) = duration {
438 write!(f, "Timeout error: {message} ({duration} seconds)")
439 } else {
440 write!(f, "Timeout error: {message}")
441 }
442 }
443 Error::Abort { message } => {
444 write!(f, "Request aborted: {message}")
445 }
446 Error::Connection { message, .. } => {
447 write!(f, "Connection error: {message}")
448 }
449 Error::InternalServer { message, request_id } => {
450 if let Some(request_id) = request_id {
451 write!(f, "Internal server error: {message} (Request ID: {request_id})")
452 } else {
453 write!(f, "Internal server error: {message}")
454 }
455 }
456 Error::ServiceUnavailable { message, retry_after } => {
457 if let Some(retry_after) = retry_after {
458 write!(f, "Service unavailable: {message} (retry after {retry_after} seconds)")
459 } else {
460 write!(f, "Service unavailable: {message}")
461 }
462 }
463 Error::Serialization { message, .. } => {
464 write!(f, "Serialization error: {message}")
465 }
466 Error::Io { message, .. } => {
467 write!(f, "I/O error: {message}")
468 }
469 Error::HttpClient { message, .. } => {
470 write!(f, "HTTP client error: {message}")
471 }
472 Error::Validation { message, param } => {
473 if let Some(param) = param {
474 write!(f, "Validation error: {message} (parameter: {param})")
475 } else {
476 write!(f, "Validation error: {message}")
477 }
478 }
479 Error::Url { message, .. } => {
480 write!(f, "URL error: {message}")
481 }
482 Error::Streaming { message, .. } => {
483 write!(f, "Streaming error: {message}")
484 }
485 Error::Encoding { message, .. } => {
486 write!(f, "Encoding error: {message}")
487 }
488 Error::Unknown { message } => {
489 write!(f, "Unknown error: {message}")
490 }
491 Error::ToDo { message } => {
492 write!(f, "Unimplemented: {message}")
493 }
494 }
495 }
496}
497
498impl error::Error for Error {
499 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
500 match self {
501 Error::Connection { source, .. } => {
502 source.as_ref().map(|e| e.as_ref() as &(dyn error::Error + 'static))
503 }
504 Error::Serialization { source, .. } => {
505 source.as_ref().map(|e| e.as_ref() as &(dyn error::Error + 'static))
506 }
507 Error::Io { source, .. } => Some(source),
508 Error::HttpClient { source, .. } => {
509 source.as_ref().map(|e| e.as_ref() as &(dyn error::Error + 'static))
510 }
511 Error::Url { source, .. } => {
512 source.as_ref().map(|e| e as &(dyn error::Error + 'static))
513 }
514 Error::Streaming { source, .. } => {
515 source.as_ref().map(|e| e.as_ref() as &(dyn error::Error + 'static))
516 }
517 Error::Encoding { source, .. } => {
518 source.as_ref().map(|e| e.as_ref() as &(dyn error::Error + 'static))
519 }
520 _ => None,
521 }
522 }
523}
524
525impl From<io::Error> for Error {
526 fn from(err: io::Error) -> Self {
527 Error::io(err.to_string(), err)
528 }
529}
530
531impl From<serde_json::Error> for Error {
532 fn from(err: serde_json::Error) -> Self {
533 Error::serialization(format!("JSON error: {err}"), Some(Box::new(err)))
534 }
535}
536
537impl From<url::ParseError> for Error {
538 fn from(err: url::ParseError) -> Self {
539 Error::url(format!("URL parse error: {err}"), Some(err))
540 }
541}
542
543impl From<Utf8Error> for Error {
544 fn from(err: Utf8Error) -> Self {
545 Error::encoding(format!("UTF-8 error: {err}"), Some(Box::new(err)))
546 }
547}
548
549pub type Result<T> = std::result::Result<T, Error>;