1use core::{error, fmt};
2
3use crate::{thin_box::ThinBox, Source, Trace};
4
5#[ptr_meta::pointee]
6trait ErrorTrace: fmt::Debug + fmt::Display + Send + Sync + 'static {}
7
8impl<T> ErrorTrace for T where
9 T: fmt::Debug + fmt::Display + Send + Sync + 'static + ?Sized
10{
11}
12
13#[derive(Debug)]
14struct ErrorWithTrace {
15 error: BoxedError,
16 trace: ThinBox<dyn ErrorTrace>,
17}
18
19impl fmt::Display for ErrorWithTrace {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "{}", self.error)?;
22 if f.alternate() {
23 write!(f, "trace: {}", self.trace)?;
24 }
25
26 Ok(())
27 }
28}
29
30impl error::Error for ErrorWithTrace {
31 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
32 Some(&*self.error.inner)
33 }
34}
35
36#[derive(Debug)]
39pub struct BoxedError {
40 inner: ThinBox<dyn error::Error + Send + Sync + 'static>,
41}
42
43impl BoxedError {
44 pub fn inner(this: &Self) -> &(dyn error::Error + 'static) {
46 &*this.inner
47 }
48}
49
50impl fmt::Display for BoxedError {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(f, "{}", self.inner)
53 }
54}
55
56impl error::Error for BoxedError {
57 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
58 self.inner.source()
59 }
60}
61
62impl Trace for BoxedError {
63 fn trace<R>(self, trace: R) -> Self
64 where
65 R: fmt::Debug + fmt::Display + Send + Sync + 'static,
66 {
67 Self::new(ErrorWithTrace {
68 error: self,
69 trace: unsafe {
72 ThinBox::new_unchecked(trace, |ptr| ptr as *mut _)
73 },
74 })
75 }
76}
77
78impl Source for BoxedError {
79 fn new<T: error::Error + Send + Sync + 'static>(source: T) -> Self {
80 Self {
81 inner: unsafe {
84 ThinBox::new_unchecked(source, |ptr| ptr as *mut _)
85 },
86 }
87 }
88}