Skip to content

Commit

Permalink
Automatically convert to external errors w/ ensure! and bail! (#95)
Browse files Browse the repository at this point in the history
* Automatically convert to external errors

A pattern documented by thiserror is

```
pub enum MyError {
  ...

  #[error(transparent)]
  Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
}
```

It'd be nice for this to work with ensure! but right now, that macro returns
an eyre error.

With this PR, the macro additionally runs an .into(). In the case that
the return type is an eyre error, obviously .into() will do nothing and
be compiled away. In the case that there is a from method, the wrapping
will occur. This enables eyre to be used for ergonomic 'implementation
detail error' in a thiserror using system which has contractual errors.

Since this conversion adds more flexibility to the result of these
macros, this could break code which relies on the narrowness to inform
type inference. If this is the case, update your code to specify the
result type you would like to use.

* Fix single-argument ensure test and allow dead code.

By adding the possibility for polymorphism from an eyre error, the
previous commit breaks a previous eyre test for single-argument
ensure!().

This change fixes that test and adds `allow(dead_code)` to the struct
used for the test for automatically converting to external errors.

---------

Co-authored-by: nori li <[email protected]>
  • Loading branch information
j-baker and thenorili committed Nov 25, 2023
1 parent 0979ad7 commit a795c97
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
12 changes: 6 additions & 6 deletions eyre/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@
#[macro_export]
macro_rules! bail {
($msg:literal $(,)?) => {
return $crate::private::Err($crate::eyre!($msg));
return $crate::private::Err($crate::eyre!($msg).into());
};
($err:expr $(,)?) => {
return $crate::private::Err($crate::eyre!($err));
return $crate::private::Err($crate::eyre!($err).into());
};
($fmt:expr, $($arg:tt)*) => {
return $crate::private::Err($crate::eyre!($fmt, $($arg)*));
return $crate::private::Err($crate::eyre!($fmt, $($arg)*).into());
};
}

Expand Down Expand Up @@ -114,17 +114,17 @@ macro_rules! ensure {
};
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
return $crate::private::Err($crate::eyre!($msg));
return $crate::private::Err($crate::eyre!($msg).into());
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return $crate::private::Err($crate::eyre!($err));
return $crate::private::Err($crate::eyre!($err).into());
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
return $crate::private::Err($crate::eyre!($fmt, $($arg)*));
return $crate::private::Err($crate::eyre!($fmt, $($arg)*).into());
}
};
}
Expand Down
21 changes: 20 additions & 1 deletion eyre/tests/test_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,33 @@ fn test_ensure() {
};
assert!(f().is_err());

let f = || {
// Tests single-argument `ensure!`
let f = || -> Result<()> {
ensure!(v + v == 1);
Ok(())
};
assert_eq!(
f().unwrap_err().to_string(),
"Condition failed: `v + v == 1`",
);

// Tests automatically converting to external errors with ensure!()
let f = || -> Result<(), SomeWrappingErr> {
ensure!(false, "this will fail");
Ok(())
};
assert!(f().is_err());
}

#[allow(dead_code)]
struct SomeWrappingErr {
err: eyre::Error,
}

impl From<eyre::Error> for SomeWrappingErr {
fn from(err: eyre::Error) -> Self {
SomeWrappingErr { err }
}
}

#[test]
Expand Down

0 comments on commit a795c97

Please sign in to comment.