#![allow(dead_code)]
pub fn create_report() -> Report<RootError> {
Report::new(RootError)
}
extern crate alloc;
pub use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{any::TypeId, panic::Location};
#[allow(unused_imports)]
use core::{
fmt,
future::Future,
iter,
sync::atomic::{AtomicI8, Ordering},
};
#[cfg(all(rust_1_65, feature = "std"))]
use std::backtrace::Backtrace;
use error_stack::{AttachmentKind, Context, Frame, FrameKind, Report, Result};
#[allow(unused_imports)]
use once_cell::sync::Lazy;
#[cfg(feature = "spantrace")]
use tracing_error::SpanTrace;
#[derive(Debug, PartialEq, Eq)]
pub struct RootError;
impl fmt::Display for RootError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("root error")
}
}
impl Context for RootError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContextA(pub u32);
impl fmt::Display for ContextA {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("context A")
}
}
impl Context for ContextA {
#[cfg(nightly)]
fn provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) {
demand.provide_ref(&self.0);
demand.provide_value(self.0 as u64);
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ContextB(pub i32);
impl fmt::Display for ContextB {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("context B")
}
}
impl Context for ContextB {
#[cfg(nightly)]
fn provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) {
demand.provide_ref(&self.0);
demand.provide_value(self.0 as i64);
}
}
#[derive(Debug)]
#[cfg(feature = "spantrace")]
pub struct ErrorA(pub u32, SpanTrace);
#[cfg(feature = "spantrace")]
impl ErrorA {
pub fn new(value: u32) -> Self {
Self(value, SpanTrace::capture())
}
}
#[cfg(feature = "spantrace")]
impl fmt::Display for ErrorA {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("error A")
}
}
#[cfg(feature = "spantrace")]
impl Context for ErrorA {
#[cfg(nightly)]
fn provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) {
demand.provide_ref(&self.1);
}
}
#[derive(Debug)]
#[cfg(all(rust_1_65, feature = "std"))]
pub struct ErrorB(pub u32, std::backtrace::Backtrace);
#[cfg(all(rust_1_65, feature = "std"))]
impl ErrorB {
pub fn new(value: u32) -> Self {
Self(value, Backtrace::force_capture())
}
}
#[cfg(all(rust_1_65, feature = "std"))]
impl fmt::Display for ErrorB {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("error B")
}
}
#[cfg(all(nightly, feature = "std"))]
impl std::error::Error for ErrorB {
fn provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) {
demand.provide_ref(&self.1);
}
}
#[cfg(all(rust_1_65, feature = "std"))]
impl ErrorB {
pub fn backtrace(&self) -> Option<&Backtrace> {
Some(&self.1)
}
}
#[derive(Clone)]
pub struct AttachmentA(pub u32);
pub struct AttachmentB(pub i32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PrintableA(pub u32);
impl fmt::Display for PrintableA {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("printable A")
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct PrintableB(pub u32);
impl fmt::Display for PrintableB {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("printable B")
}
}
pub fn create_error() -> Result<(), RootError> {
Err(create_report())
}
pub fn create_future() -> impl Future<Output = Result<(), RootError>> {
futures::future::err(create_report())
}
pub fn capture_ok<E>(closure: impl FnOnce() -> Result<(), E>) {
closure().expect("expected an OK value, found an error")
}
pub fn capture_error<E>(closure: impl FnOnce() -> Result<(), E>) -> Report<E> {
closure().expect_err("expected an error")
}
pub fn messages<E>(report: &Report<E>) -> Vec<String> {
report
.frames()
.map(|frame| match frame.kind() {
FrameKind::Context(context) => context.to_string(),
FrameKind::Attachment(AttachmentKind::Printable(attachment)) => attachment.to_string(),
FrameKind::Attachment(AttachmentKind::Opaque(_)) => {
#[cfg(all(rust_1_65, feature = "std"))]
if frame.type_id() == TypeId::of::<Backtrace>() {
return String::from("Backtrace");
}
#[cfg(feature = "spantrace")]
if frame.type_id() == TypeId::of::<SpanTrace>() {
return String::from("SpanTrace");
}
if frame.type_id() == TypeId::of::<Location>() {
String::from("Location")
} else {
String::from("opaque")
}
}
FrameKind::Attachment(_) => panic!("attachment was not covered"),
})
.collect()
}
pub fn frame_kinds<E>(report: &Report<E>) -> Vec<FrameKind> {
remove_builtin_frames(report).map(Frame::kind).collect()
}
#[cfg(all(rust_1_65, feature = "std"))]
pub fn supports_backtrace() -> bool {
static STATE: Lazy<bool> = Lazy::new(|| {
let bt = std::backtrace::Backtrace::capture();
bt.status() == std::backtrace::BacktraceStatus::Captured
});
*STATE
}
#[cfg(feature = "spantrace")]
pub fn supports_spantrace() -> bool {
static STATE: Lazy<bool> = Lazy::new(|| {
let st = tracing_error::SpanTrace::capture();
st.status() == tracing_error::SpanTraceStatus::CAPTURED
});
*STATE
}
pub fn remove_builtin_messages<S: AsRef<str>>(
messages: impl IntoIterator<Item = S>,
) -> Vec<String> {
messages
.into_iter()
.filter_map(|message| {
let message = message.as_ref();
if message != "Location" && message != "Backtrace" && message != "SpanTrace" {
Some(message.to_string())
} else {
None
}
})
.collect()
}
pub fn remove_builtin_frames<E>(report: &Report<E>) -> impl Iterator<Item = &Frame> {
report.frames().filter(|frame| {
#[cfg(all(rust_1_65, feature = "std"))]
if frame.type_id() == TypeId::of::<Backtrace>() {
return false;
}
#[cfg(feature = "spantrace")]
if frame.type_id() == TypeId::of::<SpanTrace>() {
return false;
}
frame.type_id() != TypeId::of::<Location>()
})
}
#[allow(unused_mut)]
#[allow(clippy::missing_const_for_fn)]
pub fn expect_count(mut count: usize) -> usize {
#[cfg(all(rust_1_65, feature = "std"))]
if supports_backtrace() {
count += 1;
}
#[cfg(feature = "spantrace")]
if supports_spantrace() {
count += 1;
}
count + 1
}
#[allow(unused_macros)]
macro_rules! assert_kinds {
($report:ident, [
$($pattern:pat_param),*
]) => {
let kinds = remove_builtin_frames($report).map(|frame| frame.kind()).collect::<Vec<_>>();
assert!(matches!(kinds.as_slice(), [$($pattern),*]));
};
}