From 89713d0a58ef27be6276787d8526c0e187b07842 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 28 Jul 2018 16:55:48 +0200 Subject: [PATCH 1/2] Added support for rendering errors with causes --- examples/simple.rs | 4 +--- src/backtrace/mod.rs | 5 +++++ src/display.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/error/mod.rs | 7 +++++++ src/lib.rs | 7 +++++++ 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/display.rs diff --git a/examples/simple.rs b/examples/simple.rs index 35d25e1..e25ba8e 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -16,7 +16,5 @@ fn bad_function() -> Result<(), WrappingError> { } fn main() { - for cause in Fail::iter_causes(&bad_function().unwrap_err()) { - println!("{}", cause); - } + println!("{}", Fail::display(&bad_function().unwrap_err())); } diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 58f0477..17d264f 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -111,6 +111,11 @@ with_backtrace! { Backtrace { internal: InternalBacktrace::new() } } + /// Checks if the backtrace is empty. + pub fn is_empty(&self) -> bool { + self.internal.is_none() + } + pub(crate) fn none() -> Backtrace { Backtrace { internal: InternalBacktrace::none() } } diff --git a/src/display.rs b/src/display.rs new file mode 100644 index 0000000..4e6cb90 --- /dev/null +++ b/src/display.rs @@ -0,0 +1,43 @@ +use std::fmt; + +use Fail; +use backtrace::Backtrace; + + +/// Renders a fail with all causes. +pub struct FailDisplay<'a>(pub(crate) &'a Fail, pub(crate) Option<&'a Backtrace>); + +impl<'a> fmt::Display for FailDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut ptr = Some(self.0); + let mut idx = 0; + let mut was_backtrace = false; + + while let Some(fail) = ptr { + if was_backtrace { + write!(f, "\n")?; + } + was_backtrace = false; + if idx == 0 { + write!(f, "error: {}", fail)?; + } else { + write!(f, "\n caused by: {}", fail)?; + } + if f.alternate() { + let backtrace = if idx == 0 && self.1.is_some() { + Some(self.1.unwrap()) + } else { + fail.backtrace() + }; + if let Some(backtrace) = backtrace { + write!(f, "\nbacktrace:\n{}", backtrace)?; + was_backtrace = true; + } + } + ptr = fail.cause(); + idx += 1; + } + + Ok(()) + } +} diff --git a/src/error/mod.rs b/src/error/mod.rs index 18a103c..1cc53d9 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -15,6 +15,8 @@ use self::error_impl::ErrorImpl; #[cfg(feature = "std")] use std::error::Error as StdError; +use display::FailDisplay; + /// The `Error` type, which can contain any failure. /// @@ -155,6 +157,11 @@ impl Error { self.imp.failure_mut().downcast_mut() } + /// Displays the error. + pub fn display(&self) -> FailDisplay { + FailDisplay(self.as_fail(), Some(self.backtrace())) + } + /// Deprecated alias to `find_root_cause`. #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")] pub fn root_cause(&self) -> &Fail { diff --git a/src/lib.rs b/src/lib.rs index a35fff5..d029c14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ mod box_std; mod compat; mod context; mod result_ext; +mod display; use core::any::TypeId; use core::fmt::{Debug, Display}; @@ -47,6 +48,7 @@ pub use backtrace::Backtrace; pub use compat::Compat; pub use context::Context; pub use result_ext::ResultExt; +pub use display::FailDisplay; #[cfg(feature = "failure_derive")] #[allow(unused_imports)] @@ -230,6 +232,11 @@ impl Fail { Causes { fail: Some(self) } } + /// Displays the failure. + pub fn display(&self) -> FailDisplay { + FailDisplay(self, None) + } + /// Deprecated alias to `find_root_cause`. #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")] pub fn root_cause(&self) -> &Fail { From 0936ee41b5c5ea7d2c7820518c48d01490223922 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 28 Jul 2018 17:03:48 +0200 Subject: [PATCH 2/2] Remove std dependency --- src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display.rs b/src/display.rs index 4e6cb90..e0f9037 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,4 +1,4 @@ -use std::fmt; +use _core::fmt; use Fail; use backtrace::Backtrace;