throws/
lib.rs

1#![allow(unused_imports)]
2
3#[macro_export]
4macro_rules! throws {
5    ($($(#[$attr:meta])* $name:ident = $($case:ident($error:path)),*);+) => {
6        throws!($($(#[$attr])* () $name = $($case($error)),*);+);
7    };
8    ($($(#[$attr:meta])* pub $name:ident = $($case:ident($error:path)),*);+) => {
9        throws!($($(#[$attr])* (pub) $name = $($case($error)),*);+);
10    };
11    ($($(#[$attr:meta])* pub($($restriction:tt)+) $name:ident = $($case:ident($error:path)),*);+) => {
12        throws!($($(#[$attr])* (pub($($restriction)+)) $name = $($case($error)),*);+);
13    };
14    ($($(#[$attr:meta])* ($($vis:tt)*) $name:ident = $($case:ident($error:path)),*);+) => {
15    $(
16        $(#[$attr])*
17        #[derive(Debug)]
18        $($vis)* enum $name { $($case($error)),* }
19
20        impl ::std::fmt::Display for $name {
21            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
22                match *self {
23                    $($name::$case(ref err) => write!(formatter, stringify!($case error: {}), err)),*
24                }
25            }
26        }
27
28        impl ::std::error::Error for $name {
29            fn description(&self) -> &str {
30                match *self {
31                    $($name::$case(ref err) => err.description()),*
32                }
33            }
34
35            fn cause(&self) -> Option<&::std::error::Error> {
36                match *self {
37                    $($name::$case(ref err) => Some(err)),*
38                }
39            }
40        }
41
42        $(
43        impl ::std::convert::From<$error> for $name {
44            fn from(err: $error) -> $name {
45                $name::$case(err)
46            }
47        }
48        )*
49    )+
50    };
51}
52
53#[cfg(test)]
54mod tests {
55    use std::io;
56    use std::num::{ParseIntError, ParseFloatError};
57
58    throws!(SingleIoError = Io(io::Error));
59
60    throws!(#[derive(PartialEq, Eq)] SingleParseIntError = Parse(ParseIntError));
61
62    throws!(MultipleError = Io(io::Error), ParseFloat(ParseFloatError), Single(SingleIoError));
63
64    throws! {
65        IoError = Io(io::Error);
66        ParseError = Parse(ParseIntError)
67    }
68
69    mod error {
70        use super::*;
71
72        throws!(pub PubError = Io(io::Error), Parse(ParseIntError));
73
74        throws!(pub(crate) PubCrateError = Io(io::Error), Parse(ParseIntError));
75
76        throws!(
77            #[derive(PartialEq, Eq, Clone)]
78            #[allow(missing_docs)]
79            pub(crate) AllFeaturesError = ParseInt(ParseIntError), ParseFloat(ParseFloatError)
80        );
81
82        throws! {
83            () PrivateIoError = Io(io::Error);
84            #[derive(Clone)]
85            (pub) PubParseError = Parse(ParseIntError)
86        }
87    }
88
89    #[test]
90    fn create_from_error() {
91        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
92        assert!(match error {
93            SingleIoError::Io(_) => true,
94        });
95
96        let error = "not int"
97            .parse::<i32>()
98            .map_err(SingleParseIntError::from)
99            .unwrap_err();
100        assert!(match error {
101            SingleParseIntError::Parse(_) => true,
102        });
103        assert_eq!(error, error);
104
105        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
106        assert!(match error {
107            MultipleError::Io(_) => true,
108            _ => false,
109        });
110
111        let error = SingleIoError::from(io::Error::from(io::ErrorKind::NotFound));
112        let error = From::from(error);
113        assert!(match error {
114            MultipleError::Single(_) => true,
115            _ => false,
116        });
117
118        let error = From::from("not float".parse::<f32>().unwrap_err());
119        assert!(match error {
120            MultipleError::ParseFloat(_) => true,
121            _ => false,
122        });
123
124        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
125        assert!(match error {
126            error::PubError::Io(_) => true,
127            _ => false,
128        });
129
130        let error = From::from("not int".parse::<i32>().unwrap_err());
131        assert!(match error {
132            error::PubCrateError::Parse(_) => true,
133            _ => false,
134        });
135
136        let error = From::from("not float".parse::<f32>().unwrap_err());
137        assert!(match error {
138            error::AllFeaturesError::ParseFloat(_) => true,
139            _ => false,
140        });
141        assert_eq!(error, error.clone());
142
143        let error = From::from(io::Error::from(io::ErrorKind::NotFound));
144        assert!(match error {
145            IoError::Io(_) => true,
146        });
147    }
148}