Skip to content

Commit 21824a6

Browse files
refactor: use thiserror for error handlign
1 parent a890f98 commit 21824a6

File tree

2 files changed

+24
-116
lines changed

2 files changed

+24
-116
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ stop-token = { version = "0.1.1", features = ["unstable"] }
3636
byte-pool = "0.2.1"
3737
lazy_static = "1.4.0"
3838
log = "0.4.8"
39+
thiserror = "1.0.9"
3940

4041
[dev-dependencies]
4142
lettre_email = "0.9"

src/error.rs

Lines changed: 23 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,159 +1,66 @@
11
//! IMAP error types.
22
3-
use std::error::Error as StdError;
4-
use std::fmt;
53
use std::io::Error as IoError;
64
use std::result;
75
use std::str::Utf8Error;
86

97
use base64::DecodeError;
10-
use imap_proto::Response;
118

129
/// A convenience wrapper around `Result` for `imap::Error`.
1310
pub type Result<T> = result::Result<T, Error>;
1411

1512
/// A set of errors that can occur in the IMAP client
16-
#[derive(Debug)]
13+
#[derive(thiserror::Error, Debug)]
1714
pub enum Error {
1815
/// An `io::Error` that occurred while trying to read or write to a network stream.
19-
Io(IoError),
16+
#[error("io: {0}")]
17+
Io(#[from] IoError),
2018
/// A BAD response from the IMAP server.
19+
#[error("bad response: {0}")]
2120
Bad(String),
2221
/// A NO response from the IMAP server.
22+
#[error("no response: {0}")]
2323
No(String),
2424
/// The connection was terminated unexpectedly.
25+
#[error("connection lost")]
2526
ConnectionLost,
2627
/// Error parsing a server response.
27-
Parse(ParseError),
28+
#[error("parse: {0}")]
29+
Parse(#[from] ParseError),
2830
/// Command inputs were not valid [IMAP
2931
/// strings](https://tools.ietf.org/html/rfc3501#section-4.3).
30-
Validate(ValidateError),
31-
/// `native_tls` error
32-
NativeTlsError(async_native_tls::Error),
32+
#[error("validate: {0}")]
33+
Validate(#[from] ValidateError),
34+
/// `async_native_tls` error
35+
#[error("async_native_tls: {0}")]
36+
NativeTlsError(#[from] async_native_tls::Error),
3337
/// Error appending an e-mail.
38+
#[error("could not append mail to mailbox")]
3439
Append,
3540
#[doc(hidden)]
41+
#[error("unknown")]
3642
__Nonexhaustive,
3743
}
3844

39-
impl From<IoError> for Error {
40-
fn from(err: IoError) -> Error {
41-
Error::Io(err)
42-
}
43-
}
44-
45-
impl From<ParseError> for Error {
46-
fn from(err: ParseError) -> Error {
47-
Error::Parse(err)
48-
}
49-
}
50-
51-
impl<'a> From<&'a Response<'a>> for Error {
52-
fn from(err: &'a Response<'a>) -> Error {
53-
Error::Parse(ParseError::Unexpected(format!("{:?}", err)))
54-
}
55-
}
56-
57-
impl From<async_native_tls::Error> for Error {
58-
fn from(err: async_native_tls::Error) -> Error {
59-
Error::NativeTlsError(err)
60-
}
61-
}
62-
63-
impl fmt::Display for Error {
64-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65-
match *self {
66-
Error::Io(ref e) => fmt::Display::fmt(e, f),
67-
Error::Validate(ref e) => fmt::Display::fmt(e, f),
68-
Error::No(ref data) | Error::Bad(ref data) => {
69-
write!(f, "{}: {}", &String::from(self.description()), data)
70-
}
71-
ref e => f.write_str(e.description()),
72-
}
73-
}
74-
}
75-
76-
impl StdError for Error {
77-
fn description(&self) -> &str {
78-
match *self {
79-
Error::Io(ref e) => e.description(),
80-
Error::Parse(ref e) => e.description(),
81-
Error::Validate(ref e) => e.description(),
82-
Error::NativeTlsError(ref e) => e.description(),
83-
Error::Bad(_) => "Bad Response",
84-
Error::No(_) => "No Response",
85-
Error::ConnectionLost => "Connection lost",
86-
Error::Append => "Could not append mail to mailbox",
87-
Error::__Nonexhaustive => "Unknown",
88-
}
89-
}
90-
91-
fn cause(&self) -> Option<&dyn StdError> {
92-
match *self {
93-
Error::Io(ref e) => Some(e),
94-
Error::Parse(ParseError::DataNotUtf8(_, ref e)) => Some(e),
95-
_ => None,
96-
}
97-
}
98-
}
99-
10045
/// An error occured while trying to parse a server response.
101-
#[derive(Debug)]
46+
#[derive(thiserror::Error, Debug)]
10247
pub enum ParseError {
10348
/// Indicates an error parsing the status response. Such as OK, NO, and BAD.
49+
#[error("unable to parse status response")]
10450
Invalid(Vec<u8>),
10551
/// An unexpected response was encountered.
52+
#[error("encountered unexpected parsed response: {0}")]
10653
Unexpected(String),
10754
/// The client could not find or decode the server's authentication challenge.
55+
#[error("unable to parse authentication response: {0} - {1:?}")]
10856
Authentication(String, Option<DecodeError>),
10957
/// The client received data that was not UTF-8 encoded.
110-
DataNotUtf8(Vec<u8>, Utf8Error),
111-
}
112-
113-
impl fmt::Display for ParseError {
114-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115-
match *self {
116-
ref e => f.write_str(e.description()),
117-
}
118-
}
119-
}
120-
121-
impl StdError for ParseError {
122-
fn description(&self) -> &str {
123-
match *self {
124-
ParseError::Invalid(_) => "Unable to parse status response",
125-
ParseError::Unexpected(_) => "Encountered unexpected parsed response",
126-
ParseError::Authentication(_, _) => "Unable to parse authentication response",
127-
ParseError::DataNotUtf8(_, _) => "Unable to parse data as UTF-8 text",
128-
}
129-
}
130-
131-
fn cause(&self) -> Option<&dyn StdError> {
132-
match *self {
133-
ParseError::Authentication(_, Some(ref e)) => Some(e),
134-
_ => None,
135-
}
136-
}
58+
#[error("unable to parse data ({0:?}) as UTF-8 text: {1:?}")]
59+
DataNotUtf8(Vec<u8>, #[source] Utf8Error),
13760
}
13861

13962
/// An [invalid character](https://tools.ietf.org/html/rfc3501#section-4.3) was found in an input
14063
/// string.
141-
#[derive(Debug)]
64+
#[derive(thiserror::Error, Debug)]
65+
#[error("invalid character in input: '{0}'")]
14266
pub struct ValidateError(pub char);
143-
144-
impl fmt::Display for ValidateError {
145-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146-
// print character in debug form because invalid ones are often whitespaces
147-
write!(f, "{}: {:?}", self.description(), self.0)
148-
}
149-
}
150-
151-
impl StdError for ValidateError {
152-
fn description(&self) -> &str {
153-
"Invalid character in input"
154-
}
155-
156-
fn cause(&self) -> Option<&dyn StdError> {
157-
None
158-
}
159-
}

0 commit comments

Comments
 (0)