Crate err_derive

Source
Expand description

§err-derive

§Deriving error causes / sources

Add an #[error(source)] attribute to the field:

use std::io;
use err_derive::Error;

/// `MyError::source` will return a reference to the `io_error` field
#[derive(Debug, Error)]
#[error(display = "An error occurred.")]
struct MyError {
    #[error(source)]
    io_error: io::Error,
}

§Automatic From implementations

From will be automatically implemented when there is a single field in the enum variant or struct, and that field has the #[source] attribute.

In cases where multiple enum variants have a #[source] field of the same type all but one of the variants need to be opted-out from the automatic From implementation (see below).

use std::io;
use err_derive::Error;

/// `From<io::Error>` will be implemented for `MyError`
#[derive(Debug, Error)]
#[error(display = "An error occurred.")]
struct MyError {
    #[error(from)]
    io_error: io::Error,
}

§Opt out of From implementation

Use the #[no_from] attribute on either the enum or a single variant to opt-out of the automatic From implementation.

When #[no_from] is set on the enum, you can opt-in individual variants by using #[from]

use err_derive::Error;
use std::{io, fmt};

#[derive(Debug, Error)]
enum ClientError {
    #[error(display = "regular bad io error {}", _0)]
    Io(#[source] io::Error),
    #[error(display = "extra bad io error {}", _0)]
    // Without #[no_from], this From impl would conflict with the normal Io error
    ReallyBadIo(#[error(source, no_from)] io::Error)
}

#[derive(Debug, Error)]
#[error(no_from)] // Don't impl From for any variants by default
enum InnerError {
    #[error(display = "an error")]
    Io(#[source] io::Error),
    #[error(display = "an error")]
    // Opt-in impl From for a single variant
    Formatting(#[error(source, from)] fmt::Error)
}

§Auto-boxing From implementation

If an enum single variant has Box<T> as its type, a From implementation for T will be automatically be generated that wraps it in Box::new.

use err_derive::Error;
use std::{io, fmt};

#[derive(Debug, Error)]
enum ClientError {
    #[error(display = "io error in a box{}", _0)]
    Io(#[error(source)] Box<io::Error>),
}

§Formatting fields

use std::path::PathBuf;
use err_derive::Error;

#[derive(Debug, Error)]
pub enum FormatError {
    #[error(display = "invalid header (expected: {:?}, got: {:?})", expected, found)]
    InvalidHeader {
        expected: String,
        found: String,
    },
    // Note that tuple fields need to be prefixed with `_`
    #[error(display = "missing attribute: {:?}", _0)]
    MissingAttribute(String),

}

#[derive(Debug, Error)]
pub enum LoadingError {
    #[error(display = "could not decode file")]
    FormatError(#[error(source)] #[error(from)] FormatError),
    #[error(display = "could not find file: {:?}", path)]
    NotFound { path: PathBuf },
}

§Printing the error

use std::error::Error;

fn print_error(e: &dyn Error) {
    eprintln!("error: {}", e);
    let mut cause = e.source();
    while let Some(e) = cause {
        eprintln!("caused by: {}", e);
        cause = e.source();
    }
}

Derive Macros§