use alloc::boxed::Box;
use alloc::sync::Arc;
use crate::{Backtrace, ErrorCode, HelpText, SpanTrace};
pub trait Diagnostic: core::error::Error {
#[inline]
fn oopsie_backtrace(&self) -> Option<&Backtrace> {
None
}
#[inline]
fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
None
}
#[inline]
fn oopsie_location(&self) -> Option<&'static core::panic::Location<'static>> {
None
}
#[inline]
fn oopsie_error_code(&self) -> Option<ErrorCode> {
None
}
#[inline]
fn oopsie_help_text(&self) -> Option<HelpText> {
None
}
#[inline]
fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
None
}
}
impl<T: Diagnostic> Diagnostic for Box<T> {
#[inline]
fn oopsie_backtrace(&self) -> Option<&Backtrace> {
(**self).oopsie_backtrace()
}
#[inline]
fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
(**self).oopsie_spantrace()
}
#[inline]
fn oopsie_location(&self) -> Option<&'static core::panic::Location<'static>> {
(**self).oopsie_location()
}
#[inline]
fn oopsie_error_code(&self) -> Option<ErrorCode> {
(**self).oopsie_error_code()
}
#[inline]
fn oopsie_help_text(&self) -> Option<HelpText> {
(**self).oopsie_help_text()
}
#[inline]
fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
(**self).oopsie_exit_code()
}
}
impl<T: Diagnostic> Diagnostic for Arc<T> {
#[inline]
fn oopsie_backtrace(&self) -> Option<&Backtrace> {
(**self).oopsie_backtrace()
}
#[inline]
fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
(**self).oopsie_spantrace()
}
#[inline]
fn oopsie_location(&self) -> Option<&'static core::panic::Location<'static>> {
(**self).oopsie_location()
}
#[inline]
fn oopsie_error_code(&self) -> Option<ErrorCode> {
(**self).oopsie_error_code()
}
#[inline]
fn oopsie_help_text(&self) -> Option<HelpText> {
(**self).oopsie_help_text()
}
#[inline]
fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
(**self).oopsie_exit_code()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Capturable;
use std::fmt;
#[derive(Debug)]
struct Src {
backtrace: Backtrace,
spantrace: SpanTrace,
}
impl fmt::Display for Src {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("src")
}
}
impl std::error::Error for Src {}
impl Diagnostic for Src {
fn oopsie_backtrace(&self) -> Option<&Backtrace> {
Some(&self.backtrace)
}
fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
Some(&self.spantrace)
}
}
#[test]
fn box_delegates_diagnostic_accessors() {
let src = Src {
backtrace: Backtrace::capture(),
spantrace: SpanTrace::capture(),
};
let boxed = Box::new(src);
assert!(boxed.oopsie_backtrace().is_some());
assert!(boxed.oopsie_spantrace().is_some());
}
#[test]
fn box_diagnostic_extraction_reuses_source_frames() {
use crate::{RustBacktrace, with_rust_backtrace_override};
with_rust_backtrace_override(RustBacktrace::Enabled, || {
let src = Src {
backtrace: Backtrace::capture(),
spantrace: SpanTrace::capture(),
};
let expected_frames = src.backtrace.frames().len();
assert!(
expected_frames > 0,
"backtrace must be enabled for this test to be probative"
);
let boxed = Box::new(src);
let extracted = <(Backtrace, SpanTrace) as Capturable>::capture_or_extract(&boxed);
assert_eq!(extracted.0.frames().len(), expected_frames);
});
}
#[test]
fn arc_delegates_diagnostic_accessors() {
let src = Src {
backtrace: Backtrace::capture(),
spantrace: SpanTrace::capture(),
};
let arced = Arc::new(src);
assert!(arced.oopsie_backtrace().is_some());
assert!(arced.oopsie_spantrace().is_some());
}
#[test]
fn arc_diagnostic_extraction_reuses_source_frames() {
use crate::{RustBacktrace, with_rust_backtrace_override};
with_rust_backtrace_override(RustBacktrace::Enabled, || {
let src = Src {
backtrace: Backtrace::capture(),
spantrace: SpanTrace::capture(),
};
let expected_frames = src.backtrace.frames().len();
assert!(
expected_frames > 0,
"backtrace must be enabled for this test to be probative"
);
let arced = Arc::new(src);
let extracted = <(Backtrace, SpanTrace) as Capturable>::capture_or_extract(&arced);
assert_eq!(extracted.0.frames().len(), expected_frames);
});
}
}