3 ms·
`thiserror` definitely does allow it, e.g. #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Cannot open `{1}`")] OpenFile(#
by nagisa 5y ago
`thiserror` definitely does allow it, e.g.
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Cannot open `{1}`")]
OpenFile(#[source] std::io::Error, PathBuf)
#[error("Cannot read file contents")]
ReadFileContents(#[source] std::io::Error)
#[error("Cannot parse the configuration file")]
ParseConfig(#[source] serde::Error)
}
fn open_config(path: &Path) -> Result<Config, Error> {
let mut file = File::open(path).map_err(|e| Error::OpenFile(e, path.to_owned()))?;
let mut data = Vec::with_capacity(1024);
file.read_to_end(&mut data).map_err(Error::ReadFileContents)?;
parse_config(&data).map_err(Error::ParseConfig)
}
EDIT: adjusted to add an example of adding path to the error message.
- shepmaster 5y agoI should have worded myself better, apologies. With that example, since you use `Result::map_err` and specify the specific variant, you aren't really using anything from thiserror at the site of the `?`, correct? Most usages I have seen, people use `#[from]`, which would end up having conflicting implementations. Is there a reason you didn't use `#[from]` for `ParseConfig`?
- nagisa 5y agoAh, I see. In short, I consider `From::from` implementations for errors to be an anti-pattern. It is super easy to become lax about adding context with these implementations in place. Especially as code is modified in the future. I describe the approach that I use for errors in a detail in an article (https://kazlauskas.me/entries/errors.html https://kazlauskas.me/entries/errors.html) that has already been linked elsewhere in the thread. It is, as far as I can tell, pretty much equivalent to what `snafu` makes users to do.