matches/lib.rs
1#![no_std]
2//! A macro to evaluate, as a boolean, whether an expression matches a pattern.
3//!
4//! For users who build using only Rust 1.42 and newer, consider using [`std::matches`], which
5//! is included in the [standard library prelude] and thus is automatically in scope.
6//!
7//! [`std::matches`]: core::matches
8//! [standard library prelude]: https://doc.rust-lang.org/stable/reference/names/preludes.html
9//!
10//! # Examples
11//!
12//! ```
13//! #[macro_use]
14//! extern crate matches;
15//!
16//! #[derive(Debug)]
17//! pub enum Foo<T> {
18//! A,
19//! B(T),
20//! }
21//!
22//! impl<T> Foo<T> {
23//! pub fn is_b(&self) -> bool {
24//! matches!(*self, Foo::B(_))
25//! }
26//! }
27//!
28//! impl<T: core::fmt::Debug> Foo<T> {
29//! pub fn assert_is_b(&self) {
30//! assert_matches!(&self, Foo::B(_));
31//! }
32//! }
33//! # fn main() { }
34//! ```
35
36/// Check if an expression matches a refutable pattern.
37///
38/// Syntax: `matches!(` *expression* `,` *pattern* `)`
39///
40/// Return a boolean, true if the expression matches the pattern, false otherwise.
41///
42/// # Examples
43///
44/// ```
45/// #[macro_use]
46/// extern crate matches;
47///
48/// pub enum Foo<T> {
49/// A,
50/// B(T),
51/// }
52///
53/// impl<T> Foo<T> {
54/// pub fn is_a(&self) -> bool {
55/// matches!(*self, Foo::A)
56/// }
57///
58/// pub fn is_b(&self) -> bool {
59/// matches!(*self, Foo::B(_))
60/// }
61/// }
62///
63/// # fn main() { }
64/// ```
65#[macro_export]
66macro_rules! matches {
67 ($expression:expr, $($pattern:tt)+) => {
68 match $expression {
69 $($pattern)+ => true,
70 _ => false
71 }
72 }
73}
74
75/// Assert that an expression matches a refutable pattern.
76///
77/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
78///
79/// Panic with a message that shows the expression if it does not match the
80/// pattern.
81///
82/// # Examples
83///
84/// ```
85/// #[macro_use]
86/// extern crate matches;
87///
88/// fn main() {
89/// let data = [1, 2, 3];
90/// assert_matches!(data.get(1), Some(_));
91/// }
92/// ```
93#[macro_export]
94macro_rules! assert_matches {
95 ($expression:expr, $($pattern:tt)+) => {
96 match $expression {
97 $($pattern)+ => (),
98 ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
99 }
100 }
101}
102
103/// Assert that an expression matches a refutable pattern using debug assertions.
104///
105/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
106///
107/// If debug assertions are enabled, panic with a message that shows the
108/// expression if it does not match the pattern.
109///
110/// When debug assertions are not enabled, this macro does nothing.
111///
112/// # Examples
113///
114/// ```
115/// #[macro_use]
116/// extern crate matches;
117///
118/// fn main() {
119/// let data = [1, 2, 3];
120/// debug_assert_matches!(data.get(1), Some(_));
121/// }
122/// ```
123#[macro_export]
124macro_rules! debug_assert_matches {
125 ($expression:expr, $($pattern:tt)+) => {
126 if cfg!(debug_assertions) {
127 match $expression {
128 $($pattern)+ => (),
129 ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
130 }
131 }
132 }
133}
134
135#[test]
136fn matches_works() {
137 let foo = Some("-12");
138 assert!(matches!(foo, Some(bar) if
139 matches!(bar.as_bytes()[0], b'+' | b'-') &&
140 matches!(bar.as_bytes()[1], b'0'...b'9')
141 ));
142}
143
144#[test]
145fn assert_matches_works() {
146 let foo = Some("-12");
147 assert_matches!(foo, Some(bar) if
148 matches!(bar.as_bytes()[0], b'+' | b'-') &&
149 matches!(bar.as_bytes()[1], b'0'...b'9')
150 );
151}
152
153#[test]
154#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
155fn assert_matches_panics() {
156 let foo = Some("-AB");
157 assert_matches!(foo, Some(bar) if
158 matches!(bar.as_bytes()[0], b'+' | b'-') &&
159 matches!(bar.as_bytes()[1], b'0'...b'9')
160 );
161}