1use std::{
2 error,
3 fmt::{self},
4 num::ParseIntError,
5 result,
6 str::Utf8Error,
7};
8
9use crate::runtime::io::Error as IoError;
10
11macro_rules! err {
12 ($kind:expr, $($arg:tt)*) => {{
13 use crate::error::Error;
14
15 let kind = $kind;
16 let message = format!($($arg)*);
17 return Err(Error::new( kind, message ));
18 }};
19}
20
21#[derive(Debug)]
22pub enum ErrorKind {
23 #[cfg(feature = "async-native-tls")]
24 Tls(async_native_tls::Error),
25 #[cfg(feature = "async-rustls")]
26 InvalidDnsName,
27 Io(IoError),
28 ParseInt(ParseIntError),
29 ParseString(Utf8Error),
30 ServerError(String),
31 #[cfg(feature = "sasl")]
32 DecodeBase64(base64::DecodeError),
33 NotConnected,
34 ShouldNotBeConnected,
35 IncorrectStateForCommand,
36 MessageIsDeleted,
37 FeatureUnsupported,
38 ServerFailedToGreet,
39 InvalidResponse,
40 ResponseTooLarge,
41 MissingRequest,
42 ParseCommand,
43 UnexpectedResponse,
44 ConnectionClosed,
45}
46
47#[derive(Debug)]
48pub struct Error {
49 message: String,
50 kind: ErrorKind,
51}
52
53impl Error {
54 pub fn new<S>(error_kind: ErrorKind, message: S) -> Self
55 where
56 String: From<S>,
57 {
58 Self {
59 message: message.into(),
60 kind: error_kind,
61 }
62 }
63
64 pub fn message(&self) -> &str {
65 &self.message
66 }
67
68 pub fn kind(&self) -> &ErrorKind {
69 &self.kind
70 }
71}
72
73impl error::Error for Error {
74 fn description(&self) -> &str {
75 &self.message
76 }
77
78 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
79 match self.kind() {
80 _ => None,
81 }
82 }
83}
84
85impl Into<String> for Error {
86 fn into(self) -> String {
87 self.message
88 }
89}
90
91impl fmt::Display for Error {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "{}", self.message)
94 }
95}
96
97#[cfg(feature = "async-native-tls")]
98impl From<async_native_tls::Error> for Error {
99 fn from(tls_error: async_native_tls::Error) -> Self {
100 Self::new(
101 ErrorKind::Tls(tls_error),
102 "Error creating secure connection",
103 )
104 }
105}
106
107impl From<IoError> for Error {
108 fn from(io_error: IoError) -> Self {
109 Self::new(ErrorKind::Io(io_error), "Error with connection to server")
110 }
111}
112
113impl From<ParseIntError> for Error {
114 fn from(parse_int_error: ParseIntError) -> Self {
115 Self::new(ErrorKind::ParseInt(parse_int_error), "Failed to parse int")
116 }
117}
118
119impl From<Utf8Error> for Error {
120 fn from(error: Utf8Error) -> Self {
121 Self::new(ErrorKind::ParseString(error), "Failed to parse string")
122 }
123}
124
125#[cfg(feature = "sasl")]
126impl From<base64::DecodeError> for Error {
127 fn from(error: base64::DecodeError) -> Self {
128 Self::new(ErrorKind::DecodeBase64(error), "Failed to decode base64")
129 }
130}
131
132pub(crate) use err;
133
134pub type Result<T> = result::Result<T, Error>;