use crate::types;
#[derive(thiserror::Error, Debug)]
pub enum Error<E = NoError> {
#[error("Dropbox API endpoint returned an error: {0}")]
Api(#[source] E),
#[error("error from HTTP client: {0}")]
HttpClient(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
#[error("JSON serialization error: {0}")]
Json(#[from] serde_json::Error),
#[error("Dropbox API returned something unexpected: {0}")]
UnexpectedResponse(String),
#[error("Dropbox API indicated that the request was malformed: {0}")]
BadRequest(String),
#[error("Dropbox API indicated a problem with authentication: {0}")]
Authentication(#[source] types::auth::AuthError),
#[error(
"Dropbox API declined the request due to rate-limiting ({reason}), \
retry after {retry_after_seconds}s"
)]
RateLimited {
reason: types::auth::RateLimitReason,
retry_after_seconds: u32,
},
#[error("Dropbox API denied access to the resource: {0}")]
AccessDenied(#[source] types::auth::AccessError),
#[error("Dropbox API had an internal server error: {0}")]
ServerError(String),
#[error("Dropbox API returned HTTP {code} - {response}")]
UnexpectedHttpError {
code: u16,
response: String,
},
}
pub type BoxedError = Error<Box<dyn std::error::Error + Send + Sync>>;
impl<E: std::error::Error + 'static> Error<E> {
pub fn downcast_ref_inner<E2: std::error::Error + 'static>(&self) -> Option<&E2> {
let mut inner = Some(self as &dyn std::error::Error);
while let Some(e) = inner {
if let Some(e) = e.downcast_ref() {
return Some(e);
}
inner = e.source();
}
None
}
}
impl<E: std::error::Error + Send + Sync + 'static> Error<E> {
pub fn boxed(self) -> BoxedError {
match self {
Error::Api(e) => Error::Api(Box::new(e)),
Error::HttpClient(e) => Error::HttpClient(e),
Error::Json(e) => Error::Json(e),
Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
Error::BadRequest(e) => Error::BadRequest(e),
Error::Authentication(e) => Error::Authentication(e),
Error::RateLimited {
reason,
retry_after_seconds,
} => Error::RateLimited {
reason,
retry_after_seconds,
},
Error::AccessDenied(e) => Error::AccessDenied(e),
Error::ServerError(e) => Error::ServerError(e),
Error::UnexpectedHttpError { code, response } => {
Error::UnexpectedHttpError { code, response }
}
}
}
}
impl Error<NoError> {
pub fn typed<E>(self) -> Error<E> {
match self {
Error::Api(x) => unreachable(x),
Error::HttpClient(e) => Error::HttpClient(e),
Error::Json(e) => Error::Json(e),
Error::UnexpectedResponse(e) => Error::UnexpectedResponse(e),
Error::BadRequest(e) => Error::BadRequest(e),
Error::Authentication(e) => Error::Authentication(e),
Error::RateLimited {
reason,
retry_after_seconds,
} => Error::RateLimited {
reason,
retry_after_seconds,
},
Error::AccessDenied(e) => Error::AccessDenied(e),
Error::ServerError(e) => Error::ServerError(e),
Error::UnexpectedHttpError { code, response } => {
Error::UnexpectedHttpError { code, response }
}
}
}
}
#[derive(Copy, Clone)]
pub enum NoError {}
impl PartialEq<NoError> for NoError {
fn eq(&self, _: &NoError) -> bool {
unreachable(*self)
}
}
impl std::error::Error for NoError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
unreachable(*self)
}
fn description(&self) -> &str {
unreachable(*self)
}
fn cause(&self) -> Option<&dyn std::error::Error> {
unreachable(*self)
}
}
impl std::fmt::Debug for NoError {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unreachable(*self)
}
}
impl std::fmt::Display for NoError {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unreachable(*self)
}
}
impl<'de> serde::de::Deserialize<'de> for NoError {
fn deserialize<D: serde::de::Deserializer<'de>>(_: D) -> Result<Self, D::Error> {
Err(serde::de::Error::custom(
"method has no defined error type, but an error was returned",
))
}
}
#[inline(always)]
fn unreachable(x: NoError) -> ! {
match x {}
}