use std::fmt;
#[derive(thiserror::Error, Debug, PartialEq)]
pub enum Error {
#[error("Expected {min}-{max} characters, found {len}")]
InvalidCharacterCount { len: usize, min: usize, max: usize },
#[error("Expected {min}-{max} bytes, found {len}")]
InvalidLength { len: usize, min: usize, max: usize },
#[error("Character '{1}' @ {0} is not allowed")]
InvalidCharacter(usize, char),
#[error("Prefix {0} is not allowed")]
InvalidPrefix(&'static str),
#[error("Sequence {0} is not allowed")]
InvalidSequence(&'static str),
#[error("HTTP error")]
Http(#[source] HttpError),
#[error("HTTP status")]
HttpStatus(#[source] HttpStatusError),
#[error("An HTTP response didn't have a valid Content-Length")]
UnknownContentLength,
#[error("GCS API error")]
API(#[source] ApiError),
#[error("JSON error")]
Json(#[source] JsonError),
#[error("Response body doesn't contain enough data")]
InsufficientData,
#[error("Key rejected: {0}")]
KeyRejected(&'static str),
#[error("An error occurred during signing")]
SigningError,
#[error("An expiration duration was too long: requested = {requested}, max = {max}")]
TooLongExpiration { requested: u64, max: u64 },
#[error("Failed to parse url")]
UrlParse(#[source] url::ParseError),
#[error("Unable to stringize header value '{0:?}'")]
OpaqueHeaderValue(http::header::HeaderValue),
#[error("I/O error occurred")]
Io(#[source] IoError),
#[error("Unable to decode base64")]
Base64Decode(#[source] base64::DecodeError),
#[error("Unable to encode url")]
UrlEncode(#[source] serde_urlencoded::ser::Error),
}
#[derive(Debug, thiserror::Error)]
pub struct HttpError(#[source] http::Error);
impl fmt::Display for HttpError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl PartialEq for HttpError {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl From<http::Error> for Error {
fn from(e: http::Error) -> Self {
Error::Http(HttpError(e))
}
}
#[derive(Debug, thiserror::Error)]
pub struct HttpStatusError(http::StatusCode);
impl PartialEq for HttpStatusError {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl fmt::Display for HttpStatusError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<http::StatusCode> for Error {
fn from(e: http::StatusCode) -> Self {
Error::HttpStatus(HttpStatusError(e))
}
}
#[derive(Debug, thiserror::Error)]
pub struct IoError(#[source] std::io::Error);
impl PartialEq for IoError {
fn eq(&self, other: &Self) -> bool {
self.0.kind() == other.0.kind()
}
}
impl fmt::Display for IoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(IoError(e))
}
}
#[derive(Debug, thiserror::Error)]
pub struct JsonError(#[source] pub(crate) serde_json::Error);
impl fmt::Display for JsonError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl PartialEq for JsonError {
fn eq(&self, other: &Self) -> bool {
self.0.classify() == other.0.classify()
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::Json(JsonError(e))
}
}
impl From<serde_urlencoded::ser::Error> for Error {
fn from(e: serde_urlencoded::ser::Error) -> Self {
Error::UrlEncode(e)
}
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct ApiErrorInner {
domain: Option<String>,
reason: Option<String>,
message: Option<String>,
}
#[derive(Debug, thiserror::Error, PartialEq, Deserialize)]
pub struct ApiError {
code: u16,
message: String,
errors: Vec<ApiErrorInner>,
}
impl fmt::Display for ApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#?}", self)
}
}
#[cfg(feature = "signing")]
impl From<ring::error::KeyRejected> for Error {
fn from(re: ring::error::KeyRejected) -> Self {
Error::KeyRejected(re.description_())
}
}
#[cfg(feature = "signing")]
impl From<ring::error::Unspecified> for Error {
fn from(_re: ring::error::Unspecified) -> Self {
Error::SigningError
}
}