eyre

Trait WrapErr

Source
pub trait WrapErr<T, E>: Sealed {
    // Required methods
    fn wrap_err<D>(self, msg: D) -> Result<T, Report>
       where D: Display + Send + Sync + 'static;
    fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
       where D: Display + Send + Sync + 'static,
             F: FnOnce() -> D;
    fn context<D>(self, msg: D) -> Result<T, Report>
       where D: Display + Send + Sync + 'static;
    fn with_context<D, F>(self, f: F) -> Result<T, Report>
       where D: Display + Send + Sync + 'static,
             F: FnOnce() -> D;
}
Expand description

Provides the wrap_err method for Result.

This trait is sealed and cannot be implemented for types outside of eyre.

§Example

use eyre::{WrapErr, Result};
use std::fs;
use std::path::PathBuf;

pub struct ImportantThing {
    path: PathBuf,
}

impl ImportantThing {
    pub fn detach(&mut self) -> Result<()> {...}
}

pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
    it.detach().wrap_err("Failed to detach the important thing")?;

    let path = &it.path;
    let content = fs::read(path)
        .wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?;

    Ok(content)
}

When printed, the outermost error would be printed first and the lower level underlying causes would be enumerated below.

Error: Failed to read instrs from ./path/to/instrs.json

Caused by:
    No such file or directory (os error 2)

§Wrapping Types That Don’t impl Error (e.g. &str and Box<dyn Error>)

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:

use std::error::Error;
use eyre::{WrapErr, Report};

fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
    err.wrap_err("saw a downstream error")
}

We encourage you to write this:

use std::error::Error;
use eyre::{WrapErr, Report, eyre};

fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> 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 eyre::Report may be downcast to D or to E.

That is, in codebases that rely on downcasting, Eyre’s wrap_err supports both of the following use cases:

  • Attaching messages whose type is insignificant onto errors whose type is used in downcasts.

    In other error libraries whose wrap_err is not designed this way, it can be risky to introduce messages to existing code because new message might break existing working downcasts. In Eyre, any downcast that worked before adding the message will continue to work after you add a message, so you should freely wrap errors wherever it would be helpful.

    use eyre::{WrapErr, Result};
    
    fn do_it() -> Result<()> {
        helper().wrap_err("Failed to complete the work")?;
        ...
    }
    
    fn main() {
        let err = do_it().unwrap_err();
        if let Some(e) = err.downcast_ref::<SuspiciousError>() {
            // If helper() returned SuspiciousError, this downcast will
            // correctly succeed even with the message in between.
        }
    }
  • Attaching message whose type is used in downcasts onto errors whose type is insignificant.

    Some codebases prefer to use machine-readable messages to categorize lower level errors in a way that will be actionable to higher levels of the application.

    use eyre::{WrapErr, Result};
    
    fn do_it() -> Result<()> {
        helper().wrap_err(HelperFailed)?;
        ...
    }
    
    fn main() {
        let err = do_it().unwrap_err();
        if let Some(e) = err.downcast_ref::<HelperFailed>() {
            // If helper failed, this downcast will succeed because
            // HelperFailed is the message that has been attached to
            // that error.
        }
    }

§wrap_err vs wrap_err_with

wrap_err incurs a runtime cost even in the non-error case because it requires eagerly constructing the error object. wrap_err_with avoids this cost through lazy evaluation. This cost is proportional to the cost of the currently installed EyreHandler’s creation step. wrap_err is useful in cases where an constructed error object already exists.

Required Methods§

Source

fn wrap_err<D>(self, msg: D) -> Result<T, Report>
where D: Display + Send + Sync + 'static,

Wrap the error value with a new adhoc error

Source

fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
where D: Display + Send + Sync + 'static, F: FnOnce() -> D,

Wrap the error value with a new adhoc error that is evaluated lazily only once an error does occur.

Source

fn context<D>(self, msg: D) -> Result<T, Report>
where D: Display + Send + Sync + 'static,

Compatibility re-export of wrap_err for interop with anyhow

Source

fn with_context<D, F>(self, f: F) -> Result<T, Report>
where D: Display + Send + Sync + 'static, F: FnOnce() -> D,

Compatibility re-export of wrap_err_with for interop with anyhow

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl<T, E> WrapErr<T, E> for Result<T, E>
where E: StdError + Send + Sync + 'static,

Source§

fn wrap_err<D>(self, msg: D) -> Result<T, Report>
where D: Display + Send + Sync + 'static,

Source§

fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
where D: Display + Send + Sync + 'static, F: FnOnce() -> D,

Source§

fn context<D>(self, msg: D) -> Result<T, Report>
where D: Display + Send + Sync + 'static,

Source§

fn with_context<D, F>(self, msg: F) -> Result<T, Report>
where D: Display + Send + Sync + 'static, F: FnOnce() -> D,

Implementors§