dtolnay / thiserror

derive(Error) for struct and enum error types
Apache License 2.0
4.44k stars 159 forks source link

feature request: with_context #336

Closed andreytkachenko closed 2 hours ago

andreytkachenko commented 3 hours ago

Basic idea in brief:

Add with_context proc macro option, like

#[derive(Debug, thiserror::Error)]
#[thiserror(with_context)]
enum Error {
    #[error("Io Error: {0}")]
    IoError(#[from] std::io::Error)
}

it will be expanded into something like:

#[derive(Debug, thiserror::Error)]
enum Error {
    #[error("Io Error: {0}")]
    IoError(#[from] std::io::Error),

    #[error("{1} ({0})")]
    WithContext(thiserror::ErrorContext, Box<Self>),
}

impl<T: Into<Error>, U> thiserror::WithContext<Error, U> for Result<U, T> {
    #[track_caller]
    fn with_context<S: ToString>(self, message: S) -> Result<U, Error> {
        self.map_err(|err| {
            Error::WithContext(
                thiserror::ErrorContext {
                    backtrace: None,
                    location: core::panic::Location::caller(),
                    message: message.to_string(),
                },
                Box::new(err.into()),
            )
        })
    }

    #[track_caller]
    fn with_backtrace<S: ToString>(self, message: S) -> Result<U, Error> {
        self.map_err(|err| {
            Error::WithContext(
                thiserror::ErrorContext {
                    backtrace: Some(std::backtrace::Backtrace::capture()),
                    location: core::panic::Location::caller(),
                    message: message.to_string(),
                },
                Box::new(err.into()),
            )
        })
    }
}

Usage cese:


fn test(a: &Path, b: &Path) -> Result<Vec<u8>, Error> {
   let a = std::fs::read().with_context("file a")?;
   let b = std::fs::read().with_context("file b")?;

   Ok(a.concat(b))
}
dtolnay commented 2 hours ago

I would prefer not to build this into this crate.

You can get some of this by using anyhow's Context extension trait in combination with thiserror. Or you can look for a more fully featured error enum library.