matching!() { /* proc-macro */ }
Expand description
Macro to ease call pattern matching for function arguments. 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.