DEV Community

toyster
toyster

Posted on

Error handling (Part 2)

Using anyhow and my favorite color-eyre crates for error reporting and handling.

use color_eyre::eyre::{eyre, Result};
use color_eyre::*;

fn main() -> Result<()> {
    color_eyre::install().unwrap();


// ************************************************************
    // ******************** wrap_err
// ************************************************************
    // wrap_err wraps the error with new message
let _a = "123a".parse::<f32>().wrap_err("parsing something bad")?;
/*
Error:
    0: parsing something bad
    1: invalid float literal

Location:
    src/main.rs:25
*/


//************************************************************
// ******************** eyre!("message")
//************************************************************
// eyre! just changes the underlying error message and colors it
/*
Error:
    0: parsing something bad

Location:
    src/main.rs:23

*/
let _a = "123a"
   .parse::<f32>()
   .map_err(|_e| eyre!("parsing something bad"))?;


// ************************************************************
    // ******************** eyre!(Error)
// ************************************************************
// bubble up underlying error, not helpful, until you have RUST_BACKTRACE
/*
Error:
    0: invalid digit found in string

Location:
    /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/convert/mod.rs:538
*/

let _a = "123a"
   .parse::<f32>()
   .map_err(|e| eyre!(e))?;

    Ok(())
}

Enter fullscreen mode Exit fullscreen mode

If using thiserror for creating error types and propagating color-eyre errors to them, use

#[derive(Error, Debug)]
pub struct MyError {
    msg: String,
    #[source]  // optional if field name is `source`
    source: eyre::Error,
}
Enter fullscreen mode Exit fullscreen mode

Using anyhow (we prefer color-eyre)

use anyhow::*;
use std::fmt::Debug; // 1.0.40

fn test_error1() -> Result<()> {
    let _ = "a".parse::<i32>().context("some context with parse i32")?;
    let _ = "a".parse::<f64>()?;
    Ok(())
}

fn test_error2() -> Result<()> {
    let _ = "1".parse::<i32>()?;
    let _ = "a".parse::<f64>()?;
    Ok(())
}

fn main() -> Result<()> {
    test_error1().context("give some context to the error generated from this error")?;
    Ok(())
}

Enter fullscreen mode Exit fullscreen mode

Using anyhow and thiserror together

use anyhow::*;
use std::fmt::Debug;
use std::num::{ParseFloatError, ParseIntError};
use thiserror; // 1.0.25 // 1.0.40

#[derive(thiserror::Error, Debug)]
enum MyErrors {
    #[error("my first error")]
    Error1(#[from] ParseIntError),
    #[error("my second error")]
    Error2(#[from] ParseFloatError),
}

fn test_error1() -> Result<(), MyErrors> {
    let _ = "a".parse::<i32>()?; ///// raises error with error message "my first error"
    let _ = "a".parse::<f64>()?;
    Ok(())
}

fn test_error2() -> Result<()> {
    let _ = "1".parse::<i32>()?;
    let _ = "a".parse::<f64>()?;
    Ok(())
}

fn main() -> Result<()> {
    // test_error1()?;
    if let Err(e) = test_error1() {
        println!("Error message: {}", e);
        //        if let Some(source) = e.source() { ///// this is error because source is not found, remove this block
        //            println!(" Caused by: {}", source)
        //        }
    }
    // if let Err(e) = test_error2() {
    //     println!("Error message: {}", e)
    // }
    Ok(())
}

////// Error message: my first error
Enter fullscreen mode Exit fullscreen mode

Simple anyhow macro

// simple macro
use anyhow::{anyhow, Error};

macro_rules! test {
    ($x:expr) => { $x.map_err(|e| anyhow!(e)) }
}



// Extension method - this is good
use anyhow::{anyhow, Error};
trait AnyhowExt<O, E> {
    fn as_anyhow(self) -> Result<O, Error>;
}

impl<O, E> AnyhowExt<O, E> for Result<O, E> where E: Into<Error> {
    fn as_anyhow(self) -> Result<O, Error> {
        self.map_err(|e| anyhow!(e))
    }
}

fn main() {
    use AnyhowExt;
    let err = "NaN".parse::<u32>();
    //let y: Result<u32, Error> = err.map_err(|e| anyhow!(e));
    let y: Result<u32, Error> = err.as_anyhow();
    println!("{:?}", y);
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)