1
use core::error::Error;
2
use core::fmt::Debug;
3
use core::fmt::Display;
4

            
5
/// The Merc error type. This has a blanket [`From`] impl for any type that implements Rust's [`Error`],
6
/// meaning it can be used as a "catch all" error. Captures a backtrace that can be printed from this object.
7
pub struct MercError {
8
    inner: Box<InnerMercError>,
9
}
10

            
11
impl MercError {
12
    /// Attempts to downcast the internal error to the given type.
13
    ///
14
    /// This is useful when you need to inspect or handle a specific error type
15
    /// that may have been wrapped inside a `MercError`.
16
    ///
17
    /// # Examples
18
    ///
19
    /// ```
20
    /// use merc_utilities::MercError;
21
    /// use std::io;
22
    ///
23
    /// fn handle_error(err: MercError) {
24
    ///     // Check if the underlying error is an IO error
25
    ///     if let Some(io_err) = err.downcast_ref::<io::Error>() {
26
    ///         println!("IO error occurred: {}", io_err.kind());
27
    ///     } else {
28
    ///         println!("Some other error occurred");
29
    ///     }
30
    /// }
31
    /// ```
32
    #[must_use]
33
    pub fn downcast_ref<E: Error + 'static>(&self) -> Option<&E> {
34
        self.inner.error.downcast_ref::<E>()
35
    }
36
}
37

            
38
/// This type exists to make [`MercError`] use a "thin pointer" instead of a
39
/// "fat pointer", which reduces the size of our Result by a usize. This does
40
/// introduce an extra indirection, but error handling is a "cold path". We
41
/// don't need to optimize it to that degree.
42
struct InnerMercError {
43
    /// The underlying error
44
    error: Box<dyn Error + Send + Sync + 'static>,
45
    /// A backtrace captured at creation
46
    backtrace: std::backtrace::Backtrace,
47
}
48

            
49
// NOTE: writing the impl this way gives us From<&str>
50
impl<E> From<E> for MercError
51
where
52
    Box<dyn Error + Send + Sync + 'static>: From<E>,
53
{
54
    #[cold]
55
1094
    fn from(error: E) -> Self {
56
1094
        MercError {
57
1094
            inner: Box::new(InnerMercError {
58
1094
                error: error.into(),
59
1094
                backtrace: std::backtrace::Backtrace::capture(),
60
1094
            }),
61
1094
        }
62
1094
    }
63
}
64

            
65
impl Display for MercError {
66
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67
        writeln!(f, "{}", self.inner.error)?;
68
        {
69
            let backtrace = &self.inner.backtrace;
70
            if let std::backtrace::BacktraceStatus::Captured = backtrace.status() {
71
                writeln!(f, "{backtrace}")?;
72
            }
73
        }
74
        Ok(())
75
    }
76
}
77

            
78
impl Debug for MercError {
79
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80
        writeln!(f, "{:?}", self.inner.error)?;
81
        {
82
            let backtrace = &self.inner.backtrace;
83
            if let std::backtrace::BacktraceStatus::Captured = backtrace.status() {
84
                writeln!(f, "{backtrace}")?;
85
            }
86
        }
87

            
88
        Ok(())
89
    }
90
}