1use std::any::Any;
16use std::fmt::{Debug, Formatter};
17use std::io::ErrorKind;
18use std::str::FromStr;
19use std::sync::Arc;
20
21use serde::{Deserialize, Deserializer, Serializer};
22use snafu::{FromString, Snafu};
23
24fn error_chain_root(err: &dyn std::error::Error) -> &dyn std::error::Error {
31 let mut root = err;
32 while let Some(source) = root.source() {
33 root = source;
34 }
35 root
36}
37
38use crate::status_code::StatusCode;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum RetryHint {
47 Retryable,
49 RetryAfterRouteRefresh,
53 NonRetryable,
57}
58
59const RETRY_HINT_RETRYABLE: &str = "retryable";
60const RETRY_HINT_AFTER_ROUTE_REFRESH: &str = "retry_after_route_refresh";
61const RETRY_HINT_NON_RETRYABLE: &str = "non_retryable";
62
63impl RetryHint {
64 pub fn is_retryable(self) -> bool {
66 matches!(
67 self,
68 RetryHint::Retryable | RetryHint::RetryAfterRouteRefresh
69 )
70 }
71
72 pub fn as_str(self) -> &'static str {
74 match self {
75 RetryHint::Retryable => RETRY_HINT_RETRYABLE,
76 RetryHint::RetryAfterRouteRefresh => RETRY_HINT_AFTER_ROUTE_REFRESH,
77 RetryHint::NonRetryable => RETRY_HINT_NON_RETRYABLE,
78 }
79 }
80
81 pub fn serialize_as_str<S>(hint: &Self, serializer: S) -> Result<S::Ok, S::Error>
82 where
83 S: Serializer,
84 {
85 serializer.serialize_str(hint.as_str())
86 }
87
88 pub fn deserialize_from_str<'de, D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: Deserializer<'de>,
91 {
92 let hint = String::deserialize(deserializer)?;
93 hint.parse::<RetryHint>()
94 .map_err(|_| serde::de::Error::custom(format!("unknown retry hint: {hint}")))
95 }
96}
97
98impl FromStr for RetryHint {
99 type Err = ();
100
101 fn from_str(s: &str) -> Result<Self, Self::Err> {
102 match s {
103 RETRY_HINT_RETRYABLE => Ok(RetryHint::Retryable),
104 RETRY_HINT_AFTER_ROUTE_REFRESH => Ok(RetryHint::RetryAfterRouteRefresh),
105 RETRY_HINT_NON_RETRYABLE => Ok(RetryHint::NonRetryable),
106 _ => Err(()),
107 }
108 }
109}
110
111pub fn retry_hint_from_io_error(error: &std::io::Error) -> RetryHint {
118 match error.kind() {
119 ErrorKind::ConnectionRefused
120 | ErrorKind::ConnectionReset
121 | ErrorKind::HostUnreachable
122 | ErrorKind::NetworkUnreachable
123 | ErrorKind::ConnectionAborted
124 | ErrorKind::NotConnected
125 | ErrorKind::NetworkDown
126 | ErrorKind::BrokenPipe
127 | ErrorKind::WouldBlock
128 | ErrorKind::StaleNetworkFileHandle
129 | ErrorKind::TimedOut
130 | ErrorKind::ResourceBusy
131 | ErrorKind::Interrupted => RetryHint::Retryable,
132
133 _ => RetryHint::NonRetryable,
134 }
135}
136
137pub trait ErrorExt: StackError {
139 fn status_code(&self) -> StatusCode {
141 StatusCode::Unknown
142 }
143
144 fn retry_hint(&self) -> RetryHint {
152 RetryHint::NonRetryable
153 }
154
155 fn is_retryable(&self) -> bool {
160 self.retry_hint().is_retryable()
161 }
162
163 fn as_any(&self) -> &dyn Any;
166
167 fn output_msg(&self) -> String
168 where
169 Self: Sized,
170 {
171 match self.status_code() {
172 StatusCode::Unknown | StatusCode::Internal => {
173 format!("Internal error: {}", self.status_code() as u32)
175 }
176 _ => {
177 let error = self.last();
178 if let Some(external_error) = error.source() {
179 let external_root = error_chain_root(external_error);
180
181 if error.transparent() {
182 format!("{external_root}")
183 } else {
184 format!("{error}: {external_root}")
185 }
186 } else {
187 format!("{error}")
188 }
189 }
190 }
191 }
192
193 fn root_cause(&self) -> Option<&dyn std::error::Error>
195 where
196 Self: Sized,
197 {
198 let error = self.last();
199 if let Some(external_error) = error.source() {
200 let external_root = error_chain_root(external_error);
201 Some(external_root)
202 } else {
203 None
204 }
205 }
206}
207
208pub trait StackError: std::error::Error {
209 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>);
210
211 fn next(&self) -> Option<&dyn StackError>;
212
213 fn last(&self) -> &dyn StackError
214 where
215 Self: Sized,
216 {
217 let Some(mut result) = self.next() else {
218 return self;
219 };
220 while let Some(err) = result.next() {
221 result = err;
222 }
223 result
224 }
225
226 fn transparent(&self) -> bool {
231 false
232 }
233}
234
235impl<T: ?Sized + StackError> StackError for Arc<T> {
236 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
237 self.as_ref().debug_fmt(layer, buf)
238 }
239
240 fn next(&self) -> Option<&dyn StackError> {
241 self.as_ref().next()
242 }
243}
244
245impl<T: StackError> StackError for Box<T> {
246 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
247 self.as_ref().debug_fmt(layer, buf)
248 }
249
250 fn next(&self) -> Option<&dyn StackError> {
251 self.as_ref().next()
252 }
253}
254
255pub type WhateverResult<T> = Result<T, Whatever>;
259
260#[derive(Snafu)]
261#[snafu(display("{inner}"))]
262pub struct Whatever {
263 inner: snafu::Whatever,
264}
265
266impl Debug for Whatever {
267 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
268 write!(f, "{}", self.inner)
269 }
270}
271
272impl<E: ErrorExt> From<E> for Whatever {
273 fn from(e: E) -> Self {
274 Self {
275 inner: FromString::without_source(format!("{e:?}")),
276 }
277 }
278}
279
280impl From<String> for Whatever {
281 fn from(s: String) -> Self {
282 Self {
283 inner: FromString::without_source(s),
284 }
285 }
286}
287
288pub struct BoxedError {
290 inner: Box<dyn crate::ext::ErrorExt + Send + Sync>,
291}
292
293impl BoxedError {
294 pub fn new<E: crate::ext::ErrorExt + Send + Sync + 'static>(err: E) -> Self {
295 Self {
296 inner: Box::new(err),
297 }
298 }
299
300 pub fn into_inner(self) -> Box<dyn crate::ext::ErrorExt + Send + Sync> {
301 self.inner
302 }
303}
304
305impl std::fmt::Debug for BoxedError {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 let mut buf = vec![];
308 self.debug_fmt(0, &mut buf);
309 write!(f, "{}", buf.join("\n"))
310 }
311}
312
313impl std::fmt::Display for BoxedError {
314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 write!(f, "{}", self.inner)
316 }
317}
318
319impl std::error::Error for BoxedError {
320 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
321 self.inner.source()
322 }
323}
324
325impl crate::ext::ErrorExt for BoxedError {
326 fn status_code(&self) -> crate::status_code::StatusCode {
327 self.inner.status_code()
328 }
329
330 fn retry_hint(&self) -> RetryHint {
331 self.inner.retry_hint()
332 }
333
334 fn as_any(&self) -> &dyn std::any::Any {
335 self.inner.as_any()
336 }
337}
338
339impl crate::snafu::ErrorCompat for BoxedError {
342 fn backtrace(&self) -> Option<&crate::snafu::Backtrace> {
343 None
344 }
345}
346
347impl StackError for BoxedError {
348 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
349 self.inner.debug_fmt(layer, buf)
350 }
351
352 fn next(&self) -> Option<&dyn StackError> {
353 self.inner.next()
354 }
355}
356
357#[derive(Debug)]
359pub struct PlainError {
360 msg: String,
361 status_code: StatusCode,
362}
363
364impl PlainError {
365 pub fn new(msg: String, status_code: StatusCode) -> Self {
366 Self { msg, status_code }
367 }
368}
369
370impl std::fmt::Display for PlainError {
371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372 write!(f, "{}", self.msg)
373 }
374}
375
376impl std::error::Error for PlainError {
377 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
378 None
379 }
380}
381
382impl crate::ext::ErrorExt for PlainError {
383 fn status_code(&self) -> crate::status_code::StatusCode {
384 self.status_code
385 }
386
387 fn as_any(&self) -> &dyn std::any::Any {
388 self as _
389 }
390}
391
392impl StackError for PlainError {
393 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
394 buf.push(format!("{}: {}", layer, self.msg))
395 }
396
397 fn next(&self) -> Option<&dyn StackError> {
398 None
399 }
400}