1use crate::types;
2
3#[derive(thiserror::Error, Debug)]
6pub enum Error<E = NoError> {
7 #[error("Dropbox API endpoint returned an error: {0}")]
9 Api(#[source] E),
10
11 #[error("error from HTTP client: {0}")]
13 HttpClient(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
14
15 #[error("JSON serialization error: {0}")]
17 Json(#[from] serde_json::Error),
18
19 #[error("Dropbox API returned something unexpected: {0}")]
21 UnexpectedResponse(String),
22
23 #[error("Dropbox API indicated that the request was malformed: {0}")]
25 BadRequest(String),
26
27 #[error("Dropbox API indicated a problem with authentication: {0}")]
29 Authentication(#[source] types::auth::AuthError),
30
31 #[error(
33 "Dropbox API declined the request due to rate-limiting ({reason}), \
34 retry after {retry_after_seconds}s"
35 )]
36 RateLimited {
37 reason: types::auth::RateLimitReason,
39
40 retry_after_seconds: u32,
42 },
43
44 #[error("Dropbox API denied access to the resource: {0}")]
46 AccessDenied(#[source] types::auth::AccessError),
47
48 #[error("Dropbox API had an internal server error: {0}")]
50 ServerError(String),
51
52 #[error("Dropbox API returned HTTP {code} - {response}")]
54 UnexpectedHttpError {
55 code: u16,
57
58 response: String,
60 },
61}
62
63pub type BoxedError = Error<Box<dyn std::error::Error + Send + Sync>>;
73
74impl<E: std::error::Error + 'static> Error<E> {
75 pub fn downcast_ref_inner<E2: std::error::Error + 'static>(&self) -> Option<&E2> {
78 let mut inner = Some(self as &dyn std::error::Error);
79 while let Some(e) = inner {
80 if let Some(e) = e.downcast_ref() {
81 return Some(e);
82 }
83 inner = e.source();
84 }
85 None
86 }
87}
88
89impl<E: std::error::Error + Send + Sync + 'static> Error<E> {
90 pub fn boxed(self) -> BoxedError {
97 match self {
98 Error::Api(e) => Error::Api(Box::new(e)),
99
100 Error::HttpClient(e) => Error::HttpClient(e),
104 Error::Json(e) => Error::Json(e),
105 Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
106 Error::BadRequest(e) => Error::BadRequest(e),
107 Error::Authentication(e) => Error::Authentication(e),
108 Error::RateLimited {
109 reason,
110 retry_after_seconds,
111 } => Error::RateLimited {
112 reason,
113 retry_after_seconds,
114 },
115 Error::AccessDenied(e) => Error::AccessDenied(e),
116 Error::ServerError(e) => Error::ServerError(e),
117 Error::UnexpectedHttpError { code, response } => {
118 Error::UnexpectedHttpError { code, response }
119 }
120 }
121 }
122}
123
124impl Error<NoError> {
125 pub fn typed<E>(self) -> Error<E> {
131 match self {
132 Error::Api(x) => unreachable(x),
133 Error::HttpClient(e) => Error::HttpClient(e),
134 Error::Json(e) => Error::Json(e),
135 Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
136 Error::BadRequest(e) => Error::BadRequest(e),
137 Error::Authentication(e) => Error::Authentication(e),
138 Error::RateLimited {
139 reason,
140 retry_after_seconds,
141 } => Error::RateLimited {
142 reason,
143 retry_after_seconds,
144 },
145 Error::AccessDenied(e) => Error::AccessDenied(e),
146 Error::ServerError(e) => Error::ServerError(e),
147 Error::UnexpectedHttpError { code, response } => {
148 Error::UnexpectedHttpError { code, response }
149 }
150 }
151 }
152}
153
154#[derive(Copy, Clone)]
157pub enum NoError {}
158
159impl PartialEq<NoError> for NoError {
160 fn eq(&self, _: &NoError) -> bool {
161 unreachable(*self)
162 }
163}
164
165impl std::error::Error for NoError {
166 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
167 unreachable(*self)
168 }
169
170 fn description(&self) -> &str {
171 unreachable(*self)
172 }
173
174 fn cause(&self) -> Option<&dyn std::error::Error> {
175 unreachable(*self)
176 }
177}
178
179impl std::fmt::Debug for NoError {
180 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 unreachable(*self)
182 }
183}
184
185impl std::fmt::Display for NoError {
186 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 unreachable(*self)
188 }
189}
190
191impl<'de> serde::de::Deserialize<'de> for NoError {
194 fn deserialize<D: serde::de::Deserializer<'de>>(_: D) -> Result<Self, D::Error> {
195 Err(serde::de::Error::custom(
196 "method has no defined error type, but an error was returned",
197 ))
198 }
199}
200
201#[inline(always)]
202fn unreachable(x: NoError) -> ! {
203 match x {}
204}