1use std::fmt::{Debug, Display, Formatter};
17use std::rc::Rc;
18
19use backtrace::Backtrace;
20
21#[derive(Clone)]
23pub struct BacktraceError<E>
24where
25 E: Debug + Display + 'static
26{
27 value: Rc<BacktraceErrorImpl<E>>
28}
29
30struct BacktraceErrorImpl<E>
31where
32 E: Debug + Display
33{
34 error: E,
35 backtrace: Backtrace,
36 cause: Option<Box<dyn std::error::Error>>
37}
38
39impl<E: Debug + Display> std::error::Error for BacktraceError<E> {}
40
41impl<E: Debug + Display> Display for BacktraceError<E>
42{
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
44 {
45 Display::fmt(self.error(), f)
46 }
47}
48
49impl<E: Debug + Display> Debug for BacktraceError<E>
50{
51 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
52 {
53 f.debug_struct("BacktraceError")
54 .field("error", self.error())
55 .field("backtrace", self.get_backtrace())
56 .field("cause", self.cause())
57 .finish()
58 }
59}
60
61impl<E: Debug + Display> BacktraceError<E>
62{
63 #[must_use]
64 pub(crate) fn new_with_cause<Cause: std::error::Error + 'static>(
65 error: E,
66 cause: Cause
67 ) -> Self
68 {
69 BacktraceError {
70 value: Rc::new(BacktraceErrorImpl {
71 backtrace: Backtrace::new(),
72 error,
73 cause: Some(Box::new(cause))
74 })
75 }
76 }
77
78 #[must_use]
79 pub(crate) fn new(error: E) -> Self
80 {
81 BacktraceError {
82 value: Rc::new(BacktraceErrorImpl {
83 backtrace: Backtrace::new(),
84 error,
85 cause: None
86 })
87 }
88 }
89
90 #[must_use]
92 pub fn get_backtrace(&self) -> &Backtrace
93 {
94 &self.value.backtrace
95 }
96
97 #[must_use]
99 pub fn error(&self) -> &E
100 {
101 &self.value.error
102 }
103
104 #[must_use]
106 pub fn cause(&self) -> &Option<Box<dyn std::error::Error>>
107 {
108 &self.value.cause
109 }
110
111 #[must_use]
112 pub(crate) fn context<S: AsRef<str>>(
113 self,
114 description: S
115 ) -> BacktraceError<ErrorMessage>
116 {
117 BacktraceError::new_with_cause(
118 ErrorMessage {
119 description: description.as_ref().to_string()
120 },
121 self
122 )
123 }
124}
125
126#[derive(Clone, Debug)]
128pub struct ErrorMessage
129{
130 description: String
131}
132
133impl ErrorMessage
134{
135 pub(crate) fn msg<S: AsRef<str>>(description: S) -> BacktraceError<Self>
136 {
137 BacktraceError::new(Self {
138 description: description.as_ref().to_string()
139 })
140 }
141
142 pub(crate) fn msg_with_cause<S, Cause>(
143 description: S,
144 cause: Cause
145 ) -> BacktraceError<Self>
146 where
147 S: AsRef<str>,
148 Cause: std::error::Error + 'static
149 {
150 BacktraceError::new_with_cause(
151 Self {
152 description: description.as_ref().to_string()
153 },
154 cause
155 )
156 }
157}
158
159impl Display for ErrorMessage
160{
161 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
162 {
163 Display::fmt(&self.description, f)
164 }
165}
166
167pub(crate) trait Context<R>
168{
169 fn context<S: AsRef<str>>(
170 self,
171 description: S
172 ) -> Result<R, BacktraceError<ErrorMessage>>;
173}
174
175impl<R, E: std::error::Error + 'static> Context<R> for Result<R, E>
176{
177 fn context<S: AsRef<str>>(
178 self,
179 description: S
180 ) -> Result<R, BacktraceError<ErrorMessage>>
181 {
182 match self {
183 Ok(result) => Ok(result),
184 Err(err) => Err(BacktraceError::new_with_cause(
185 ErrorMessage {
186 description: description.as_ref().to_string()
187 },
188 err
189 ))
190 }
191 }
192}