1use alloc::string::{String, ToString};
2use alloc::sync::Arc;
3use core::fmt::{self, Debug, Display, Formatter};
4
5use eyre::{eyre, Report};
6
7pub type HermesError = Error;
8
9#[derive(Clone)]
10pub struct Error {
11 pub is_retryable: bool,
12 pub detail: ErrorDetail,
13}
14
15#[derive(Clone)]
16pub enum ErrorDetail {
17 Report(Arc<Report>),
18 Wrapped(String, Arc<ErrorDetail>),
19}
20
21impl<E> From<E> for Error
22where
23 Report: From<E>,
24{
25 fn from(e: E) -> Self {
26 Self::report(e)
27 }
28}
29
30#[allow(clippy::from_over_into)]
31impl Into<Report> for Error {
32 fn into(self) -> Report {
33 eyre!("{}", self)
34 }
35}
36
37impl Error {
38 pub fn report<E>(e: E) -> Self
39 where
40 Report: From<E>,
41 {
42 Self {
43 is_retryable: false,
44 detail: ErrorDetail::Report(Arc::new(e.into())),
45 }
46 }
47
48 pub fn wrap<M>(self, message: M) -> Self
49 where
50 M: Display,
51 {
52 Self {
53 is_retryable: self.is_retryable,
54 detail: ErrorDetail::Wrapped(message.to_string(), Arc::new(self.detail)),
55 }
56 }
57}
58
59impl Debug for Error {
60 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
61 if self.is_retryable {
62 write!(f, "retryable error: ")?;
63 }
64
65 Debug::fmt(&self.detail, f)
66 }
67}
68
69impl Display for Error {
70 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
71 Debug::fmt(self, f)
72 }
73}
74
75impl Debug for ErrorDetail {
76 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
77 match self {
78 ErrorDetail::Report(report) => Debug::fmt(report, f),
79 ErrorDetail::Wrapped(message, detail) => {
80 write!(f, "{}: {:?}", message, detail)
81 }
82 }
83 }
84}