From a795c97a2b26e4dbeb42992e1301862a2266fdf1 Mon Sep 17 00:00:00 2001 From: James Baker Date: Sat, 25 Nov 2023 06:04:47 +0000 Subject: [PATCH] Automatically convert to external errors w/ ensure! and bail! (#95) * 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 <50680474+thenorili@users.noreply.github.com> --- eyre/src/macros.rs | 12 ++++++------ eyre/tests/test_macros.rs | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/eyre/src/macros.rs b/eyre/src/macros.rs index 032f82a..4820b28 100644 --- a/eyre/src/macros.rs +++ b/eyre/src/macros.rs @@ -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()); }; } @@ -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()); } }; } diff --git a/eyre/tests/test_macros.rs b/eyre/tests/test_macros.rs index 41d3ddb..9fddd8a 100644 --- a/eyre/tests/test_macros.rs +++ b/eyre/tests/test_macros.rs @@ -40,7 +40,8 @@ fn test_ensure() { }; assert!(f().is_err()); - let f = || { + // Tests single-argument `ensure!` + let f = || -> Result<()> { ensure!(v + v == 1); Ok(()) }; @@ -48,6 +49,24 @@ fn test_ensure() { 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 for SomeWrappingErr { + fn from(err: eyre::Error) -> Self { + SomeWrappingErr { err } + } } #[test]