Skip to content

Commit

Permalink
feat: explicit backtraces
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Dec 5, 2023
1 parent b52dba1 commit 1f860f7
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 138 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ rust-version = "1.65.0"
indenter = "0.3.0"
once_cell = "1.18.0"
# For use with anyhow-compat
anyhow = "1.0"
anyhow = { version = "1.0", features = ["backtrace"] }
4 changes: 3 additions & 1 deletion eyre/examples/custom_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ fn install() -> Result<(), impl Error> {

let hook = Hook { capture_backtrace };

eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e))))
eyre::set_hook(Box::new(move |e: &(dyn Error + 'static)| {
Box::new(hook.make_handler(e)) as Box<dyn EyreHandler>
}))
}

struct Hook {
Expand Down
2 changes: 1 addition & 1 deletion eyre/src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ macro_rules! backtrace_if_absent {
($err:expr) => {
match $err.backtrace() {
Some(_) => None,
None => Some(Backtrace::capture()),
None => Some(Backtrace::capture().into()),
}
};
}
Expand Down
99 changes: 83 additions & 16 deletions eyre/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
use crate::{
backtrace::Backtrace,
error::{context_downcast, context_downcast_mut, context_drop_rest, ContextError},
vtable::{
object_boxed, object_downcast, object_downcast_mut, object_drop, object_drop_front,
object_mut, object_ref, ErrorVTable,
},
Report, StdError,
HandlerBacktraceCompat, HookParams, Report, StdError,
};
use std::fmt::Display;

#[derive(Default)]
#[derive(Debug, Default)]
/// Used for incrementally constructing reports
pub struct ReportBuilder {
backtrace: Option<Backtrace>,
}

impl std::fmt::Debug for ReportBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
params: HookParams,
}

impl ReportBuilder {
/// Creates a new report builder with default parameters
pub fn new() -> Self {
Self::default()
}

/// Use the given backtrace for the error
pub fn with_backtrace(mut self, backtrace: Option<Backtrace>) -> Self {
self.backtrace = backtrace;
pub fn with_backtrace(mut self, backtrace: impl Into<HandlerBacktraceCompat>) -> Self {
self.params.backtrace = Some(backtrace.into());
self
}

#[cfg_attr(track_caller, track_caller)]
/// Creates a report from the given error message
pub fn msg<M>(self, message: M) -> Report
pub fn from_msg<M>(self, message: M) -> Report
where
M: Display + std::fmt::Debug + Send + Sync + 'static,
{
Expand All @@ -50,14 +46,14 @@ impl ReportBuilder {

// Safety: MessageError is repr(transparent) so it is okay for the
// vtable to allow casting the MessageError<M> to M.
let handler = Some(crate::capture_handler(&error));
let handler = Some(crate::capture_handler(&error, self.params));

unsafe { Report::construct(error, vtable, handler) }
}

#[cfg_attr(track_caller, track_caller)]
/// Creates a report from the following error
pub fn report<E>(self, error: E) -> Report
pub fn from_stderr<E>(self, error: E) -> Report
where
E: StdError + Send + Sync + 'static,
{
Expand All @@ -72,7 +68,78 @@ impl ReportBuilder {
};

// Safety: passing vtable that operates on the right type E.
let handler = Some(crate::capture_handler(&error));
let handler = Some(crate::capture_handler(&error, self.params));

unsafe { Report::construct(error, vtable, handler) }
}

#[cfg_attr(track_caller, track_caller)]
/// Creates a report from the following boxed error
pub fn from_boxed(self, error: Box<dyn StdError + Send + Sync>) -> Report {
use crate::wrapper::BoxedError;
let error = BoxedError(error);
let handler = Some(crate::capture_handler(&error, self.params));

let vtable = &ErrorVTable {
object_drop: object_drop::<BoxedError>,
object_ref: object_ref::<BoxedError>,
object_mut: object_mut::<BoxedError>,
object_boxed: object_boxed::<BoxedError>,
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
};

// Safety: BoxedError is repr(transparent) so it is okay for the vtable
// to allow casting to Box<dyn StdError + Send + Sync>.
unsafe { Report::construct(error, vtable, handler) }
}

#[cfg_attr(track_caller, track_caller)]
/// Wraps a source error with a message
pub fn wrap_with_msg<D, E>(self, msg: D, error: E) -> Report
where
D: Display + Send + Sync + 'static,
E: StdError + Send + Sync + 'static,
{
let error: ContextError<D, E> = ContextError { msg, error };

let vtable = &ErrorVTable {
object_drop: object_drop::<ContextError<D, E>>,
object_ref: object_ref::<ContextError<D, E>>,
object_mut: object_mut::<ContextError<D, E>>,
object_boxed: object_boxed::<ContextError<D, E>>,
object_downcast: context_downcast::<D, E>,
object_downcast_mut: context_downcast_mut::<D, E>,
object_drop_rest: context_drop_rest::<D, E>,
};

// Safety: passing vtable that operates on the right type.
let handler = Some(crate::capture_handler(&error, self.params));

unsafe { Report::construct(error, vtable, handler) }
}

#[cfg_attr(track_caller, track_caller)]
pub(crate) fn from_display<M>(self, message: M) -> Report
where
M: Display + Send + Sync + 'static,
{
use crate::wrapper::{DisplayError, NoneError};
let error: DisplayError<M> = DisplayError(message);
let vtable = &ErrorVTable {
object_drop: object_drop::<DisplayError<M>>,
object_ref: object_ref::<DisplayError<M>>,
object_mut: object_mut::<DisplayError<M>>,
object_boxed: object_boxed::<DisplayError<M>>,
object_downcast: object_downcast::<M>,
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
};

// Safety: DisplayError is repr(transparent) so it is okay for the
// vtable to allow casting the DisplayError<M> to M.
let handler = Some(crate::capture_handler(&NoneError, Default::default()));

unsafe { Report::construct(error, vtable, handler) }
}
Expand Down
34 changes: 2 additions & 32 deletions eyre/src/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,40 +39,10 @@ impl IntoEyreReport for anyhow::Error {
where
Self: Sized,
{
// dbg!(
// self.root_cause(),
// self.source(),
// self.chain().rev().collect::<Vec<_>>(),
// self.chain()
// .rev()
// .map(|v| v.to_string())
// .collect::<Vec<_>>()
// );

let mut chain = self.chain().rev();

// We can't store the actual error
// PENDING: https://github.com/dtolnay/anyhow/issues/327
let head = chain
.next()
.expect("Error chain contains at least one error");

#[cfg(backtrace)]
let report = ReportBuilder::default()
.with_backtrace(self.backtrace())
.msg(head.to_string());

#[cfg(not(backtrace))]
let report = ReportBuilder::default().msg(head.to_string());
// chai
// eprintln!("{:?}", chain.map(|v| v.to_string()).collect::<Vec<_>>());

// report
.from_boxed(self.into());

chain.fold(report, |report, err| {
// We can't write the actual error
// PENDING: https://github.com/dtolnay/anyhow/issues/327
report.wrap_err(err.to_string())
})
report
}
}
78 changes: 13 additions & 65 deletions eyre/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::builder::ReportBuilder;
use crate::chain::Chain;
use crate::ptr::{MutPtr, OwnedPtr, RefPtr};
use crate::vtable::{
header, header_mut, object_boxed, object_downcast, object_downcast_mut, object_drop,
object_drop_front, object_mut, object_ref, ErrorHeader, ErrorImpl, ErrorVTable,
header, header_mut, object_boxed, object_drop, object_mut, object_ref, ErrorHeader, ErrorImpl,
ErrorVTable,
};
use crate::EyreHandler;
use crate::{Report, StdError};
Expand All @@ -27,7 +27,7 @@ impl Report {
where
E: StdError + Send + Sync + 'static,
{
ReportBuilder::default().report(error)
ReportBuilder::default().from_stderr(error)
}

/// Create a new error object from a printable error message.
Expand Down Expand Up @@ -72,39 +72,23 @@ impl Report {
where
M: Display + Debug + Send + Sync + 'static,
{
ReportBuilder::default().msg(message)
ReportBuilder::default().from_msg(message)
}

#[cfg_attr(track_caller, track_caller)]
pub(crate) fn from_adhoc<M>(message: M) -> Self
where
M: Display + Debug + Send + Sync + 'static,
{
ReportBuilder::default().msg(message)
ReportBuilder::default().from_msg(message)
}

#[cfg_attr(track_caller, track_caller)]
pub(crate) fn from_display<M>(message: M) -> Self
where
M: Display + Send + Sync + 'static,
{
use crate::wrapper::{DisplayError, NoneError};
let error: DisplayError<M> = DisplayError(message);
let vtable = &ErrorVTable {
object_drop: object_drop::<DisplayError<M>>,
object_ref: object_ref::<DisplayError<M>>,
object_mut: object_mut::<DisplayError<M>>,
object_boxed: object_boxed::<DisplayError<M>>,
object_downcast: object_downcast::<M>,
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
};

// Safety: DisplayError is repr(transparent) so it is okay for the
// vtable to allow casting the DisplayError<M> to M.
let handler = Some(crate::capture_handler(&NoneError));

unsafe { Report::construct(error, vtable, handler) }
ReportBuilder::default().from_display(message)
}

#[cfg_attr(track_caller, track_caller)]
Expand All @@ -114,43 +98,7 @@ impl Report {
D: Display + Send + Sync + 'static,
E: StdError + Send + Sync + 'static,
{
let error: ContextError<D, E> = ContextError { msg, error };

let vtable = &ErrorVTable {
object_drop: object_drop::<ContextError<D, E>>,
object_ref: object_ref::<ContextError<D, E>>,
object_mut: object_mut::<ContextError<D, E>>,
object_boxed: object_boxed::<ContextError<D, E>>,
object_downcast: context_downcast::<D, E>,
object_downcast_mut: context_downcast_mut::<D, E>,
object_drop_rest: context_drop_rest::<D, E>,
};

// Safety: passing vtable that operates on the right type.
let handler = Some(crate::capture_handler(&error));

unsafe { Report::construct(error, vtable, handler) }
}

#[cfg_attr(track_caller, track_caller)]
pub(crate) fn from_boxed(error: Box<dyn StdError + Send + Sync>) -> Self {
use crate::wrapper::BoxedError;
let error = BoxedError(error);
let handler = Some(crate::capture_handler(&error));

let vtable = &ErrorVTable {
object_drop: object_drop::<BoxedError>,
object_ref: object_ref::<BoxedError>,
object_mut: object_mut::<BoxedError>,
object_boxed: object_boxed::<BoxedError>,
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
};

// Safety: BoxedError is repr(transparent) so it is okay for the vtable
// to allow casting to Box<dyn StdError + Send + Sync>.
unsafe { Report::construct(error, vtable, handler) }
ReportBuilder::default().wrap_with_msg(msg, error)
}

// Takes backtrace as argument rather than capturing it here so that the
Expand Down Expand Up @@ -461,7 +409,7 @@ where
{
#[cfg_attr(track_caller, track_caller)]
fn from(error: E) -> Self {
ReportBuilder::default().report(error)
ReportBuilder::default().from_stderr(error)
}
}

Expand Down Expand Up @@ -503,7 +451,7 @@ impl Drop for Report {
/// # Safety
///
/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
unsafe fn context_downcast<D, E>(
pub(crate) unsafe fn context_downcast<D, E>(
e: RefPtr<'_, ErrorImpl<()>>,
target: TypeId,
) -> Option<NonNull<()>>
Expand All @@ -527,7 +475,7 @@ where
/// # Safety
///
/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
unsafe fn context_downcast_mut<D, E>(
pub(crate) unsafe fn context_downcast_mut<D, E>(
e: MutPtr<'_, ErrorImpl<()>>,
target: TypeId,
) -> Option<NonNull<()>>
Expand All @@ -550,7 +498,7 @@ where
/// # Safety
///
/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
unsafe fn context_drop_rest<D, E>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
pub(crate) unsafe fn context_drop_rest<D, E>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
where
D: 'static,
E: 'static,
Expand Down Expand Up @@ -595,7 +543,7 @@ where
/// # Safety
///
/// Requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
unsafe fn context_chain_downcast_mut<D>(
pub(crate) unsafe fn context_chain_downcast_mut<D>(
e: MutPtr<'_, ErrorImpl<()>>,
target: TypeId,
) -> Option<NonNull<()>>
Expand All @@ -616,7 +564,7 @@ where
/// # Safety
///
/// Requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
unsafe fn context_chain_drop_rest<D>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
pub(crate) unsafe fn context_chain_drop_rest<D>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
where
D: 'static,
{
Expand Down
4 changes: 2 additions & 2 deletions eyre/src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
// let error = $msg;
// (&error).eyre_kind().new(error)

use crate::Report;
use crate::{builder::ReportBuilder, Report};
use core::fmt::{Debug, Display};

use crate::StdError;
Expand Down Expand Up @@ -106,6 +106,6 @@ impl BoxedKind for Box<dyn StdError + Send + Sync> {}
impl Boxed {
#[cfg_attr(track_caller, track_caller)]
pub fn new(self, error: Box<dyn StdError + Send + Sync>) -> Report {
Report::from_boxed(error)
ReportBuilder::default().from_boxed(error)
}
}
Loading

0 comments on commit 1f860f7

Please sign in to comment.