Skip to main content

headless_lms_base/error/
backend_error.rs

1/*!
2Contains a common trait for all the error types for this application.
3*/
4
5use std::panic::Location;
6
7use backtrace::Backtrace;
8use tracing_error::SpanTrace;
9
10/// The error types of this program all implement this trait for interoperability.
11pub trait BackendError: std::error::Error + std::marker::Sync {
12    type ErrorType: std::fmt::Debug;
13
14    /// Create an error, capturing the caller's location, a backtrace and the span trace.
15    ///
16    /// `#[track_caller]` makes [`Location::caller`] resolve to the real call site, even
17    /// through the `*_err!` macros, rather than to this method.
18    #[track_caller]
19    fn new<M: Into<String>, S: Into<Option<anyhow::Error>>>(
20        error_type: Self::ErrorType,
21        message: M,
22        source_error: S,
23    ) -> Self
24    where
25        Self: Sized,
26    {
27        Self::new_with_traces_and_location(
28            error_type,
29            message,
30            source_error,
31            Backtrace::new_unresolved(),
32            SpanTrace::capture(),
33            Some(Location::caller()),
34        )
35    }
36
37    /// Like [`new`](Self::new) but with an explicit backtrace and span trace, e.g. to
38    /// preserve a source error's traces.
39    #[track_caller]
40    fn new_with_traces<M: Into<String>, S: Into<Option<anyhow::Error>>>(
41        error_type: Self::ErrorType,
42        message: M,
43        source_error: S,
44        backtrace: Backtrace,
45        span_trace: SpanTrace,
46    ) -> Self
47    where
48        Self: Sized,
49    {
50        Self::new_with_traces_and_location(
51            error_type,
52            message,
53            source_error,
54            backtrace,
55            span_trace,
56            Some(Location::caller()),
57        )
58    }
59
60    /// The one required constructor; the others delegate to it.
61    fn new_with_traces_and_location<M: Into<String>, S: Into<Option<anyhow::Error>>>(
62        error_type: Self::ErrorType,
63        message: M,
64        source_error: S,
65        backtrace: Backtrace,
66        span_trace: SpanTrace,
67        location: Option<&'static Location<'static>>,
68    ) -> Self;
69
70    fn backtrace(&self) -> Option<&Backtrace>;
71
72    fn error_type(&self) -> &Self::ErrorType;
73
74    fn message(&self) -> &str;
75
76    fn span_trace(&self) -> &SpanTrace;
77
78    /// Source location where the error was raised, if captured.
79    fn location(&self) -> Option<&'static Location<'static>>;
80
81    #[track_caller]
82    fn to_different_error<T>(self, new_error_type: T::ErrorType, new_message: String) -> T
83    where
84        T: BackendError,
85        Self: Sized + 'static + std::marker::Send,
86    {
87        T::new(new_error_type, new_message, Some(self.into()))
88    }
89}