crates_io_api_wasm_patch/
error.rs

1//! Error types.
2
3/// Errors returned by the api client.
4#[derive(Debug)]
5#[non_exhaustive]
6pub enum Error {
7    /// Low-level http error.
8    Http(reqwest::Error),
9    /// Invalid URL.
10    Url(url::ParseError),
11    /// Crate could not be found.
12    NotFound(NotFoundError),
13    /// No permission to access the resource.
14    PermissionDenied(PermissionDeniedError),
15    /// JSON decoding of API response failed.
16    JsonDecode(JsonDecodeError),
17    /// Error returned by the crates.io API directly.
18    Api(crate::types::ApiErrors),
19}
20
21impl std::fmt::Display for Error {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            Error::Http(e) => e.fmt(f),
25            Error::Url(e) => e.fmt(f),
26            Error::NotFound(e) => e.fmt(f),
27            Error::PermissionDenied(e) => e.fmt(f),
28            Error::Api(err) => {
29                let inner = if err.errors.is_empty() {
30                    "Unknown API error".to_string()
31                } else {
32                    err.errors
33                        .iter()
34                        .map(|err| err.to_string())
35                        .collect::<Vec<_>>()
36                        .join(", ")
37                };
38
39                write!(f, "API Error ({})", inner)
40            }
41            Error::JsonDecode(err) => write!(f, "Could not decode API JSON response: {err}"),
42        }
43    }
44}
45
46impl std::error::Error for Error {
47    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
48        match self {
49            Error::Http(e) => Some(e),
50            Error::Url(e) => Some(e),
51            Error::NotFound(_) => None,
52            Error::PermissionDenied(_) => None,
53            Error::Api(_) => None,
54            Error::JsonDecode(err) => Some(err),
55        }
56    }
57
58    // TODO: uncomment once backtrace feature is stabilized (https://github.com/rust-lang/rust/issues/53487).
59    /*
60    fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
61        match self {
62            Self::Http(e) => e.backtrace(),
63            Self::Url(e) => e.backtrace(),
64            Self::InvalidHeader(e) => e.backtrace(),
65            Self::NotFound(_) => None,
66        }
67    }
68    */
69}
70
71impl From<reqwest::Error> for Error {
72    fn from(e: reqwest::Error) -> Self {
73        Error::Http(e)
74    }
75}
76
77impl From<url::ParseError> for Error {
78    fn from(e: url::ParseError) -> Self {
79        Error::Url(e)
80    }
81}
82
83/// Error returned when the JSON returned by the API could not be decoded.
84#[derive(Debug)]
85pub struct JsonDecodeError {
86    pub(crate) message: String,
87}
88
89impl std::fmt::Display for JsonDecodeError {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "Could not decode JSON: {}", self.message)
92    }
93}
94
95impl std::error::Error for JsonDecodeError {}
96
97/// Error returned when a resource could not be found.
98#[derive(Debug)]
99pub struct NotFoundError {
100    pub(crate) url: String,
101}
102
103impl std::fmt::Display for NotFoundError {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        write!(f, "Resource at url '{}' could not be found", self.url)
106    }
107}
108
109/// Error returned when a resource is not accessible.
110#[derive(Debug)]
111pub struct PermissionDeniedError {
112    pub(crate) reason: String,
113}
114
115impl std::fmt::Display for PermissionDeniedError {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        write!(f, "Permission denied: {}", self.reason)
118    }
119}