stacked_errors/
stackable_err.rs

1use core::{fmt::Display, mem};
2
3use crate::{Error, StackableErrorTrait};
4
5/// Conversion to and addition to the stack of a
6/// [stackable_error::Error](crate::Error).
7///
8/// See the main crate documentation and implementation for examples.
9pub trait StackableErr {
10    type Output;
11
12    /// Pushes just location information to the error stack
13    fn stack(self) -> Self::Output;
14
15    /// Only converts to `Self::Output` and pushes it on the error stack
16    fn stack_locationless(self) -> Self::Output;
17
18    /// Pushes the result of `f` and location information to the error stack
19    fn stack_err<E: Display + Send + Sync + 'static>(self, e: E) -> Self::Output;
20
21    /// Pushes `e` and location information to the error stack
22    fn stack_err_with<E: Display + Send + Sync + 'static, F: FnOnce() -> E>(
23        self,
24        f: F,
25    ) -> Self::Output;
26
27    /// Pushes `e` without location information to the error stack
28    fn stack_err_locationless<E: Display + Send + Sync + 'static>(self, e: E) -> Self::Output;
29
30    /// Pushes the result of `f` without location information to the error stack
31    fn stack_err_with_locationless<E: Display + Send + Sync + 'static, F: FnOnce() -> E>(
32        self,
33        f: F,
34    ) -> Self::Output;
35
36    /// Alternate for [StackableErr::stack_err] which can be used for easier
37    /// translation to and from the `eyre` crate
38    fn wrap_err<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output;
39
40    /// Alternate for [StackableErr::stack_err_with] which can be used for
41    /// easier translation to and from the `eyre` crate
42    fn wrap_err_with<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
43        self,
44        msg: F,
45    ) -> Self::Output;
46
47    /// Alternate for [StackableErr::stack_err] which can be used for easier
48    /// translation to and from the `anyhow` crate
49    fn context<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output;
50
51    /// Alternate for [StackableErr::stack_err_with] which can be used for
52    /// easier translation to and from the `anyhow` crate
53    fn with_context<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
54        self,
55        msg: F,
56    ) -> Self::Output;
57}
58
59// TODO when trait aliases are stabilized
60//pub trait WrapErr = StackableErr;
61
62// NOTE: trait conflicts prevent us from implementing some desirable cases.
63// However, if specialization allows us to one day implement more, we have to be
64// careful that internal behavior similar to
65//
66// `Err(Error::from(string)).stack_err(|| "...")`
67//
68// is enforced, i.e. we do not want strings boxed if we were able to write
69//
70// `Err(string).stack()`
71// or `string.stack()`
72//
73// the current state of affairs is cumbersome when starting from a
74// `Into<ErrorKind>` wrapped with nothing, but we do not want to invoke the
75// `impl<T, E: core::error::Error + Send + Sync + 'static> StackableErr for
76// core::result::Result<T, E>` impl on any `Into<ErrorKind>` types
77
78/*impl<T> StackableErr for core::result::Result<T, Error> {
79    type Output = core::result::Result<T, Error>;
80
81    #[track_caller]
82    fn stack(self) -> Self::Output {
83        match self {
84            Ok(o) => Ok(o),
85            Err(e) => Err(e.add_location()),
86        }
87    }
88
89    fn stack_locationless(self) -> Self::Output {
90        self
91    }
92
93    #[track_caller]
94    fn stack_err<E: Display + Send + Sync + 'static>(self, e: E) -> Self::Output {
95        match self {
96            Ok(o) => Ok(o),
97            Err(e) => Err(e.add_kind(f())),
98        }
99    }
100
101    fn stack_err_locationless<E: Display + Send + Sync + 'static>(self, e: E) -> Self::Output {
102        match self {
103            Ok(o) => Ok(o),
104            Err(e) => Err(e.add_kind_locationless(f())),
105        }
106    }
107}*/
108
109#[track_caller]
110fn stack<E: Display + Send + Sync + 'static>(mut err: E) -> Error {
111    let tmp: &mut dyn StackableErrorTrait = &mut err;
112    if let Some(tmp) = tmp._as_any_mut().downcast_mut::<Error>() {
113        tmp.push();
114        // TODO does the allocation here optimize away or can we do something about
115        // this?
116        mem::take(tmp)
117    } else {
118        Error::from_err(err)
119    }
120}
121
122fn stack_locationless<E: Display + Send + Sync + 'static>(mut err: E) -> Error {
123    let tmp: &mut dyn StackableErrorTrait = &mut err;
124    if let Some(tmp) = tmp._as_any_mut().downcast_mut::<Error>() {
125        mem::take(tmp)
126    } else {
127        Error::from_err_locationless(err)
128    }
129}
130
131#[track_caller]
132fn stack_err<E: Display + Send + Sync + 'static, E1: Display + Send + Sync + 'static>(
133    mut err: E,
134    e: E1,
135) -> Error {
136    let tmp: &mut dyn StackableErrorTrait = &mut err;
137    if let Some(tmp) = tmp._as_any_mut().downcast_mut::<Error>() {
138        tmp.push_err(e);
139        mem::take(tmp)
140    } else {
141        // the location should be attached to the later part
142        Error::from_err_locationless(err).add_err(e)
143    }
144}
145
146#[track_caller]
147fn stack_err_locationless<
148    E: Display + Send + Sync + 'static,
149    E1: Display + Send + Sync + 'static,
150>(
151    mut err: E,
152    e: E1,
153) -> Error {
154    let tmp: &mut dyn StackableErrorTrait = &mut err;
155    if let Some(tmp) = tmp._as_any_mut().downcast_mut::<Error>() {
156        tmp.push_err_locationless(e);
157        mem::take(tmp)
158    } else {
159        Error::from_err_locationless(err).add_err_locationless(e)
160    }
161}
162
163impl<T, E: Display + Send + Sync + 'static> StackableErr for core::result::Result<T, E> {
164    type Output = core::result::Result<T, Error>;
165
166    #[track_caller]
167    fn stack(self) -> Self::Output {
168        match self {
169            Ok(o) => Ok(o),
170            Err(err) => Err(stack(err)),
171        }
172    }
173
174    fn stack_locationless(self) -> Self::Output {
175        match self {
176            Ok(o) => Ok(o),
177            Err(err) => Err(stack_locationless(err)),
178        }
179    }
180
181    #[track_caller]
182    fn stack_err<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
183        match self {
184            Ok(o) => Ok(o),
185            Err(err) => Err(stack_err(err, e)),
186        }
187    }
188
189    #[track_caller]
190    fn stack_err_with<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
191        self,
192        f: F,
193    ) -> Self::Output {
194        match self {
195            Ok(o) => Ok(o),
196            Err(err) => Err(stack_err(err, f())),
197        }
198    }
199
200    fn stack_err_locationless<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
201        match self {
202            Ok(o) => Ok(o),
203            Err(err) => Err(stack_err_locationless(err, e)),
204        }
205    }
206
207    fn stack_err_with_locationless<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
208        self,
209        f: F,
210    ) -> Self::Output {
211        match self {
212            Ok(o) => Ok(o),
213            Err(err) => Err(stack_err_locationless(err, f())),
214        }
215    }
216
217    #[track_caller]
218    fn wrap_err<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
219        self.stack_err(msg)
220    }
221
222    #[track_caller]
223    fn wrap_err_with<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
224        self,
225        msg: F,
226    ) -> Self::Output {
227        self.stack_err_with(msg)
228    }
229
230    #[track_caller]
231    fn context<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
232        self.stack_err(msg)
233    }
234
235    #[track_caller]
236    fn with_context<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
237        self,
238        msg: F,
239    ) -> Self::Output {
240        self.stack_err_with(msg)
241    }
242}
243
244impl<T> StackableErr for Option<T> {
245    type Output = core::result::Result<T, Error>;
246
247    #[track_caller]
248    fn stack(self) -> Self::Output {
249        match self {
250            Some(o) => Ok(o),
251            None => Err(Error::new()),
252        }
253    }
254
255    fn stack_locationless(self) -> Self::Output {
256        match self {
257            Some(o) => Ok(o),
258            None => Err(Error::empty()),
259        }
260    }
261
262    #[track_caller]
263    fn stack_err<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
264        match self {
265            Some(o) => Ok(o),
266            None => Err(Error::from_err(e)),
267        }
268    }
269
270    #[track_caller]
271    fn stack_err_with<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
272        self,
273        f: F,
274    ) -> Self::Output {
275        match self {
276            Some(o) => Ok(o),
277            None => Err(Error::from_err(f())),
278        }
279    }
280
281    fn stack_err_locationless<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
282        match self {
283            Some(o) => Ok(o),
284            None => Err(Error::from_err_locationless(e)),
285        }
286    }
287
288    fn stack_err_with_locationless<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
289        self,
290        f: F,
291    ) -> Self::Output {
292        match self {
293            Some(o) => Ok(o),
294            None => Err(Error::from_err_locationless(f())),
295        }
296    }
297
298    #[track_caller]
299    fn wrap_err<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
300        self.stack_err(msg)
301    }
302
303    #[track_caller]
304    fn wrap_err_with<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
305        self,
306        msg: F,
307    ) -> Self::Output {
308        self.stack_err_with(msg)
309    }
310
311    #[track_caller]
312    fn context<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
313        self.stack_err(msg)
314    }
315
316    #[track_caller]
317    fn with_context<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
318        self,
319        msg: F,
320    ) -> Self::Output {
321        self.stack_err_with(msg)
322    }
323}
324
325impl StackableErr for Error {
326    type Output = core::result::Result<(), Error>;
327
328    #[track_caller]
329    fn stack(self) -> Self::Output {
330        Err(self.add())
331    }
332
333    fn stack_locationless(self) -> Self::Output {
334        Err(self)
335    }
336
337    #[track_caller]
338    fn stack_err<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
339        Err(self.add_err(e))
340    }
341
342    #[track_caller]
343    fn stack_err_with<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
344        self,
345        f: F,
346    ) -> Self::Output {
347        Err(self.add_err(f()))
348    }
349
350    fn stack_err_locationless<E1: Display + Send + Sync + 'static>(self, e: E1) -> Self::Output {
351        Err(self.add_err_locationless(e))
352    }
353
354    fn stack_err_with_locationless<E1: Display + Send + Sync + 'static, F: FnOnce() -> E1>(
355        self,
356        f: F,
357    ) -> Self::Output {
358        Err(self.add_err_locationless(f()))
359    }
360
361    #[track_caller]
362    fn wrap_err<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
363        self.stack_err(msg)
364    }
365
366    #[track_caller]
367    fn wrap_err_with<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
368        self,
369        msg: F,
370    ) -> Self::Output {
371        self.stack_err_with(msg)
372    }
373
374    #[track_caller]
375    fn context<D: Display + Send + Sync + 'static>(self, msg: D) -> Self::Output {
376        self.stack_err(msg)
377    }
378
379    #[track_caller]
380    fn with_context<D: Display + Send + Sync + 'static, F: FnOnce() -> D>(
381        self,
382        msg: F,
383    ) -> Self::Output {
384        self.stack_err_with(msg)
385    }
386}