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}