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
use std::{error::Error as StdError, fmt};

#[derive(Debug)]
pub struct Error {
    pub message: Option<String>,
    pub kind: Box<ErrorKind>,
}

impl Error {
    pub fn request(err: serde_json::Error) -> Self {
        Self {
            message: None,
            kind: Box::new(ErrorKind::Request(err)),
        }
    }

    pub fn response(err: serde_json::Error) -> Self {
        Self {
            message: None,
            kind: Box::new(ErrorKind::Response(err)),
        }
    }

    /// Creates a wrapper to easily embed messages in the error handling.
    /// Meant to be used like:
    ///
    /// ```
    /// Error::message("A cool message")
    /// ```
    pub fn message<S, E>(message: S) -> Box<dyn FnOnce(E) -> Self>
    where
        ErrorKind: From<E>,
        S: Into<String>,
    {
        let message: String = message.into();

        Box::new(move |kind| Self {
            message: Some(message),
            kind: Box::new(ErrorKind::from(kind)),
        })
    }

    pub fn http(err: http::Error) -> Self {
        Self {
            message: None,
            kind: Box::new(ErrorKind::Http(err)),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.kind)?;

        if let Some(ref msg) = self.message {
            write!(f, ". Message: {}", msg)?;
        }
        Ok(())
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self.kind {
            ErrorKind::Http(ref err) => Some(err),
            ErrorKind::Net(ref err) => Some(err),
            ErrorKind::Request(ref err) => Some(err),
            ErrorKind::Response(ref err) => Some(err),
        }
    }
}

impl<E> From<E> for Error
where
    ErrorKind: From<E>,
{
    fn from(e: E) -> Self {
        Self {
            message: None,
            kind: Box::new(ErrorKind::from(e)),
        }
    }
}

#[derive(Debug)]
pub enum ErrorKind {
    Http(http::Error),
    Net(hyper::Error),
    Request(serde_json::Error),
    Response(serde_json::Error),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrorKind::Http(ref err) => write!(f, "Http Error: {}", err),
            ErrorKind::Net(ref err) => write!(f, "Network Error: {}", err),
            ErrorKind::Request(ref err) => write!(f, "Error when building request: {}", err),
            ErrorKind::Response(ref err) => write!(f, "Error parsing response: {}", err),
        }
    }
}

impl From<hyper::Error> for ErrorKind {
    fn from(err: hyper::Error) -> Self {
        ErrorKind::Net(err)
    }
}

impl From<serde_json::Error> for ErrorKind {
    fn from(err: serde_json::Error) -> Self {
        Self::Response(err)
    }
}