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("Dropbox API declined the request due to rate-limiting ({reason}), \
33 retry after {retry_after_seconds}s")]
34 RateLimited {
35 reason: types::auth::RateLimitReason,
37
38 retry_after_seconds: u32,
40 },
41
42 #[error("Dropbox API denied access to the resource: {0}")]
44 AccessDenied(#[source] types::auth::AccessError),
45
46 #[error("Dropbox API had an internal server error: {0}")]
48 ServerError(String),
49
50 #[error("Dropbox API returned HTTP {code} - {response}")]
52 UnexpectedHttpError {
53 code: u16,
55
56 response: String,
58 },
59}
60
61pub type BoxedError = Error<Box<dyn std::error::Error + Send + Sync>>;
71
72impl<E: std::error::Error + 'static> Error<E> {
73 pub fn downcast_ref_inner<E2: std::error::Error + 'static>(&self) -> Option<&E2> {
76 let mut inner = Some(self as &dyn std::error::Error);
77 while let Some(e) = inner {
78 if let Some(e) = e.downcast_ref() {
79 return Some(e);
80 }
81 inner = e.source();
82 }
83 None
84 }
85}
86
87impl<E: std::error::Error + Send + Sync + 'static> Error<E> {
88 pub fn boxed(self) -> BoxedError {
95 match self {
96 Error::Api(e) => Error::Api(Box::new(e)),
97
98 Error::HttpClient(e) => Error::HttpClient(e),
102 Error::Json(e) => Error::Json(e),
103 Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
104 Error::BadRequest(e) => Error::BadRequest(e),
105 Error::Authentication(e) => Error::Authentication(e),
106 Error::RateLimited { reason, retry_after_seconds } => Error::RateLimited { reason, retry_after_seconds },
107 Error::AccessDenied(e) => Error::AccessDenied(e),
108 Error::ServerError(e) => Error::ServerError(e),
109 Error::UnexpectedHttpError { code, response } => Error::UnexpectedHttpError { code, response },
110 }
111 }
112}
113
114impl Error<NoError> {
115 pub fn typed<E>(self) -> Error<E> {
121 match self {
122 Error::Api(x) => unreachable(x),
123 Error::HttpClient(e) => Error::HttpClient(e),
124 Error::Json(e) => Error::Json(e),
125 Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
126 Error::BadRequest(e) => Error::BadRequest(e),
127 Error::Authentication(e) => Error::Authentication(e),
128 Error::RateLimited { reason, retry_after_seconds } => Error::RateLimited { reason, retry_after_seconds },
129 Error::AccessDenied(e) => Error::AccessDenied(e),
130 Error::ServerError(e) => Error::ServerError(e),
131 Error::UnexpectedHttpError { code, response } => Error::UnexpectedHttpError { code, response },
132 }
133 }
134}
135
136
137#[derive(Copy, Clone)]
140pub enum NoError {}
141
142impl PartialEq<NoError> for NoError {
143 fn eq(&self, _: &NoError) -> bool {
144 unreachable(*self)
145 }
146}
147
148impl std::error::Error for NoError {
149 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
150 unreachable(*self)
151 }
152
153 fn description(&self) -> &str {
154 unreachable(*self)
155 }
156
157 fn cause(&self) -> Option<&dyn std::error::Error> {
158 unreachable(*self)
159 }
160}
161
162impl std::fmt::Debug for NoError {
163 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 unreachable(*self)
165 }
166}
167
168impl std::fmt::Display for NoError {
169 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 unreachable(*self)
171 }
172}
173
174impl<'de> serde::de::Deserialize<'de> for NoError {
177 fn deserialize<D: serde::de::Deserializer<'de>>(_: D)
178 -> Result<Self, D::Error>
179 {
180 Err(serde::de::Error::custom(
181 "method has no defined error type, but an error was returned"))
182 }
183}
184
185#[inline(always)]
186fn unreachable(x: NoError) -> ! {
187 match x {}
188}