thiserror

The thiserror crate provides macros to help avoid boilerplate when defining error types. It provides derive macros that assist in implementing From<T>, Display, and the Error trait.

1. ```
   use std::io::Read;
   ```
2. ```
   use std::{fs, io};
   ```
3. ```
   use thiserror::Error;
   ```

5. ```
   #[derive(Debug, Error)]
   ```
6. ```
   enum ReadUsernameError {
   ```
7. ```
       #[error("I/O error: {0}")]
   ```
8. ```
       IoError(#[from] io::Error),
   ```
9. ```
       #[error("Found no username in {0}")]
   ```
10. ```
        EmptyUsername(String),
    ```
11. ```
    }
    ```

13. ```
    fn read_username(path: &str) -> Result&lt;String, ReadUsernameError> {
    ```
14. ```
        let mut username = String::with_capacity(100);
    ```
15. ```
        fs::File::open(path)?.read_to_string(&mut username)?;
    ```
16. ```
        if username.is_empty() {
    ```
17. ```
            return Err(ReadUsernameError::EmptyUsername(String::from(path)));
    ```
18. ```
        }
    ```
19. ```
        Ok(username)
    ```
20. ```
    }
    ```

22. ```
    fn main() {
    ```
23. ```
        //fs::write("config.dat", "").unwrap();
    ```
24. ```
        match read_username("config.dat") {
    ```
25. ```
            Ok(username) => println!("Username: {username}"),
    ```
26. ```
            Err(err) => println!("Error: {err:?}"),
    ```
27. ```
        }
    ```
28. ```
    }
    ```

This slide should take about 5 minutes.

  • The Error derive macro is provided by thiserror, and has lots of useful attributes to help define error types in a compact way.
  • The message from #[error] is used to derive the Display trait.
  • Note that the (thiserror::)Error derive macro, while it has the effect of implementing the (std::error::)Error trait, is not the same this; traits and macros do not share a namespace.