Skip to main content

rancor/
boxed_error.rs

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        write!(f, "trace: {}", self.trace)?;
23
24        Ok(())
25    }
26}
27
28impl error::Error for ErrorWithTrace {
29    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
30        self.error.inner.source()
31    }
32}
33
34/// An error type that preserves all detailed error messages. It is optimized
35/// to fit in a single pointer.
36#[derive(Debug)]
37pub struct BoxedError {
38    inner: ThinBox<dyn error::Error + Send + Sync + 'static>,
39}
40
41impl fmt::Display for BoxedError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "{}", self.inner)
44    }
45}
46
47impl error::Error for BoxedError {
48    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
49        self.inner.source()
50    }
51}
52
53impl Trace for BoxedError {
54    fn trace<R>(self, trace: R) -> Self
55    where
56        R: fmt::Debug + fmt::Display + Send + Sync + 'static,
57    {
58        Self::new(ErrorWithTrace {
59            error: self,
60            // SAFETY: The provided closure returns the same pointer unsized to
61            // a `dyn ErrorTrace`.
62            trace: unsafe {
63                ThinBox::new_unchecked(trace, |ptr| ptr as *mut _)
64            },
65        })
66    }
67}
68
69impl Source for BoxedError {
70    fn new<T: error::Error + Send + Sync + 'static>(source: T) -> Self {
71        Self {
72            // SAFETY: The provided closure returns the same pointer unsized to
73            // a `dyn Error`.
74            inner: unsafe {
75                ThinBox::new_unchecked(source, |ptr| ptr as *mut _)
76            },
77        }
78    }
79}