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        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/// An error type that preserves all detailed error messages. It is optimized
37/// to fit in a single pointer.
38#[derive(Debug)]
39pub struct BoxedError {
40    inner: ThinBox<dyn error::Error + Send + Sync + 'static>,
41}
42
43impl BoxedError {
44    /// Returns the inner error as a `dyn Error`.
45    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            // SAFETY: The provided closure returns the same pointer unsized to
70            // a `dyn ErrorTrace`.
71            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            // SAFETY: The provided closure returns the same pointer unsized to
82            // a `dyn Error`.
83            inner: unsafe {
84                ThinBox::new_unchecked(source, |ptr| ptr as *mut _)
85            },
86        }
87    }
88}