[][src]Macro custom_error::custom_error

macro_rules! custom_error {
    (
        $( #[$meta_attribute:meta] )* // Attributes, like #[derive(SomeTrait)]
        $visibility:vis // `pub` marker
        $errtype:ident // Name of the error type to generate
        $( < $(
            $type_param:tt // Optional type parameters for generic error types
            ),*
        > )?
        $(
            $field:ident // Name of an error variant
            $( { $(
                $attr_name:ident // Name of an attribute of the error variant
                :
                $($attr_type:ident)::* // type of the attribute
                $(< $($attr_type_param:tt),* >)? // Generic (lifetime & type) parameters for the attribute's type
            ),* } )?
            =
            $( @{ $($msg_fun:tt)* } )?
            $($msg:expr)? // The human-readable error message
         ),*
         $(,)* // Trailing comma
    ) => { ... };
    (
        $( #[$meta_attribute:meta] )* // Attributes, like #[derive(SomeTrait)]
        $visibility:vis // `pub` marker
        $errtype:ident // Name of the error type to generate
        $( < $(
            $type_param:tt // Optional type parameters for generic error types
            ),*
        > )?
        { $(
            $field_name:ident // Name of an attribute of the error variant
            :
            $($field_type:ident)::* // type of the attribute
            $(< $($field_type_param:tt),* >)? // Generic (lifetime & type) parameters for the attribute's type
        ),* }
        =
        $( @{ $($msg_fun:tt)* } )?
        $($msg:expr)? // The human-readable error message
        $(,)* // Trailing comma
    ) => { ... };
}

Constructs a custom error type.

Examples

Simple error

For an error with multiple cases you can generate an enum:

use custom_error::custom_error;

custom_error!{ pub MyError
    Bad      = "Something bad happened",
    Terrible = "This is a very serious error!!!"
}
assert_eq!("Something bad happened",          MyError::Bad.to_string());
assert_eq!("This is a very serious error!!!", MyError::Terrible.to_string());

For an error with a single case you can generate a struct:

use custom_error::custom_error;

custom_error!{ pub MyError{} = "Something bad happened" }
assert_eq!("Something bad happened", MyError{}.to_string());

Custom error with parameters

use custom_error::custom_error;

custom_error!{SantaError
    BadChild{name:String, foolishness:u8} = "{name} has been bad {foolishness} times this year",
    TooFar                                = "The location you indicated is too far from the north pole",
    InvalidReindeer{legs:u8}              = "The reindeer has {legs} legs"
}

assert_eq!(
    "Thomas has been bad 108 times this year",
    SantaError::BadChild{
        name: "Thomas".into(),
        foolishness: 108
    }.to_string());

assert_eq!(
    "The location you indicated is too far from the north pole",
    SantaError::TooFar.to_string()
);

assert_eq!(
    "The reindeer has 8 legs",
    SantaError::InvalidReindeer{legs:8}.to_string()
);

Automatic conversion from other error types

You can add a special field named source to your error types.

Use this field to include the lower-level source of the error. It will be used in the error source() method, and automatic conversion from the source error type to your custom error type will be possible (your error type will implement From<SourceErrorType>).

limitations

  • You cannot have several error cases that contain a single source field of the same type: custom_error!(E A{source:X} B{source:Y}) is allowed, but custom_error!(E A{source:X} B{source:X}) is forbidden.
  • If the source field is not the only one, then the automatic conversion will not be implemented.
use custom_error::custom_error;
use std::{io, io::Read, fs::File, result::Result};

custom_error!{MyError
    IO{source: io::Error} = "input/output error",
    Unknown               = "unknown error"
}

fn read_file(filename: &str) -> Result<String, MyError> {
    let mut res = String::new();
    File::open(filename)?.read_to_string(&mut res)?;
    Ok(res)
}

assert_eq!(
    "input/output error",
    read_file("/i'm not a file/").unwrap_err().to_string()
)

Custom formatting function for error messages

If the format string syntax is not enough to express your complex error formatting needs, you can use custom code to generate your error description.

use custom_error::custom_error;

static lang : &'static str = "FR";


custom_error!{ pub MyError
    Problem      = @{ localize(lang, "A problem occurred") },
}

assert_eq!("Un problème est survenu", MyError::Problem.to_string());
use custom_error::custom_error;
use std::io::Error;
use std::io::ErrorKind::*;

custom_error!{ pub MyError
    Io{source: Error} = @{
        match source.kind() {
            NotFound => "The file does not exist",
            TimedOut => "The operation timed out",
            _ => "unknown error",
        }
    },
}

assert_eq!("The operation timed out", MyError::Io{source: TimedOut.into()}.to_string());

Derive traits for your errors

You can add custom attributes at the beginning of the macro invocation. This allows you to derive traits for your error:

use custom_error::custom_error;

custom_error! {
    #[derive(PartialEq,PartialOrd)]
    ErrLevel Small = "Don't worry", Serious = "Aaargh!!!"
}
assert_ne!(ErrLevel::Small, ErrLevel::Serious);
assert!(ErrLevel::Small < ErrLevel::Serious);