Easier errors
You may have noticed that it is rather cumbersome to write all those From methods to convert existing errors into our own variant. Fortunately, a crate exists to make this job easier: thiserror.
After adding thiserror to your Cargo.toml
$ cargo add thiserror
you will be able to define your Error type as follows:
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] enum Error { #[error("Wrong HTTP status code: {0}")] BadHttpResult(u16), #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] ReqwestError(#[from] reqwest::Error), } }
Our Error type looks the same as before with a few additions:
- It derives
thiserror::Error. This is the heart of thethiserrorcrate and makes the other things below work. Behind the scenes, it uses "procedural macros" which is a way to transform some Rust code into another Rust code during the compilation. - The
#[error]attribute indicates how to display the error.{0}refers to the first field. The fields could also be named, a fieldxyzwould use{xyz}in the#[error]attribute. If you are encapsulating another error, you may usetransparentto indicate that you simply want to display the inner error, and that you have nothing to add. - The
#[from]attribute on the field of a variant indicates that aFromimplementation should be generated from the type following#[from]to anError. - Your
Errortype will implement thestd::error::Errortrait which allows proper error chaining: the system will know (and will be able to display) that the cause of aError::ReqwestErroris areqwest::Error, which might also be caused by another deeper error, and so on.
Exercise 5.a: modify your Error type to use thiserror and remove your existing From implementations.
Check that everything still works, including when you make errors happens by changing the urls or the file name.