Skip to content

Commit a1514b4

Browse files
authored
Rollup merge of rust-lang#65479 - SimonSapin:matches, r=alexcrichton
Add the `matches!( $expr, $pat ) -> bool` macro # Motivation This macro is: * General-purpose (not domain-specific) * Simple (the implementation is short) * Very popular [on crates.io](https://crates.io/crates/matches) (currently 37th in all-time downloads) * The two previous points combined make it number one in [left-pad index](https://twitter.com/bascule/status/1184523027888988160) score As such, I feel it is a good candidate for inclusion in the standard library. In fact I already felt that way five years ago: rust-lang#14685 (Although the proof of popularity was not as strong at the time.) # API <details> <del> Back then, the main concern was that this macro may not be quite universally-enough useful to belong in the prelude. Therefore, this PR adds the macro such that using it requires one of: ```rust use core::macros::matches; use std::macros::matches; ``` </del> </details> Like arms of a `match` expression, the macro supports multiple patterns separated by `|` and optionally followed by `if` and a guard expression: ```rust let foo = 'f'; assert!(matches!(foo, 'A'..='Z' | 'a'..='z')); let bar = Some(4); assert!(matches!(bar, Some(x) if x > 2)); ``` <details> <del> # Implementation constraints A combination of reasons make it tricky for a standard library macro not to be in the prelude. Currently, all public `macro_rules` macros in the standard library macros end up “in the prelude” of every crate not through `use std::prelude::v1::*;` like for other kinds of items, but through `#[macro_use]` on `extern crate std;`. (Both are injected by `src/libsyntax_ext/standard_library_imports.rs`.) `#[macro_use]` seems to import every macro that is available at the top-level of a crate, even if through a `pub use` re-export. Therefore, for `matches!` not to be in the prelude, we need it to be inside of a module rather than at the root of `core` or `std`. However, the only way to make a `macro_rules` macro public outside of the crate where it is defined appears to be `#[macro_export]`. This exports the macro at the root of the crate regardless of which module defines it. See [macro scoping](https://doc.rust-lang.org/reference/macros-by-example.html#scoping-exporting-and-importing) in the reference. Therefore, the macro needs to be defined in a crate that is not `core` or `std`. # Implementation This PR adds a new `matches_macro` crate as a private implementation detail of the standard library. This crate is `#![no_core]` so that libcore can depend on it. It contains a `macro_rules` definition with `#[macro_export]`. libcore and libstd each have a new public `macros` module that contains a `pub use` re-export of the macro. Both the module and the macro are unstable, for now. The existing private `macros` modules are renamed `prelude_macros`, though their respective source remains in `macros.rs` files. </del> </details>
2 parents 7c043e2 + e76a184 commit a1514b4

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

src/libcore/macros.rs

+27
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,33 @@ macro_rules! debug_assert_ne {
238238
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
239239
}
240240

241+
/// Returns whether the given expression matches any of the given patterns.
242+
///
243+
/// Like in a `match` expression, the pattern can be optionally followed by `if`
244+
/// and a guard expression that has access to names bound by the pattern.
245+
///
246+
/// # Examples
247+
///
248+
/// ```
249+
/// #![feature(matches_macro)]
250+
///
251+
/// let foo = 'f';
252+
/// assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));
253+
///
254+
/// let bar = Some(4);
255+
/// assert!(matches!(bar, Some(x) if x > 2));
256+
/// ```
257+
#[macro_export]
258+
#[unstable(feature = "matches_macro", issue = "65721")]
259+
macro_rules! matches {
260+
($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => {
261+
match $expression {
262+
$( $pattern )|+ $( if $guard )? => true,
263+
_ => false
264+
}
265+
}
266+
}
267+
241268
/// Unwraps a result or propagates its error.
242269
///
243270
/// The `?` operator was added to replace `try!` and should be used instead.

src/libstd/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@
276276
#![feature(linkage)]
277277
#![feature(log_syntax)]
278278
#![feature(manually_drop_take)]
279+
#![feature(matches_macro)]
279280
#![feature(maybe_uninit_ref)]
280281
#![feature(maybe_uninit_slice)]
281282
#![feature(needs_panic_runtime)]
@@ -527,6 +528,7 @@ pub use core::{
527528
writeln,
528529
// Unstable
529530
todo,
531+
matches,
530532
};
531533

532534
// Re-export built-in macros defined through libcore.

0 commit comments

Comments
 (0)