[go: up one dir, main page]

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}