use bytes::Bytes;
use http::{StatusCode, uri::InvalidUri};
use snafu::{Location, Snafu};
use url::Url;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
#[snafu(display("server returned a non-success http status code {status}"))]
NonSuccessStatus {
status: StatusCode,
body: Bytes,
},
#[snafu(display("could not build http request: {source}"))]
BuildRequest {
source: http::Error,
},
#[snafu(display("base url {url} cannot be a base"))]
UrlCannotBeABase {
url: Url,
},
#[snafu(display("couldn't parse uri"))]
ParseUri {
source: InvalidUri,
},
#[snafu(display("can't create query string: {message}"))]
QueryString {
message: String,
},
#[cfg(feature = "serde")]
#[snafu(display("couldn't build query string from serde url params"))]
SerdeUrlParams {
source: serde_url_params::Error,
},
#[cfg(feature = "serde")]
#[snafu(display("serde json error"))]
Json {
source: serde_json::Error,
},
#[snafu(display("{message}"))]
Custom {
message: String,
location: Location,
},
}
impl Error {
#[track_caller]
pub fn custom(message: String) -> Self {
let location = core::panic::Location::caller();
Error::Custom { message, location }
}
pub const fn is_unauthorized(&self) -> bool {
self.is_specific_http_error_status(&StatusCode::UNAUTHORIZED)
}
pub const fn is_not_found(&self) -> bool {
self.is_specific_http_error_status(&StatusCode::NOT_FOUND)
}
pub const fn is_bad_request(&self) -> bool {
self.is_specific_http_error_status(&StatusCode::BAD_REQUEST)
}
pub const fn is_internal_server_error(&self) -> bool {
self.is_specific_http_error_status(&StatusCode::INTERNAL_SERVER_ERROR)
}
pub const fn is_http_error_status(&self) -> bool {
matches!(self, Self::NonSuccessStatus { .. })
}
pub const fn is_specific_http_error_status(&self, specific_status: &StatusCode) -> bool {
matches!(self, Self::NonSuccessStatus { status,.. } if status.as_u16() == specific_status.as_u16())
}
}