#[macro_export]
macro_rules! custom_error {
(
$errtype:ident
$(
$field:ident
$( { $( $attr_name:ident : $attr_type:ty ),* } )*
=
$msg:expr
),*
) => {
#[derive(Debug)]
enum $errtype {
$(
$field
$( { $( $attr_name : $attr_type ),* } )*
),*
};
impl std::error::Error for $errtype {};
impl std::fmt::Display for $errtype {
fn fmt(&self, f: &mut std::fmt::Formatter)
-> std::fmt::Result
{
match self {$(
$errtype::$field $( { $( $attr_name ),* } )* => {
write!(f, $msg $( $( , $attr_name = $attr_name )* )*)
}
),*}
}
}
};
}
#[cfg(test)]
mod tests {
#[test]
fn single_error_case() {
custom_error!(MyError Bad="bad");
assert_eq!("bad", MyError::Bad.to_string())
}
#[test]
#[allow(dead_code)]
fn three_error_cases() {
custom_error!(MyError NotPerfect=":/", Bad="bad", Awfull="arghhh");
assert_eq!("arghhh", MyError::Awfull.to_string())
}
#[test]
fn with_error_data() {
custom_error!(MyError
Bad = "bad",
Catastrophic{broken_things:u8} = "{broken_things} things are broken"
);
assert_eq!("bad", MyError::Bad.to_string());
assert_eq!(
"9 things are broken",
MyError::Catastrophic { broken_things: 9 }.to_string()
);
}
#[test]
fn with_multiple_error_data() {
custom_error!(E X{a:u8, b:u8, c:u8} = "{c} {b} {a}");
assert_eq!("3 2 1", E::X { a: 1, b: 2, c: 3 }.to_string());
}
}