Skip to main content

base_console/
failure.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use std::{
5    backtrace::{Backtrace, BacktraceStatus},
6    error::Error,
7    fmt,
8};
9use tracing_error::{SpanTrace, SpanTraceStatus};
10
11/// An error with diagnostics captured where it is wrapped, which can be retained and reported later.
12///
13/// Capture at the failure boundary to preserve its origin before returning the value across async tasks. [`Backtrace::capture`] honours `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE`; a supplied backtrace may instead be passed to [`Self::with_backtrace`]. Span traces require the error layer included by [`crate::Console::layer`].
14#[derive(Debug)]
15pub struct Failure<E> {
16    error: E,
17    backtrace: Backtrace,
18    span_trace: Option<String>,
19}
20
21impl<E> Failure<E> {
22    /// Capture the current backtrace, when enabled, and logical span context.
23    pub fn capture(error: E) -> Self {
24        Self::with_backtrace(error, Backtrace::capture())
25    }
26
27    /// Retain a previously captured backtrace and capture the current span context.
28    pub fn with_backtrace(error: E, backtrace: Backtrace) -> Self {
29        let trace = SpanTrace::capture();
30        let span_trace = (trace.status() == SpanTraceStatus::CAPTURED).then(|| trace.to_string());
31        Self {
32            error,
33            backtrace,
34            span_trace,
35        }
36    }
37
38    /// The underlying error.
39    pub fn error(&self) -> &E {
40        &self.error
41    }
42
43    /// The captured or supplied OS stack backtrace.
44    pub fn backtrace(&self) -> &Backtrace {
45        &self.backtrace
46    }
47
48    /// A text snapshot of the logical span context at capture time, if available.
49    pub fn span_trace(&self) -> Option<&str> {
50        self.span_trace.as_deref()
51    }
52
53    /// Recover the underlying error, discarding the captured diagnostics.
54    pub fn into_inner(self) -> E {
55        self.error
56    }
57}
58
59impl<E> Failure<E> {
60    /// The backtrace when capture succeeded; disabled or unsupported traces are omitted.
61    pub fn captured_backtrace(&self) -> Option<&Backtrace> {
62        (self.backtrace.status() == BacktraceStatus::Captured).then_some(&self.backtrace)
63    }
64}
65
66impl<E: fmt::Display> fmt::Display for Failure<E> {
67    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
68        self.error.fmt(formatter)
69    }
70}
71
72impl<E: Error + 'static> Error for Failure<E> {
73    fn source(&self) -> Option<&(dyn Error + 'static)> {
74        self.error.source()
75    }
76}