use std::backtrace::{Backtrace, BacktraceStatus};
use error_stack::{AttachmentKind, Context, Frame, FrameKind, Report};
use smallvec::SmallVec;
#[cfg(feature = "tracing")]
use tracing_error::SpanTraceStatus;
pub struct ContextWithAttachments<'a> {
pub context: &'a dyn Context,
pub attachments: SmallVec<[AttachmentKind<'a>; 1]>,
}
pub trait ContextWithAttachmentsExt<'a, I: Iterator<Item = &'a Frame>> {
fn by_error(self) -> ContextWithAttachmentsIterator<'a, I>;
}
impl<'a, I> ContextWithAttachmentsExt<'a, I> for I
where
I: Iterator<Item = &'a Frame>,
{
fn by_error(self) -> ContextWithAttachmentsIterator<'a, I> {
ContextWithAttachmentsIterator { parent: self }
}
}
pub struct ContextWithAttachmentsIterator<'a, I: Iterator<Item = &'a Frame>> {
parent: I,
}
impl<'a, I> Iterator for ContextWithAttachmentsIterator<'a, I>
where
I: Iterator<Item = &'a Frame>,
{
type Item = ContextWithAttachments<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut attachments: SmallVec<[AttachmentKind<'a>; 1]> = SmallVec::new();
while let Some(frame) = self.parent.next() {
match frame.kind() {
FrameKind::Context(c) => {
attachments.reverse();
return Some(ContextWithAttachments {
context: c,
attachments,
});
}
FrameKind::Attachment(a) => {
attachments.push(a);
}
}
}
None
}
}
pub struct ErrorStackInformation<'a> {
pub backtrace: Option<&'a Backtrace>,
#[cfg(feature = "tracing")]
pub spantrace: Option<&'a tracing_error::SpanTrace>,
}
impl<'a> ErrorStackInformation<'a> {
pub fn new(err: &'a Report<impl Context>) -> Self {
let backtrace = err
.downcast_ref::<Backtrace>()
.filter(|b| b.status() == BacktraceStatus::Captured);
#[cfg(feature = "tracing")]
let spantrace = err
.downcast_ref::<tracing_error::SpanTrace>()
.filter(|s| s.status() == SpanTraceStatus::CAPTURED);
Self {
backtrace,
#[cfg(feature = "tracing")]
spantrace,
}
}
}