• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
66 macro_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]
94 macro_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]
124 macro_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]
matches_works()136 fn 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]
assert_matches_works()145 fn 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 ")]
assert_matches_panics()155 fn 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 }
162