1#![deny(missing_docs)]
15#![cfg_attr(not(test), no_std)]
16
17#[macro_export]
63macro_rules! assert_matches {
64 ( $e:expr , $($pat:pat)|+ ) => {
65 match $e {
66 $($pat)|+ => (),
67 ref e => panic!("assertion failed: `{:?}` does not match `{}`",
68 e, stringify!($($pat)|+))
69 }
70 };
71 ( $e:expr , $($pat:pat)|+ if $cond:expr ) => {
72 match $e {
73 $($pat)|+ if $cond => (),
74 ref e => panic!("assertion failed: `{:?}` does not match `{}`",
75 e, stringify!($($pat)|+ if $cond))
76 }
77 };
78 ( $e:expr , $($pat:pat)|+ => $arm:expr ) => {
79 match $e {
80 $($pat)|+ => $arm,
81 ref e => panic!("assertion failed: `{:?}` does not match `{}`",
82 e, stringify!($($pat)|+))
83 }
84 };
85 ( $e:expr , $($pat:pat)|+ if $cond:expr => $arm:expr ) => {
86 match $e {
87 $($pat)|+ if $cond => $arm,
88 ref e => panic!("assertion failed: `{:?}` does not match `{}`",
89 e, stringify!($($pat)|+ if $cond))
90 }
91 };
92 ( $e:expr , $($pat:pat)|+ , $($arg:tt)* ) => {
93 match $e {
94 $($pat)|+ => (),
95 ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
96 e, stringify!($($pat)|+), format_args!($($arg)*))
97 }
98 };
99 ( $e:expr , $($pat:pat)|+ if $cond:expr , $($arg:tt)* ) => {
100 match $e {
101 $($pat)|+ if $cond => (),
102 ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
103 e, stringify!($($pat)|+ if $cond), format_args!($($arg)*))
104 }
105 };
106 ( $e:expr , $($pat:pat)|+ => $arm:expr , $($arg:tt)* ) => {
107 match $e {
108 $($pat)|+ => $arm,
109 ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
110 e, stringify!($($pat)|+), format_args!($($arg)*))
111 }
112 };
113 ( $e:expr , $($pat:pat)|+ if $cond:expr => $arm:expr , $($arg:tt)* ) => {
114 match $e {
115 $($pat)|+ if $cond => $arm,
116 ref e => panic!("assertion failed: `{:?}` does not match `{}`: {}",
117 e, stringify!($($pat)|+ if $cond), format_args!($($arg)*))
118 }
119 };
120}
121
122#[macro_export(local_inner_macros)]
133macro_rules! debug_assert_matches {
134 ( $($tt:tt)* ) => { {
135 if _assert_matches_cfg!(debug_assertions) {
136 assert_matches!($($tt)*);
137 }
138 } }
139}
140
141#[doc(hidden)]
142#[macro_export]
143macro_rules! _assert_matches_cfg {
144 ( $($tt:tt)* ) => { cfg!($($tt)*) }
145}
146
147#[cfg(test)]
148mod test {
149 use std::panic::{catch_unwind, UnwindSafe};
150
151 #[derive(Debug)]
152 enum Foo {
153 A(i32),
154 B(&'static str),
155 C(&'static str),
156 }
157
158 #[test]
159 fn test_assert_succeed() {
160 let a = Foo::A(123);
161
162 assert_matches!(a, Foo::A(_));
163 assert_matches!(a, Foo::A(123));
164 assert_matches!(a, Foo::A(i) if i == 123);
165 assert_matches!(a, Foo::A(42) | Foo::A(123));
166
167 let b = Foo::B("foo");
168
169 assert_matches!(b, Foo::B(_));
170 assert_matches!(b, Foo::B("foo"));
171 assert_matches!(b, Foo::B(s) if s == "foo");
172 assert_matches!(b, Foo::B(s) => assert_eq!(s, "foo"));
173 assert_matches!(b, Foo::B(s) => { assert_eq!(s, "foo"); assert!(true) });
174 assert_matches!(b, Foo::B(s) if s == "foo" => assert_eq!(s, "foo"));
175 assert_matches!(b, Foo::B(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(true) });
176
177 let c = Foo::C("foo");
178
179 assert_matches!(c, Foo::B(_) | Foo::C(_));
180 assert_matches!(c, Foo::B("foo") | Foo::C("foo"));
181 assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo");
182 assert_matches!(c, Foo::B(s) | Foo::C(s) => assert_eq!(s, "foo"));
183 assert_matches!(c, Foo::B(s) | Foo::C(s) => { assert_eq!(s, "foo"); assert!(true) });
184 assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo" => assert_eq!(s, "foo"));
185 assert_matches!(c, Foo::B(s) | Foo::C(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(true) });
186 }
187
188 #[test]
189 #[should_panic]
190 fn test_assert_panic_0() {
191 let a = Foo::A(123);
192
193 assert_matches!(a, Foo::B(_));
194 }
195
196 #[test]
197 #[should_panic]
198 fn test_assert_panic_1() {
199 let b = Foo::B("foo");
200
201 assert_matches!(b, Foo::B("bar"));
202 }
203
204 #[test]
205 #[should_panic]
206 fn test_assert_panic_2() {
207 let b = Foo::B("foo");
208
209 assert_matches!(b, Foo::B(s) if s == "bar");
210 }
211
212 #[test]
213 #[should_panic]
214 fn test_assert_panic_3() {
215 let b = Foo::B("foo");
216
217 assert_matches!(b, Foo::B(s) => assert_eq!(s, "bar"));
218 }
219
220 #[test]
221 #[should_panic]
222 fn test_assert_panic_4() {
223 let b = Foo::B("foo");
224
225 assert_matches!(b, Foo::B(s) if s == "bar" => assert_eq!(s, "foo"));
226 }
227
228 #[test]
229 #[should_panic]
230 fn test_assert_panic_5() {
231 let b = Foo::B("foo");
232
233 assert_matches!(b, Foo::B(s) if s == "foo" => assert_eq!(s, "bar"));
234 }
235
236 #[test]
237 #[should_panic]
238 fn test_assert_panic_6() {
239 let b = Foo::B("foo");
240
241 assert_matches!(b, Foo::B(s) if s == "foo" => { assert_eq!(s, "foo"); assert!(false) });
242 }
243
244 #[test]
245 fn test_assert_no_move() {
246 let b = &mut Foo::A(0);
247 assert_matches!(*b, Foo::A(0));
248 }
249
250 #[test]
251 fn assert_with_message() {
252 let a = Foo::A(0);
253
254 assert_matches!(a, Foo::A(_), "o noes");
255 assert_matches!(a, Foo::A(n) if n == 0, "o noes");
256 assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes");
257 assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes");
258 assert_matches!(a, Foo::A(n) if n == 0 => assert_eq!(n, 0), "o noes");
259 assert_matches!(a, Foo::A(n) if n == 0 => { assert_eq!(n, 0); assert!(n < 1) }, "o noes");
260 assert_matches!(a, Foo::A(_), "o noes {:?}", a);
261 assert_matches!(a, Foo::A(n) if n == 0, "o noes {:?}", a);
262 assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes {:?}", a);
263 assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes {:?}", a);
264 assert_matches!(a, Foo::A(_), "o noes {value:?}", value=a);
265 assert_matches!(a, Foo::A(n) if n == 0, "o noes {value:?}", value=a);
266 assert_matches!(a, Foo::A(n) => assert_eq!(n, 0), "o noes {value:?}", value=a);
267 assert_matches!(a, Foo::A(n) => { assert_eq!(n, 0); assert!(n < 1) }, "o noes {value:?}", value=a);
268 assert_matches!(a, Foo::A(n) if n == 0 => assert_eq!(n, 0), "o noes {value:?}", value=a);
269 }
270
271 fn panic_message<F>(f: F) -> String
272 where F: FnOnce() + UnwindSafe {
273 let err = catch_unwind(f)
274 .expect_err("function did not panic");
275
276 *err.downcast::<String>()
277 .expect("function panicked with non-String value")
278 }
279
280 #[test]
281 fn test_panic_message() {
282 let a = Foo::A(1);
283
284 assert_eq!(panic_message(|| {
286 assert_matches!(a, Foo::B(_));
287 }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`"#);
288
289 assert_eq!(panic_message(|| {
291 assert_matches!(a, Foo::B(s) if s == "foo");
292 }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`"#);
293
294 assert_eq!(panic_message(|| {
296 assert_matches!(a, Foo::B(_) => {});
297 }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`"#);
298
299 assert_eq!(panic_message(|| {
301 assert_matches!(a, Foo::B(s) if s == "foo" => {});
302 }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`"#);
303
304 assert_eq!(panic_message(|| {
306 assert_matches!(a, Foo::B(_), "msg");
307 }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`: msg"#);
308
309 assert_eq!(panic_message(|| {
311 assert_matches!(a, Foo::B(s) if s == "foo", "msg");
312 }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`: msg"#);
313
314 assert_eq!(panic_message(|| {
316 assert_matches!(a, Foo::B(_) => {}, "msg");
317 }), r#"assertion failed: `A(1)` does not match `Foo::B(_)`: msg"#);
318
319 assert_eq!(panic_message(|| {
321 assert_matches!(a, Foo::B(s) if s == "foo" => {}, "msg");
322 }), r#"assertion failed: `A(1)` does not match `Foo::B(s) if s == "foo"`: msg"#);
323 }
324}