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
use reqwest::Error as ReqwestError;
use serde_json::Error as JsonError;
use std::error::Error as StdError;
use std::fmt::Display;
use std::io::Error as IoError;
use std::num::ParseIntError;

/// Random.org API `Result` alias type.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Random.org error code.
#[derive(Debug, Clone, serde::Deserialize)]
pub struct ErrorCode(pub u64);

/// Random.org response error definition.
///
/// If an error occurred, this member contains a service-specific error object with details
/// about the error. If no error occurred, this member is not included in the response.
#[derive(Debug, Clone, serde::Deserialize)]
pub struct ResponseError {
    /// A numeric error code that uniquely identifies the error type.
    pub code: ErrorCode,
    /// A string containing a human-readable error message in English suitable for printing in a
    /// log file or as part of an error message to be displayed to a user.
    pub message: String,
    /*
    /// Any values that the client needs to construct its own error message, for example in a
    /// different language than English.
    // pub data:
     */
}

/// Random.org API crate error type.
#[derive(Debug)]
pub enum Error {
    /// A `reqwest` crate error
    Reqwest(ReqwestError),
    /// A `serde_json` crate error
    Json(JsonError),
    /// A `std::io` module error
    Io(IoError),
    /// A parse number error
    ParseIntError(ParseIntError),
    /// A error common toornament service error
    RandomOrg(::reqwest::StatusCode, ResponseError),
    /// A generic non-success response from the REST API
    Status(::reqwest::StatusCode, String),
    /// A rest-api error
    Rest(&'static str),
}

impl From<ParseIntError> for Error {
    fn from(e: ParseIntError) -> Error {
        Error::ParseIntError(e)
    }
}

impl From<::reqwest::blocking::Response> for Error {
    fn from(mut response: ::reqwest::blocking::Response) -> Error {
        use std::io::Read;

        #[derive(serde::Deserialize)]
        pub struct ErrorObject {
            error: ResponseError,
        }

        let status = response.status();
        let mut body = String::new();
        let _ = response.read_to_string(&mut body);
        if !status.is_success() {
            if let Ok(e) = ::serde_json::from_str::<ErrorObject>(&body) {
                return Error::RandomOrg(status, e.error);
            }
        }
        Error::Status(status, body)
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl From<ReqwestError> for Error {
    fn from(err: ReqwestError) -> Error {
        Error::Reqwest(err)
    }
}

impl From<JsonError> for Error {
    fn from(err: JsonError) -> Error {
        Error::Json(err)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Reqwest(ref inner) => inner.fmt(f),
            Error::Json(ref inner) => inner.fmt(f),
            Error::Io(ref inner) => inner.fmt(f),
            _ => f.write_str(&self.to_string()),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Reqwest(ref inner) => Some(inner),
            Error::Json(ref inner) => Some(inner),
            Error::Io(ref inner) => Some(inner),
            Error::ParseIntError(ref inner) => Some(inner),
            _ => None,
        }
    }
}