diff --git a/Cargo.toml b/Cargo.toml index 21f1d12..a4c629c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,10 @@ rustversion = "1.0" thiserror = "1.0" trybuild = { version = "1.0.19", features = ["diff"] } backtrace = "0.3.46" +anyhow = "1.0.28" [dependencies] -indenter = "0.1.3" +indenter = "0.2.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/README.md b/README.md index f74069d..84f7959 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Eyre +eyre ==== [![Build Status][actions-badge]][actions-url] @@ -158,13 +158,22 @@ This crate does its best to be usable as a drop in replacement of `anyhow` and vice-versa by `re-exporting` all of the renamed APIs with the names used in `anyhow`. -It is not 100% compatible because there are some cases where `eyre` encounters -type inference errors but it should mostly work as a drop in replacement. -Specifically, the following works in anyhow: +There are two main incompatibilities that you might encounter when porting a +codebase from `anyhow` to `eyre`: + +- type inference errors when using `eyre!` +- `.context` not being implemented for `Option` + +#### Type Inference Errors + +The type inference issue is caused by the generic parameter, which isn't +present in `anyhow::Error`. Specifically, the following works in anyhow: ```rust +use anyhow::anyhow; + // Works -let val = get_optional_val.ok_or_else(|| anyhow!("failed to get value")).unwrap(); +let val = get_optional_val().ok_or_else(|| anyhow!("failed to get value")).unwrap_err(); ``` Where as with `eyre!` this will fail due to being unable to infer the type for @@ -172,13 +181,48 @@ the Context parameter. The solution to this problem, should you encounter it, is to give the compiler a hint for what type it should be resolving to, either via your return type or a type annotation. -```rust +```rust,compile_fail +use eyre::eyre; + // Broken -let val = get_optional_val.ok_or_else(|| eyre!("failed to get value")).unwrap(); +let val = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap(); // Works -let val: Report = get_optional_val.ok_or_else(|| eyre!("failed to get value")).unwrap(); +let val: Report = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap(); +``` + +#### `Context` and `Option` + +As part of renaming `Context` to `WrapErr` we also intentionally do not +implement `WrapErr` for `Option`. This decision was made because `wrap_err` +implies that you're creating a new error that saves the old error as its +`source`. With `Option` there is no source error to wrap, so `wrap_err` ends up +being somewhat meaningless. + +Instead `eyre` intends for users to use the combinator functions provided by +`std` for converting `Option`s to `Result`s. So where you would write this with +anyhow: + +```rust +use anyhow::Context; + +let opt: Option<()> = None; +let result = opt.context("new error message"); +``` + +With `eyre` we want users to write: + +```rust +use eyre::{eyre, Result}; + +let opt: Option<()> = None; +let result: Result<()> = opt.ok_or_else(|| eyre!("new error message")); ``` + +However, to help with porting we do provide a `ContextCompat` trait which +implements `context` for options which you can import to make existing +`.context` calls compile. + [Report]: https://docs.rs/eyre/*/eyre/struct.Report.html [`eyre::EyreContext`]: https://docs.rs/eyre/*/eyre/trait.EyreContext.html [`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html diff --git a/src/chain.rs b/src/chain.rs index 207e4f0..67edcc0 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -24,6 +24,26 @@ pub(crate) enum ChainState<'a> { } impl<'a> Chain<'a> { + /// Construct an iterator over a chain of errors via the `source` method + /// + /// # Example + /// + /// ```rust + /// use std::error::Error; + /// use std::fmt::{self, Write}; + /// use eyre::Chain; + /// use indenter::indented; + /// + /// fn report(error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// let mut errors = Chain::new(error).enumerate(); + /// for (i, error) in errors { + /// writeln!(f)?; + /// write!(indented(f).ind(i), "{}", error)?; + /// } + /// + /// Ok(()) + /// } + /// ``` pub fn new(head: &'a (dyn StdError + 'static)) -> Self { Chain { state: ChainState::Linked { next: Some(head) }, diff --git a/src/context.rs b/src/context.rs index d724e06..844e1a8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,5 +1,5 @@ use crate::error::ContextError; -use crate::{EyreContext, Report, StdError, WrapErr}; +use crate::{ContextCompat, EyreContext, Report, StdError, WrapErr}; use core::fmt::{self, Debug, Display, Write}; #[cfg(backtrace)] @@ -80,12 +80,47 @@ where } } +impl ContextCompat for Option +where + C: EyreContext, +{ + fn wrap_err(self, msg: D) -> Result> + where + D: Display + Send + Sync + 'static, + { + self.context(msg) + } + + fn wrap_err_with(self, msg: F) -> Result> + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D, + { + self.with_context(msg) + } + + fn context(self, msg: D) -> Result> + where + D: Display + Send + Sync + 'static, + { + self.ok_or_else(|| Report::from_display(msg)) + } + + fn with_context(self, msg: F) -> Result> + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D, + { + self.ok_or_else(|| Report::from_display(msg())) + } +} + impl Debug for ContextError where D: Display, E: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Error") .field("msg", &Quoted(&self.msg)) .field("source", &self.error) @@ -97,7 +132,7 @@ impl Display for ContextError where D: Display, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.msg, f) } } @@ -133,7 +168,7 @@ impl Debug for Quoted where D: Display, { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_char('"')?; Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; formatter.write_char('"')?; @@ -153,4 +188,5 @@ pub(crate) mod private { pub trait Sealed {} impl Sealed for Result where E: ext::StdError {} + impl Sealed for Option {} } diff --git a/src/error.rs b/src/error.rs index af839a2..f16b984 100644 --- a/src/error.rs +++ b/src/error.rs @@ -116,6 +116,28 @@ where unsafe { Report::construct(error, vtable, context) } } + pub(crate) fn from_display(message: M) -> Self + where + M: Display + Send + Sync + 'static, + { + use crate::wrapper::{DisplayError, NoneError}; + let error: DisplayError = DisplayError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::, C>, + object_ref: object_ref::, C>, + #[cfg(feature = "std")] + object_mut: object_mut::, C>, + object_boxed: object_boxed::, C>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // Safety: DisplayError is repr(transparent) so it is okay for the + // vtable to allow casting the DisplayError to M. + let context = Some(C::default(&NoneError)); + unsafe { Report::construct(error, vtable, context) } + } + #[cfg(feature = "std")] pub(crate) fn from_msg(msg: D, error: E) -> Self where @@ -280,7 +302,7 @@ where /// } /// ``` #[cfg(feature = "std")] - pub fn chain(&self) -> Chain { + pub fn chain(&self) -> Chain<'_> { self.inner.chain() } @@ -448,13 +470,13 @@ impl DerefMut for Report { } impl Display for Report { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.display(formatter) } } impl Debug for Report { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.debug(formatter) } } @@ -674,8 +696,8 @@ where // ContextError, E> and ContextError>. #[repr(C)] pub(crate) struct ContextError { - pub msg: D, - pub error: E, + pub(crate) msg: D, + pub(crate) error: E, } impl ErrorImpl @@ -707,7 +729,7 @@ where unsafe { &mut *(self.vtable.object_mut)(self) } } - pub(crate) fn chain(&self) -> Chain { + pub(crate) fn chain(&self) -> Chain<'_> { Chain::new(self.error()) } } @@ -727,7 +749,7 @@ where C: EyreContext, E: Debug, { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { self.erase().debug(formatter) } } @@ -737,7 +759,7 @@ where C: EyreContext, E: Display, { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.erase().error(), formatter) } } diff --git a/src/fmt.rs b/src/fmt.rs index 42e0e57..da24918 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -6,14 +6,14 @@ impl ErrorImpl<(), C> where C: EyreContext, { - pub(crate) fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { + pub(crate) fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.context .as_ref() .map(|context| context.display(self.error(), f)) .unwrap_or_else(|| std::fmt::Display::fmt(self.error(), f)) } - pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { + pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.context .as_ref() .map(|context| context.debug(self.error(), f)) diff --git a/src/kind.rs b/src/kind.rs index 5dffb87..4b82288 100644 --- a/src/kind.rs +++ b/src/kind.rs @@ -1,3 +1,4 @@ +#![allow(missing_debug_implementations, missing_docs)] // Tagged dispatch mechanism for resolving the behavior of `eyre!($expr)`. // // When eyre! is given a single expr argument to turn into eyre::Report, we diff --git a/src/lib.rs b/src/lib.rs index 16772a6..4f1434c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! [dependencies] //! eyre = "0.4" //! ``` -//! # Details +//! ## Details //! //! - Use `Result`, or equivalently `eyre::Result`, as //! the return type of any fallible function. @@ -177,7 +177,7 @@ //! # } //! ``` //! -//! # No-std support +//! ## No-std support //! //! In no_std mode, the same API is almost all available and works the same way. //! To depend on Eyre in no_std mode, disable our default enabled "std" @@ -193,19 +193,29 @@ //! will require an explicit `.map_err(Report::msg)` when working with a //! non-Eyre error type inside a function that returns Eyre's error type. //! -//! # Compatibility with `anyhow` +//! ## Compatibility with `anyhow` //! //! This crate does its best to be usable as a drop in replacement of `anyhow` and //! vice-versa by `re-exporting` all of the renamed APIs with the names used in //! `anyhow`. //! -//! It is not 100% compatible because there are some cases where `eyre` encounters -//! type inference errors but it should mostly work as a drop in replacement. -//! Specifically, the following works in anyhow: +//! There are two main incompatibilities that you might encounter when porting a +//! codebase from `anyhow` to `eyre`: +//! +//! - type inference errors when using `eyre!` +//! - `.context` not being implemented for `Option` +//! +//! #### Type Inference Errors +//! +//! The type inference issue is caused by the generic parameter, which isn't +//! present in `anyhow::Error`. Specifically, the following works in anyhow: +//! +//! ```rust +//! # fn get_optional_val() -> Option<()> { None }; +//! use anyhow::anyhow; //! -//! ```rust,compile_fail //! // Works -//! let val = get_optional_val.ok_or_else(|| anyhow!("failed to get value")).unwrap(); +//! let val = get_optional_val().ok_or_else(|| anyhow!("failed to get value")).unwrap_err(); //! ``` //! //! Where as with `eyre!` this will fail due to being unable to infer the type for @@ -214,12 +224,47 @@ //! via your return type or a type annotation. //! //! ```rust,compile_fail +//! use eyre::eyre; +//! +//! # fn get_optional_val() -> Option<()> { None }; //! // Broken -//! let val = get_optional_val.ok_or_else(|| eyre!("failed to get value")).unwrap(); +//! let val = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap(); //! //! // Works -//! let val: Report = get_optional_val.ok_or_else(|| eyre!("failed to get value")).unwrap(); +//! let val: Report = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap(); +//! ``` +//! +//! #### `Context` and `Option` +//! +//! As part of renaming `Context` to `WrapErr` we also intentionally do not +//! implement `WrapErr` for `Option`. This decision was made because `wrap_err` +//! implies that you're creating a new error that saves the old error as its +//! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up +//! being somewhat meaningless. +//! +//! Instead `eyre` intends for users to use the combinator functions provided by +//! `std` for converting `Option`s to `Result`s. So where you would write this with +//! anyhow: +//! +//! ```rust +//! use anyhow::Context; +//! +//! let opt: Option<()> = None; +//! let result = opt.context("new error message"); +//! ``` +//! +//! With `eyre` we want users to write: +//! +//! ```rust +//! use eyre::{eyre, Result}; +//! +//! let opt: Option<()> = None; +//! let result: Result<()> = opt.ok_or_else(|| eyre!("new error message")); //! ``` +//! +//! However, to help with porting we do provide a `ContextCompat` trait which +//! implements `context` for options which you can import to make existing +//! `.context` calls compile. //! [Report]: https://docs.rs/eyre/*/eyre/struct.Report.html //! [`eyre::EyreContext`]: https://docs.rs/eyre/*/eyre/trait.EyreContext.html //! [`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html @@ -228,6 +273,29 @@ //! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html //! [`stable_eyre`]: https://docs.rs/stable-eyre #![doc(html_root_url = "https://docs.rs/eyre/0.4.0")] +#![warn( + missing_debug_implementations, + missing_docs, + missing_doc_code_examples, + rust_2018_idioms, + unreachable_pub, + bad_style, + const_err, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + private_in_public, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true +)] #![cfg_attr(backtrace, feature(backtrace))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr(not(feature = "std"), no_std)] @@ -242,16 +310,16 @@ mod alloc { extern crate alloc; #[cfg(not(feature = "std"))] - pub use alloc::boxed::Box; + pub(crate) use alloc::boxed::Box; #[cfg(feature = "std")] - pub use std::boxed::Box; + pub(crate) use std::boxed::Box; #[cfg(not(feature = "std"))] - pub use alloc::string::String; + pub(crate) use alloc::string::String; - #[cfg(feature = "std")] - pub use std::string::String; + // #[cfg(feature = "std")] + // pub(crate) use std::string::String; } #[macro_use] @@ -404,6 +472,7 @@ where /// use eyre::EyreContext; /// # use eyre::Chain; /// # use std::error::Error; +/// use indenter::indented; /// /// pub struct Context { /// backtrace: Backtrace, @@ -432,9 +501,9 @@ where /// # for (n, error) in Chain::new(cause).enumerate() { /// # writeln!(f)?; /// # if multiple { -/// # write!(indenter::Indented::numbered(f, n), "{}", error)?; +/// # write!(indented(f).ind(n), "{}", error)?; /// # } else { -/// # write!(indenter::Indented::new(f), "{}", error)?; +/// # write!(indented(f), "{}", error)?; /// # } /// # } /// # } @@ -491,9 +560,9 @@ pub trait EyreContext: Sized + Send + Sync + 'static { /// # for (n, error) in Chain::new(cause).enumerate() { /// # writeln!(f)?; /// # if multiple { - /// # write!(indenter::Indented::numbered(f, n), "{}", error)?; + /// # write!(indenter::indented(f).ind(n), "{}", error)?; /// # } else { - /// # write!(indenter::Indented::new(f), "{}", error)?; + /// # write!(indenter::indented(f), "{}", error)?; /// # } /// # } /// # } @@ -516,6 +585,7 @@ pub trait EyreContext: Sized + Send + Sync + 'static { /// use eyre::EyreContext; /// use eyre::Chain; /// use std::error::Error; + /// use indenter::indented; /// /// pub struct Context { /// backtrace: Backtrace, @@ -549,9 +619,9 @@ pub trait EyreContext: Sized + Send + Sync + 'static { /// for (n, error) in Chain::new(cause).enumerate() { /// writeln!(f)?; /// if multiple { - /// write!(indenter::Indented::numbered(f, n), "{}", error)?; + /// write!(indented(f).ind(n), "{}", error)?; /// } else { - /// write!(indenter::Indented::new(f), "{}", error)?; + /// write!(indented(f), "{}", error)?; /// } /// } /// } @@ -596,6 +666,20 @@ pub struct DefaultContext { backtrace: Option, } +impl core::fmt::Debug for DefaultContext { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("DefaultContext") + .field( + "backtrace", + match &self.backtrace { + Some(_) => &"Some(Backtrace { ... })", + None => &"None", + }, + ) + .finish() + } +} + impl EyreContext for DefaultContext { #[allow(unused_variables)] fn default(error: &(dyn StdError + 'static)) -> Self { @@ -623,9 +707,9 @@ impl EyreContext for DefaultContext { for (n, error) in crate::chain::Chain::new(cause).enumerate() { writeln!(f)?; if multiple { - write!(indenter::Indented::numbered(f, n), "{}", error)?; + write!(indenter::indented(f).ind(n), "{}", error)?; } else { - write!(indenter::Indented::new(f), "{}", error)?; + write!(indenter::indented(f), "{}", error)?; } } } @@ -669,6 +753,7 @@ impl EyreContext for DefaultContext { /// ``` #[cfg(feature = "std")] #[derive(Clone)] +#[allow(missing_debug_implementations)] pub struct Chain<'a> { state: crate::chain::ChainState<'a>, } @@ -769,6 +854,35 @@ pub type Result> = core::result::Result; /// No such file or directory (os error 2) /// ``` /// +/// # Wrapping Types That Don't impl `Error` (e.g. `&str` and `Box`) +/// +/// Due to restrictions for coherence `Report` cannot impl `From` for types that don't impl +/// `Error`. Attempts to do so will give "this type might implement Error in the future" as an +/// error. As such, `wrap_err`, which uses `From` under the hood, cannot be used to wrap these +/// types. Instead we encourage you to use the combinators provided for `Result` in `std`/`core`. +/// +/// For example, instead of this: +/// +/// ```rust,compile_fail +/// use std::error::Error; +/// use eyre::{WrapErr, Report}; +/// +/// fn wrap_example(err: Result<(), Box>) -> Result<(), Report> { +/// err.wrap_err("saw a downstream error") +/// } +/// ``` +/// +/// We encourage you to write this: +/// +/// ```rust +/// use std::error::Error; +/// use eyre::{WrapErr, Report, eyre}; +/// +/// fn wrap_example(err: Result<(), Box>) -> Result<(), Report> { +/// err.map_err(|e| eyre!(e)).wrap_err("saw a downstream error") +/// } +/// ``` +/// /// # Effect on downcasting /// /// After attaching a message of type `D` onto an error of type `E`, the resulting @@ -887,6 +1001,78 @@ where F: FnOnce() -> D; } +/// Provides the `context` method for `Option` when porting from `anyhow` +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `eyre`. +/// +/// ## Why Doesn't `Eyre` impl `WrapErr` for `Option`? +/// +/// `eyre` doesn't impl `WrapErr` for `Option` because `wrap_err` implies that you're creating a +/// new error that saves the previous error as its `source`. Calling `wrap_err` on an `Option` is +/// meaningless because there is no source error. `anyhow` avoids this issue by using a different +/// mental model where you're adding "context" to an error, though this not a mental model for +/// error handling that `eyre` agrees with. +/// +/// Instead, `eyre` encourages users to think of each error as distinct, where the previous error +/// is the context being saved by the new error, which is backwards compared to anyhow's model. In +/// this model you're encouraged to use combinators provided by `std` for `Option` to convert an +/// option to a `Result` +/// +/// # Example +/// +/// Instead of: +/// +/// ```rust +/// use eyre::ContextCompat; +/// +/// fn get_thing(mut things: impl Iterator) -> eyre::Result { +/// things +/// .find(|&thing| thing == 42) +/// .context("the thing wasnt in the list") +/// } +/// ``` +/// +/// We encourage you to use this: +/// +/// ```rust +/// use eyre::eyre; +/// +/// fn get_thing(mut things: impl Iterator) -> eyre::Result { +/// things +/// .find(|&thing| thing == 42) +/// .ok_or_else(|| eyre!("the thing wasnt in the list")) +/// } +/// ``` +pub trait ContextCompat: context::private::Sealed +where + C: EyreContext, +{ + /// Compatibility version of `wrap_err` for creating new errors with new source on `Option` + /// when porting from `anyhow` + fn context(self, msg: D) -> Result> + where + D: Display + Send + Sync + 'static; + + /// Compatibility version of `wrap_err_with` for creating new errors with new source on `Option` + /// when porting from `anyhow` + fn with_context(self, f: F) -> Result> + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D; + + /// Compatibility re-export of `context` for porting from `anyhow` to `eyre` + fn wrap_err(self, msg: D) -> Result> + where + D: Display + Send + Sync + 'static; + + /// Compatibility re-export of `with_context` for porting from `anyhow` to `eyre` + fn wrap_err_with(self, f: F) -> Result> + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D; +} + // Not public API. Referenced by macro-generated code. #[doc(hidden)] pub mod private { diff --git a/src/wrapper.rs b/src/wrapper.rs index 3ebe51a..2b9bdf8 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -2,13 +2,38 @@ use crate::StdError; use core::fmt::{self, Debug, Display}; #[repr(transparent)] -pub struct MessageError(pub M); +pub(crate) struct DisplayError(pub(crate) M); + +#[repr(transparent)] +pub(crate) struct MessageError(pub(crate) M); + +pub(crate) struct NoneError; + +impl Debug for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl Display for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for DisplayError where M: Display + 'static {} impl Debug for MessageError where M: Display + Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&self.0, f) } } @@ -17,50 +42,41 @@ impl Display for MessageError where M: Display + Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } impl StdError for MessageError where M: Display + Debug + 'static {} -#[repr(transparent)] -pub struct DisplayError(pub M); - -impl Debug for DisplayError -where - M: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.0, f) +impl Debug for NoneError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt("Option was None", f) } } -impl Display for DisplayError -where - M: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.0, f) +impl Display for NoneError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt("Option was None", f) } } -impl StdError for DisplayError where M: Display + 'static {} +impl StdError for NoneError {} #[cfg(feature = "std")] #[repr(transparent)] -pub struct BoxedError(pub Box); +pub(crate) struct BoxedError(pub(crate) Box); #[cfg(feature = "std")] impl Debug for BoxedError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Debug::fmt(&self.0, f) } } #[cfg(feature = "std")] impl Display for BoxedError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } }