matching!() { /* proc-macro */ }
Expand description
Macro to ease argument pattern matching. This macro produces a closure expression suitable for passing to build::Each::call.
Takes inspiration from std::matches and works similarly, except that the value to match can be removed as a macro argument, since it is instead received as the closure argument.
Unimock uses tuples to represent multiple arguments. A single argument is not a tuple.
To avoid the extra set of parentheses for simple multi-argument matchers, there is
a special syntax that accepts several top-level patterns:
matching!("a", "b")
will expand to matching!(("a", "b"))
.
Example
fn one_str() {
fn args(_: impl Fn(&(&str)) -> bool) {}
args(matching!("a"));
}
fn three_strs() {
fn args(_: impl Fn(&(&str, &str, &str)) -> bool) {}
args(matching!("a", _, "c"));
args(matching!(("a", "b", "c") | ("d", "e", "f")));
args(matching!(("a", b, "c") if b.contains("foo")));
}
Auto-“coercions”
Since the input expression being matched is generated by the macro, you would
normally suffer from the following problem when matching some non-&str
function input:
let string = String::new();
match &string {
"foo" => true, // expected struct `String`, found `str`
_ => false,
}
To help ergonomics, the matching
macro recognizes certain literals used in the
patterns, and performs appropriate type conversion at the correct places:
struct Newtype(String);
fn exotic_strings() {
fn args(_: impl Fn(&(String, std::borrow::Cow<'static, str>, Newtype, i32)) -> bool) {}
args(matching!(("a", _, "c", _) | (_, "b", _, 42)));
}
// Newtype works by implementing the following:
impl std::convert::AsRef<str> for Newtype {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
Internally it works by calling macro_api::as_str_ref on inputs matched by a string literal.