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