throws 0.1.2

A macro for easy creation per-function errors.
Documentation
#![allow(unused_imports)]

#[macro_export]
macro_rules! throws {
    ($($(#[$attr:meta])* $name:ident = $($case:ident($error:path)),*);+) => {
        throws!($($(#[$attr])* () $name = $($case($error)),*);+);
    };
    ($($(#[$attr:meta])* pub $name:ident = $($case:ident($error:path)),*);+) => {
        throws!($($(#[$attr])* (pub) $name = $($case($error)),*);+);
    };
    ($($(#[$attr:meta])* pub($($restriction:tt)+) $name:ident = $($case:ident($error:path)),*);+) => {
        throws!($($(#[$attr])* (pub($($restriction)+)) $name = $($case($error)),*);+);
    };
    ($($(#[$attr:meta])* ($($vis:tt)*) $name:ident = $($case:ident($error:path)),*);+) => {
    $(
        $(#[$attr])*
        #[derive(Debug)]
        $($vis)* enum $name { $($case($error)),* }

        impl ::std::fmt::Display for $name {
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match *self {
                    $($name::$case(ref err) => write!(formatter, stringify!($case error: {}), err)),*
                }
            }
        }

        impl ::std::error::Error for $name {
            fn description(&self) -> &str {
                match *self {
                    $($name::$case(ref err) => err.description()),*
                }
            }

            fn cause(&self) -> Option<&::std::error::Error> {
                match *self {
                    $($name::$case(ref err) => Some(err)),*
                }
            }
        }

        $(
        impl ::std::convert::From<$error> for $name {
            fn from(err: $error) -> $name {
                $name::$case(err)
            }
        }
        )*
    )+
    };
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::num::{ParseIntError, ParseFloatError};

    throws!(SingleIoError = Io(io::Error));

    throws!(#[derive(PartialEq, Eq)] SingleParseIntError = Parse(ParseIntError));

    throws!(MultipleError = Io(io::Error), ParseFloat(ParseFloatError), Single(SingleIoError));

    throws! {
        IoError = Io(io::Error);
        ParseError = Parse(ParseIntError)
    }

    mod error {
        use super::*;

        throws!(pub PubError = Io(io::Error), Parse(ParseIntError));

        throws!(pub(crate) PubCrateError = Io(io::Error), Parse(ParseIntError));

        throws!(
            #[derive(PartialEq, Eq, Clone)]
            #[allow(missing_docs)]
            pub(crate) AllFeaturesError = ParseInt(ParseIntError), ParseFloat(ParseFloatError)
        );

        throws! {
            () PrivateIoError = Io(io::Error);
            #[derive(Clone)]
            (pub) PubParseError = Parse(ParseIntError)
        }
    }

    #[test]
    fn create_from_error() {
        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
        assert!(match error {
            SingleIoError::Io(_) => true,
        });

        let error = "not int"
            .parse::<i32>()
            .map_err(SingleParseIntError::from)
            .unwrap_err();
        assert!(match error {
            SingleParseIntError::Parse(_) => true,
        });
        assert_eq!(error, error);

        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
        assert!(match error {
            MultipleError::Io(_) => true,
            _ => false,
        });

        let error = SingleIoError::from(io::Error::from(io::ErrorKind::NotFound));
        let error = From::from(error);
        assert!(match error {
            MultipleError::Single(_) => true,
            _ => false,
        });

        let error = From::from("not float".parse::<f32>().unwrap_err());
        assert!(match error {
            MultipleError::ParseFloat(_) => true,
            _ => false,
        });

        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
        assert!(match error {
            error::PubError::Io(_) => true,
            _ => false,
        });

        let error = From::from("not int".parse::<i32>().unwrap_err());
        assert!(match error {
            error::PubCrateError::Parse(_) => true,
            _ => false,
        });

        let error = From::from("not float".parse::<f32>().unwrap_err());
        assert!(match error {
            error::AllFeaturesError::ParseFloat(_) => true,
            _ => false,
        });
        assert_eq!(error, error.clone());

        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
        assert!(match error {
            IoError::Io(_) => true,
        });
    }
}