gaunt/
error.rs

1//! Error types used by **gaunt.rs**
2
3#![allow(unused_macros)]
4
5#[cfg(feature = "alloc")]
6use prelude::*;
7
8#[cfg(feature = "alloc")]
9use core::{num::ParseIntError, str::Utf8Error};
10use failure::Context;
11
12#[cfg(feature = "std")]
13use std::{
14    error::Error as StdError,
15    fmt::{self, Display},
16    io,
17    string::{FromUtf8Error, String, ToString},
18};
19
20/// Error type
21#[derive(Debug)]
22pub struct Error {
23    /// Error context and kind
24    inner: Context<ErrorKind>,
25
26    /// Optional description
27    #[cfg(feature = "alloc")]
28    description: Option<String>,
29}
30
31impl Error {
32    /// Create a new error object with an optional error message
33    #[allow(unused_variables)]
34    pub fn new(kind: ErrorKind, description: Option<&str>) -> Self {
35        #[cfg_attr(not(feature = "alloc"), allow(unused_mut))]
36        let mut err = Self::from(kind);
37
38        #[cfg(feature = "alloc")]
39        {
40            err.description = description.map(|desc| desc.into());
41        }
42
43        err
44    }
45
46    /// Obtain the inner `ErrorKind` for this `Error`
47    pub fn kind(&self) -> ErrorKind {
48        *self.inner.get_context()
49    }
50}
51
52#[cfg(feature = "alloc")]
53impl Display for Error {
54    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55        self.description().fmt(f)
56    }
57}
58
59#[cfg(feature = "alloc")]
60impl StdError for Error {
61    fn description(&self) -> &str {
62        if let Some(ref desc) = self.description {
63            desc
64        } else {
65            "(none)"
66        }
67    }
68}
69
70impl From<ErrorKind> for Error {
71    fn from(kind: ErrorKind) -> Error {
72        Error {
73            inner: Context::new(kind),
74            #[cfg(feature = "alloc")]
75            description: None,
76        }
77    }
78}
79
80impl From<Context<ErrorKind>> for Error {
81    fn from(inner: Context<ErrorKind>) -> Self {
82        Self {
83            inner,
84            #[cfg(feature = "alloc")]
85            description: None,
86        }
87    }
88}
89
90/// Kinds of errors
91#[derive(Copy, Clone, Debug, Fail, Eq, PartialEq)]
92pub enum ErrorKind {
93    /// Invalid address
94    #[fail(display = "address invalid")]
95    AddrInvalid,
96
97    /// I/O operation failed
98    #[fail(display = "I/O error")]
99    IoError,
100
101    /// Parsing data failed
102    #[fail(display = "parse error")]
103    ParseError,
104
105    /// Request failed
106    #[fail(display = "request error")]
107    RequestError,
108
109    /// Error reading response
110    #[fail(display = "error reading response")]
111    ResponseError,
112}
113
114/// Create a new error (of a given enum variant) with a formatted message
115macro_rules! err {
116    ($variant:ident, $msg:expr) => {
117        ::error::Error::new(
118            ::error::ErrorKind::$variant,
119            Some($msg)
120        )
121    };
122    ($variant:ident, $fmt:expr, $($arg:tt)+) => {
123        err!($variant, &format!($fmt, $($arg)+))
124    };
125}
126
127/// Create and return an error with a formatted message
128macro_rules! fail {
129    ($kind:ident, $msg:expr) => {
130        return Err(err!($kind, $msg).into());
131    };
132    ($kind:ident, $fmt:expr, $($arg:tt)+) => {
133        fail!($kind, &format!($fmt, $($arg)+));
134    };
135}
136
137/// Assert a condition is true, returning an error type with a formatted message if not
138macro_rules! ensure {
139    ($condition: expr, $variant:ident, $msg:expr) => {
140        if !($condition) {
141            return Err(err!($variant, $msg).into());
142        }
143    };
144    ($condition: expr, $variant:ident, $fmt:expr, $($arg:tt)+) => {
145        ensure!($variant, $fmt, $($arg)+);
146    };
147}
148
149#[cfg(feature = "alloc")]
150impl From<ParseIntError> for Error {
151    fn from(err: ParseIntError) -> Self {
152        err!(ParseError, &err.to_string())
153    }
154}
155
156#[cfg(feature = "std")]
157impl From<FromUtf8Error> for Error {
158    fn from(err: FromUtf8Error) -> Self {
159        err!(ParseError, &err.to_string())
160    }
161}
162
163#[cfg(feature = "alloc")]
164impl From<Utf8Error> for Error {
165    fn from(err: Utf8Error) -> Self {
166        err!(ParseError, &err.to_string())
167    }
168}
169
170#[cfg(feature = "std")]
171impl From<fmt::Error> for Error {
172    fn from(err: fmt::Error) -> Self {
173        err!(RequestError, &err.to_string())
174    }
175}
176
177#[cfg(feature = "std")]
178impl From<io::Error> for Error {
179    fn from(err: io::Error) -> Self {
180        err!(IoError, &err.to_string())
181    }
182}