use crate::error::ContextError; use crate::{Context, Error, StdError}; use core::convert::Infallible; use core::fmt::{self, Debug, Display, Write}; #[cfg(backtrace)] use std::error::Request; mod ext { use super::*; pub trait StdError { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static; } #[cfg(feature = "std")] impl StdError for E where E: std::error::Error + Send + Sync + 'static, { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static, { let backtrace = backtrace_if_absent!(&self); Error::from_context(context, self, backtrace) } } impl StdError for Error { fn ext_context(self, context: C) -> Error where C: Display + Send + Sync + 'static, { self.context(context) } } } impl Context for Result where E: ext::StdError + Send + Sync + 'static, { fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static, { // Not using map_err to save 2 useless frames off the captured backtrace // in ext_context. match self { Ok(ok) => Ok(ok), Err(error) => Err(error.ext_context(context)), } } fn with_context(self, context: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C, { match self { Ok(ok) => Ok(ok), Err(error) => Err(error.ext_context(context())), } } } /// ``` /// # type T = (); /// # /// use anyhow::{Context, Result}; /// /// fn maybe_get() -> Option { /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unimplemented!() /// } /// /// fn demo() -> Result<()> { /// let t = maybe_get().context("there is no T")?; /// # const IGNORE: &str = stringify! { /// ... /// # }; /// # unimplemented!() /// } /// ``` impl Context for Option { fn context(self, context: C) -> Result where C: Display + Send + Sync + 'static, { // Not using ok_or_else to save 2 useless frames off the captured // backtrace. match self { Some(ok) => Ok(ok), None => Err(Error::from_display(context, backtrace!())), } } fn with_context(self, context: F) -> Result where C: Display + Send + Sync + 'static, F: FnOnce() -> C, { match self { Some(ok) => Ok(ok), None => Err(Error::from_display(context(), backtrace!())), } } } impl Debug for ContextError where C: Display, E: Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Error") .field("context", &Quoted(&self.context)) .field("source", &self.error) .finish() } } impl Display for ContextError where C: Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.context, f) } } impl StdError for ContextError where C: Display, E: StdError + 'static, { fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.error) } #[cfg(backtrace)] fn provide<'a>(&'a self, request: &mut Request<'a>) { StdError::provide(&self.error, request); } } impl StdError for ContextError where C: Display, { fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) }) } #[cfg(backtrace)] fn provide<'a>(&'a self, request: &mut Request<'a>) { Error::provide(&self.error, request); } } struct Quoted(C); impl Debug for Quoted where C: Display, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_char('"')?; Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; formatter.write_char('"')?; Ok(()) } } impl Write for Quoted<&mut fmt::Formatter<'_>> { fn write_str(&mut self, s: &str) -> fmt::Result { Display::fmt(&s.escape_debug(), self.0) } } pub(crate) mod private { use super::*; pub trait Sealed {} impl Sealed for Result where E: ext::StdError {} impl Sealed for Option {} }