diff options
| author | Simon Sapin <simon.sapin@exyr.org> | 2019-10-16 22:40:37 +0200 |
|---|---|---|
| committer | Simon Sapin <simon.sapin@exyr.org> | 2019-10-23 15:35:34 +0200 |
| commit | f69293ae808dea61a2dacee6057ca5bb0d7dc817 (patch) | |
| tree | 1a6c703a7cb180933e1ca12c6d2ee5de8484bc00 /src/libcore | |
| parent | f466f52c1bf8f2e4454e31c683a88625ad4b4033 (diff) | |
| download | rust-f69293ae808dea61a2dacee6057ca5bb0d7dc817.tar.gz rust-f69293ae808dea61a2dacee6057ca5bb0d7dc817.zip | |
Add `core::macros::matches!( $expr, $pat ) -> bool`
# 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.) Back then, the main concern was that this macro may not be quite universally-enough useful to belong in the prelude. # API Therefore, this PR adds the macro such that using it requires one of: ``` use core::macros::matches; use std::macros::matches; ``` Like arms of a `match` expression, the macro supports multiple patterns separated by `|` and optionally followed by `if` and a guard expression: ``` let foo = 'f'; assert!(matches!(foo, 'A'..='Z' | 'a'..='z')); let bar = Some(4); assert!(matches!(bar, Some(x) if x > 2)); ``` # 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.
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/Cargo.toml | 3 | ||||
| -rw-r--r-- | src/libcore/lib.rs | 12 | ||||
| -rw-r--r-- | src/libcore/prelude/v1.rs | 2 |
3 files changed, 15 insertions, 2 deletions
diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index ac07ffb14fe..65f7a42824b 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -20,6 +20,9 @@ path = "../libcore/tests/lib.rs" name = "corebenches" path = "../libcore/benches/lib.rs" +[dependencies] +matches_macro = { path = "../libmatches_macro" } + [dev-dependencies] rand = "0.7" diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 30e8dddff85..a5af32250e6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,6 +85,7 @@ #![feature(iter_once_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] +#![feature(matches_macro)] #![feature(never_type)] #![feature(nll)] #![feature(exhaustive_patterns)] @@ -134,7 +135,16 @@ use prelude::v1::*; #[macro_use] -mod macros; +#[path = "macros.rs"] +mod prelude_macros; + +/// Macros that are not in the prelude and need to be imported explicitly +#[unstable(feature = "matches_macro", issue = "0")] +pub mod macros { + #[unstable(feature = "matches_macro", issue = "0")] + #[doc(inline)] + pub use matches_macro::matches; +} #[macro_use] mod internal_macros; diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 7cc279a9ef2..285f8d6e077 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -82,7 +82,7 @@ pub use crate::{ #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] #[doc(no_inline)] -pub use crate::macros::builtin::{ +pub use crate::prelude_macros::builtin::{ RustcDecodable, RustcEncodable, bench, |
