1use crate::{
2 ChannelState, ConnectionState, notifier::Notifier, protocol::AMQPError, types::ChannelId,
3};
4use amq_protocol::{
5 frame::{GenError, ParserError, ProtocolVersion},
6 protocol::AMQPErrorKind,
7};
8use async_rs::{Runtime, traits::*};
9use std::{
10 error, fmt, io,
11 panic::{RefUnwindSafe, UnwindSafe},
12 sync::Arc,
13};
14
15pub type Result<T> = std::result::Result<T, Error>;
17
18#[derive(Clone, Debug)]
20pub struct Error {
21 kind: ErrorKind,
22 notifier: Option<Notifier>,
23}
24
25#[derive(Clone, Debug)]
30#[non_exhaustive]
31pub enum ErrorKind {
32 ChannelsLimitReached,
34 InvalidProtocolVersion(ProtocolVersion),
36
37 InvalidChannel(ChannelId),
39 InvalidChannelState(ChannelState, &'static str),
41 InvalidConnectionState(ConnectionState),
43
44 IOError(Arc<io::Error>),
46 RuntimeShutdownError(Arc<io::Error>),
48 ParsingError(ParserError),
50 ProtocolError(AMQPError),
52 SerialisationError(Arc<GenError>),
54 AuthProviderError(String),
56 FutureCompleted,
58 NoDefaultRuntime,
60
61 MissingHeartbeatError,
63}
64
65impl Error {
66 pub(crate) fn other<E: Into<Box<dyn error::Error + Send + Sync>>>(error: E) -> Self {
67 io::Error::other(error).into()
68 }
69
70 pub(crate) fn io<RK: RuntimeKit>(error: io::Error, rt: &Runtime<RK>) -> Self {
71 if rt.is_runtime_shutdown_error(&error) {
72 ErrorKind::RuntimeShutdownError(Arc::new(error)).into()
73 } else {
74 error.into()
75 }
76 }
77
78 #[must_use]
80 pub fn kind(&self) -> &ErrorKind {
81 &self.kind
82 }
83
84 pub(crate) fn notifier(&self) -> Option<Notifier> {
85 self.notifier.clone()
86 }
87
88 pub(crate) fn with_notifier(mut self, notifier: Option<Notifier>) -> Self {
89 self.notifier = notifier;
90 self
91 }
92
93 #[must_use]
95 pub fn wouldblock(&self) -> bool {
96 matches!(self.kind(), ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock)
97 }
98
99 #[must_use]
101 pub fn interrupted(&self) -> bool {
102 matches!(self.kind(), ErrorKind::IOError(e) if e.kind() == io::ErrorKind::Interrupted)
103 }
104
105 #[must_use]
108 pub fn is_io_error(&self) -> bool {
109 matches!(self.kind(), ErrorKind::IOError(_)) || self.is_runtime_shutdown_error()
110 }
111
112 #[must_use]
114 pub fn is_runtime_shutdown_error(&self) -> bool {
115 matches!(self.kind(), ErrorKind::RuntimeShutdownError(_))
116 }
117
118 #[must_use]
120 pub fn is_amqp_error(&self) -> bool {
121 matches!(self.kind(), ErrorKind::ProtocolError(_))
122 }
123
124 #[must_use]
126 pub fn is_amqp_soft_error(&self) -> bool {
127 matches!(self.kind(), ErrorKind::ProtocolError(e) if matches!(e.kind(), AMQPErrorKind::Soft(_)))
128 }
129
130 #[must_use]
132 pub fn is_amqp_hard_error(&self) -> bool {
133 matches!(self.kind(), ErrorKind::ProtocolError(e) if matches!(e.kind(), AMQPErrorKind::Hard(_)))
134 }
135
136 #[must_use]
143 pub fn can_be_recovered(&self) -> bool {
144 match self.kind() {
145 ErrorKind::ChannelsLimitReached => false,
146 ErrorKind::InvalidProtocolVersion(_) => false,
147
148 ErrorKind::InvalidChannel(_) => true,
149 ErrorKind::InvalidChannelState(..) => true,
150 ErrorKind::InvalidConnectionState(_) => true,
151
152 ErrorKind::IOError(_) => true,
153 ErrorKind::RuntimeShutdownError(_) => false,
154 ErrorKind::ParsingError(_) => false,
155 ErrorKind::ProtocolError(_) => true,
156 ErrorKind::SerialisationError(_) => false,
157 ErrorKind::AuthProviderError(_) => false,
158 ErrorKind::FutureCompleted => false,
159 ErrorKind::NoDefaultRuntime => false,
160
161 ErrorKind::MissingHeartbeatError => true,
162 }
163 }
164}
165
166impl UnwindSafe for Error {}
171impl RefUnwindSafe for Error {}
172
173impl fmt::Display for Error {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 match self.kind() {
176 ErrorKind::ChannelsLimitReached => write!(
177 f,
178 "the maximum number of channels for this connection has been reached"
179 ),
180 ErrorKind::InvalidProtocolVersion(version) => {
181 write!(f, "the server only supports AMQP {version}")
182 }
183
184 ErrorKind::InvalidChannel(channel) => write!(f, "invalid channel: {channel}"),
185 ErrorKind::InvalidChannelState(state, context) => {
186 write!(f, "invalid channel state: {state:?} ({context})")
187 }
188 ErrorKind::InvalidConnectionState(state) => {
189 write!(f, "invalid connection state: {state:?}")
190 }
191
192 ErrorKind::IOError(e) => write!(f, "IO error: {e}"),
193 ErrorKind::RuntimeShutdownError(e) => write!(f, "runtime shutdown error: {e}"),
194 ErrorKind::ParsingError(e) => write!(f, "failed to parse: {e}"),
195 ErrorKind::ProtocolError(e) => write!(f, "protocol error: {e}"),
196 ErrorKind::SerialisationError(e) => write!(f, "failed to serialise: {e}"),
197 ErrorKind::AuthProviderError(e) => write!(f, "failure during authentication: {e}"),
198 ErrorKind::FutureCompleted => write!(f, "future polled after completion"),
199 ErrorKind::NoDefaultRuntime => write!(f, "no default configured runtime"),
200
201 ErrorKind::MissingHeartbeatError => {
202 write!(f, "no heartbeat received from server for too long")
203 }
204 }
205 }
206}
207
208impl error::Error for Error {
209 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
210 match self.kind() {
211 ErrorKind::IOError(e) => Some(&**e),
212 ErrorKind::RuntimeShutdownError(e) => Some(&**e),
213 ErrorKind::ParsingError(e) => Some(e),
214 ErrorKind::ProtocolError(e) => Some(e),
215 ErrorKind::SerialisationError(e) => Some(&**e),
216 _ => None,
217 }
218 }
219}
220
221impl From<ErrorKind> for Error {
222 fn from(kind: ErrorKind) -> Self {
223 Self {
224 kind,
225 notifier: None,
226 }
227 }
228}
229
230impl From<io::Error> for Error {
231 fn from(other: io::Error) -> Self {
232 ErrorKind::IOError(Arc::new(other)).into()
233 }
234}
235
236impl PartialEq for Error {
237 fn eq(&self, other: &Self) -> bool {
238 use ErrorKind::*;
239
240 match (self.kind(), other.kind()) {
241 (ChannelsLimitReached, ChannelsLimitReached) => true,
242 (InvalidProtocolVersion(left_inner), InvalidProtocolVersion(right_version)) => {
243 left_inner == right_version
244 }
245
246 (InvalidChannel(left_inner), InvalidChannel(right_inner)) => left_inner == right_inner,
247 (
248 InvalidChannelState(left_inner, left_context),
249 InvalidChannelState(right_inner, right_context),
250 ) => left_inner == right_inner && left_context == right_context,
251 (InvalidConnectionState(left_inner), InvalidConnectionState(right_inner)) => {
252 left_inner == right_inner
253 }
254
255 (IOError(_), IOError(_)) => false,
256 (RuntimeShutdownError(_), RuntimeShutdownError(_)) => false,
257 (ParsingError(left_inner), ParsingError(right_inner)) => left_inner == right_inner,
258 (ProtocolError(left_inner), ProtocolError(right_inner)) => left_inner == right_inner,
259 (SerialisationError(_), SerialisationError(_)) => false,
260 (FutureCompleted, FutureCompleted) => true,
261 (NoDefaultRuntime, NoDefaultRuntime) => true,
262
263 _ => false,
264 }
265 }
266}