Skip to content

Commit

Permalink
feat: convert between anyhow::Error and eyre::Result
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Aug 29, 2024
1 parent df42dc4 commit 5d5e18c
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ indenter = "0.3.0"
once_cell = "1.18.0"
owo-colors = "4.0"
autocfg = "1.0"
anyhow = "1.0"

[profile.dev.package.backtrace]
opt-level = 3
Expand Down
6 changes: 3 additions & 3 deletions eyre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,26 @@ readme = { workspace = true }
rust-version = { workspace = true }

[features]
default = ["anyhow", "auto-install", "track-caller"]
anyhow = []
default = [ "auto-install", "track-caller"]
auto-install = []
track-caller = []

[dependencies]
indenter = { workspace = true }
once_cell = { workspace = true }
pyo3 = { version = "0.20", optional = true, default-features = false }
anyhow = { workspace = true, optional = true, default-features = false }

[build-dependencies]
autocfg = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true, default-features = true }
futures = { version = "0.3", default-features = false }
rustversion = "1.0"
thiserror = "1.0"
trybuild = { version = "=1.0.89", features = ["diff"] } # pinned due to MSRV
backtrace = "0.3.46"
anyhow = "1.0.28"
syn = { version = "2.0", features = ["full"] }
pyo3 = { version = "0.20", default-features = false, features = ["auto-initialize"] }

Expand Down
15 changes: 13 additions & 2 deletions eyre/src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,31 @@ macro_rules! capture_backtrace {
None
};
}

/// Capture a backtrace iff there is not already a backtrace in the error chain
#[cfg(generic_member_access)]
macro_rules! backtrace_if_absent {
($err:expr) => {
match std::error::request_ref::<std::backtrace::Backtrace>($err as &dyn std::error::Error) {
Some(_) => None,
None => capture_backtrace!(),
Some(v) => {
eprintln!(
"BAcktrace present: {v:?} {:?}",
($err as &dyn std::error::Error).type_id()
);
None
}
None => {
eprintln!("No backtrace");
capture_backtrace!()
}
}
};
}

#[cfg(not(generic_member_access))]
macro_rules! backtrace_if_absent {
($err:expr) => {
eprintln!("capturing stable backtrace");

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable, --no-default-features --features track-caller)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (beta)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Clippy (stable)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (macOS-latest)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (ubuntu-latest)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features --features track-caller)

trailing semicolon in macro used in expression position

Check warning on line 44 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite

trailing semicolon in macro used in expression position
capture_backtrace!()

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable, --no-default-features --features track-caller)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (beta)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Clippy (stable)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (macOS-latest)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (ubuntu-latest)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features --features track-caller)

macro expansion ignores token `capture_backtrace` and any following

Check failure on line 45 in eyre/src/backtrace.rs

View workflow job for this annotation

GitHub Actions / Test Suite

macro expansion ignores token `capture_backtrace` and any following
};
}
5 changes: 5 additions & 0 deletions eyre/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ impl<D> StdError for ContextError<D, Report>
where
D: Display,
{
#[cfg(generic_member_access)]
fn provide<'a>(&'a self, request: &mut std::error::Request<'a>) {
self.error.provide(request)
}

fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(ErrorImpl::error(self.error.inner.as_ref()))
}
Expand Down
18 changes: 14 additions & 4 deletions eyre/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use core::mem::{self, ManuallyDrop};
use core::ptr::{self, NonNull};

use core::ops::{Deref, DerefMut};
use std::any::Any;

impl Report {
/// Create a new error object from any error type.
Expand Down Expand Up @@ -490,11 +491,20 @@ impl Report {

impl<E> From<E> for Report
where
E: StdError + Send + Sync + 'static,
E: 'static + Into<anyhow::Error>,

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable, --no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (beta)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Miri

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (macOS-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (ubuntu-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 494 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite

failed to resolve: use of undeclared crate or module `anyhow`
Result<(), E>: anyhow::Context<(), E>,

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable, --no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (beta)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Miri

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (macOS-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (ubuntu-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 495 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite

failed to resolve: use of undeclared crate or module `anyhow`
{
#[cfg_attr(track_caller, track_caller)]
fn from(error: E) -> Self {
Report::from_std(error)
fn from(value: E) -> Self {
let mut value = Some(value);
let e = &mut value as &mut dyn Any;

if let Some(e) = e.downcast_mut::<Option<anyhow::Error>>() {

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable, --no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (beta)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Miri

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (macOS-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (ubuntu-latest)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite (--no-default-features --features track-caller)

failed to resolve: use of undeclared crate or module `anyhow`

Check failure on line 501 in eyre/src/error.rs

View workflow job for this annotation

GitHub Actions / Test Suite

failed to resolve: use of undeclared crate or module `anyhow`
let e: Box<dyn StdError + Send + Sync> = e.take().unwrap().into();
Report::from_boxed(e)
} else {
let e: Box<dyn StdError + Send + Sync> = value.take().unwrap().into().into();
Report::from_boxed(e)
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions eyre/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ use crate::backtrace::Backtrace;
use crate::error::ErrorImpl;
use core::fmt::{Debug, Display};

use std::error::Error as StdError;
use std::{any::Any, error::Error as StdError};

Check warning on line 384 in eyre/src/lib.rs

View workflow job for this annotation

GitHub Actions / Clippy (stable)

unused import: `any::Any`

pub use eyre as format_err;
/// Compatibility re-export of `eyre` for interop with `anyhow`
Expand Down Expand Up @@ -779,6 +779,7 @@ impl DefaultHandler {
#[cfg_attr(not(feature = "auto-install"), allow(dead_code))]
pub fn default_with(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
// Capture the backtrace if the source error did not already capture one
eprintln!("checking backtrace");
let backtrace = backtrace_if_absent!(error);

Box::new(Self {
Expand Down Expand Up @@ -848,7 +849,10 @@ impl EyreHandler for DefaultHandler {
let backtrace = self
.backtrace
.as_ref()
.or_else(|| std::error::request_ref::<Backtrace>(error))
.or_else(|| {
eprintln!("Requesting backtrace from underlying type");
std::error::request_ref::<std::backtrace::Backtrace>(error)
})
.expect("backtrace capture failed");

if let BacktraceStatus::Captured = backtrace.status() {
Expand Down
58 changes: 58 additions & 0 deletions eyre/tests/test_anyhow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#![feature(error_generic_member_access)]

use eyre::Report;
use std::fmt::Display;

#[derive(Debug)]
struct RootError;

impl Display for RootError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RootError")
}
}

impl std::error::Error for RootError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}

fn this_function_fails() -> anyhow::Result<()> {
use anyhow::Context;

Err(RootError).context("Ouch!").context("Anyhow context A")
}

fn test_failure() -> eyre::Result<()> {
use anyhow::Context;
this_function_fails().context("Anyhow context B")?;

Ok(())
}

#[test]
fn anyhow_conversion() {
use eyre::WrapErr;
let error: Report = test_failure().wrap_err("Eyre context").unwrap_err();

eprintln!("Error: {:?}", error);

let chain = error.chain().map(ToString::to_string).collect::<Vec<_>>();
assert_eq!(
chain,
[
"Eyre context",
// Anyhow context
"Anyhow context B",
"Anyhow context A",
// Anyhow error
"Ouch!",
// Original concrete error, shows up in chain too
"RootError"
]
);

let backtrace = std::error::request_ref::<std::backtrace::Backtrace>(&*error).unwrap();
dbg!(backtrace);
}

0 comments on commit 5d5e18c

Please sign in to comment.