1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::fmt;

#[derive(Fail, Debug, PartialEq)]
pub enum Error {
    #[fail(display = "Expected {}-{} characters, found {}", min, max, len)]
    InvalidCharacterCount { len: usize, min: usize, max: usize },
    #[fail(display = "Expected {}-{} bytes, found {}", min, max, len)]
    InvalidLength { len: usize, min: usize, max: usize },
    #[fail(display = "Character '{}' @ {} is not allowed", _1, _0)]
    InvalidCharacter(usize, char),
    #[fail(display = "Prefix {} is not allowed", _0)]
    InvalidPrefix(&'static str),
    #[fail(display = "Sequence {} is not allowed", _0)]
    InvalidSequence(&'static str),
    #[fail(display = "{}", _0)]
    Http(#[fail(cause)] HttpError),
    #[fail(display = "{}", _0)]
    HttpStatus(#[fail(cause)] HttpStatusError),
    #[fail(display = "An HTTP response didn't have a valid Content-Length")]
    UnknownContentLength,
    #[fail(display = "GCS API error: {}", _0)]
    API(#[fail(cause)] ApiError),
    #[fail(display = "JSON error: {}", _0)]
    Json(#[fail(cause)] JsonError),
    #[fail(display = "Response body doesn't contain enough data")]
    InsufficientData,
}

#[derive(Debug)]
pub struct HttpError(http::Error);

impl PartialEq for HttpError {
    fn eq(&self, _other: &Self) -> bool {
        // I feel really bad about this
        true
    }
}

impl fmt::Display for HttpError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        std::error::Error::description(self).fmt(f)
    }
}

impl std::error::Error for HttpError {
    fn description(&self) -> &str {
        self.0.description()
    }

    // Return any available cause from the inner error. Note the inner error is
    // not itself the cause.
    #[allow(deprecated)]
    fn cause(&self) -> Option<&std::error::Error> {
        self.0.cause()
    }
}

impl From<http::Error> for Error {
    fn from(e: http::Error) -> Self {
        Error::Http(HttpError(e))
    }
}

#[derive(Debug, Fail)]
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)]
pub struct JsonError(pub(crate) serde_json::Error);

impl PartialEq for JsonError {
    fn eq(&self, other: &Self) -> bool {
        self.0.classify() == other.0.classify()
    }
}

impl fmt::Display for JsonError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        std::error::Error::description(self).fmt(f)
    }
}

impl std::error::Error for JsonError {
    fn description(&self) -> &str {
        self.0.description()
    }

    // Return any available cause from the inner error. Note the inner error is
    // not itself the cause.
    #[allow(deprecated)]
    fn cause(&self) -> Option<&std::error::Error> {
        self.0.cause()
    }
}

#[derive(Debug, PartialEq, Deserialize)]
pub struct ApiErrorInner {
    domain: Option<String>,
    reason: Option<String>,
    message: Option<String>,
}

#[derive(Debug, Fail, 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)
    }
}