diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-10-23 22:19:11 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-23 22:19:11 +0200 |
| commit | a1514b475854e858a3de95b3806d5795e0d6d72e (patch) | |
| tree | e7478f199d47d3d1b8252b2acdafb553f8e4d6c3 | |
| parent | 7c043e284a9a3e71ee2e5d34be8e40abf1daa49e (diff) | |
| parent | e76a1846153209b15dfbf697a33c25214bb753b3 (diff) | |
| download | rust-a1514b475854e858a3de95b3806d5795e0d6d72e.tar.gz rust-a1514b475854e858a3de95b3806d5795e0d6d72e.zip | |
Rollup merge of #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: https://github.com/rust-lang/rust/pull/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>
| -rw-r--r-- | src/libcore/macros.rs | 27 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 2 |
2 files changed, 29 insertions, 0 deletions
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 1320e63df06..35558e3abcd 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -238,6 +238,33 @@ macro_rules! debug_assert_ne { ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) } +/// Returns whether the given expression matches any of the given patterns. +/// +/// Like in a `match` expression, the pattern can be optionally followed by `if` +/// and a guard expression that has access to names bound by the pattern. +/// +/// # Examples +/// +/// ``` +/// #![feature(matches_macro)] +/// +/// let foo = 'f'; +/// assert!(matches!(foo, 'A'..='Z' | 'a'..='z')); +/// +/// let bar = Some(4); +/// assert!(matches!(bar, Some(x) if x > 2)); +/// ``` +#[macro_export] +#[unstable(feature = "matches_macro", issue = "65721")] +macro_rules! matches { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => { + match $expression { + $( $pattern )|+ $( if $guard )? => true, + _ => false + } + } +} + /// Unwraps a result or propagates its error. /// /// The `?` operator was added to replace `try!` and should be used instead. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 93d3e4ea3df..d0cb0104f6c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -276,6 +276,7 @@ #![feature(linkage)] #![feature(log_syntax)] #![feature(manually_drop_take)] +#![feature(matches_macro)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(needs_panic_runtime)] @@ -527,6 +528,7 @@ pub use core::{ writeln, // Unstable todo, + matches, }; // Re-export built-in macros defined through libcore. |
