macro_rules! assert_matches {
($got:expr, $want:pat $(,)?) => { ... };
}Expand description
Checks whether $got matches $want.
$got is an arbitrary expression, it is evaluated unchanged. Must implement std::fmt::Debug.
$want is an expression resembling a pattern syntax.
§Motivation
The primary goal of this macro over a more standard assert_matches! syntax is to allow
flexible checks of nested fields for types that don’t implement PartialEq, e.g. various
Error types.
Example:
#[derive(Debug)]
enum Error {
A,
B(String),
C(Box<Error>),
}
fn my_func() -> Result<(), Error> {
Err(Error::C(Box::new(Error::B("failed".to_owned()))))
}
assert_matches!(my_func(), Err(Error::C(deref!(Error::B("failed")))));As of Rust 1.95 this is not possible to express in a single check without unstable deref_patterns. The next best thing is something along these lines:
#[derive(Debug)]
enum Error {
A,
B(String),
C(Box<Error>),
}
fn my_func() -> Result<(), Error> {
Err(Error::C(Box::new(Error::B("failed".to_owned()))))
}
let r = my_func();
let Err(Error::C(err)) = my_func() else {
panic!("Expected Error::C, got {r:?}");
};
let Error::B(msg) = *err else {
panic!("Expected Error::B, got {err:?}");
};
assert_eq!(msg, "failed");In author’s opinion the alternative is less expressive.
§$want syntax
$want generally follows Rust pattern
syntax, except the ability to bind data. Every field must be either checked against a matcher
expression, explicitly ignored via matching to _, or omitted entirely.
§Binding issues
Due to how procedural macros are implemented it is impossible to know whether a specific path
(e.g. Err, std::option::Option::Some, or even x) is a variable name or a type name. This
macro will always assume a type name. This can lead to surprising compilation errors if a
variable is provided instead.
For example the following may result in a compilation error because the value is unused.
#[derive(Debug)]
struct Type(&'static str);
#[deny(unused)]
fn main() {
let x = Type("hello");
assert_matches!(x, Type(value));
}§deref! matcher
Allows matching on inner types implementing Deref.
Inspired by deref_patterns.
#[derive(Debug)]
struct Inner(String);
#[derive(Debug)]
struct Outer {
inner: Box<Inner>,
}
let x = Outer {
inner: Box::new(Inner("hello".into())),
};
assert_matches!(x, Outer {
inner: deref!(Inner("hello")),
});§eq! matcher
Allows matching on variables where the syntax would otherwise be ambiguous.
#[derive(Debug)]
struct Type(i32);
let want = 10;
let got = Type(10);
assert_matches!(got, Type(eq!(want)));§Examples
§Literals
let x = 10;
assert_matches!(x, 10);§Boxed types
#[derive(Debug)]
enum Enum {
A,
B,
}
// Box is a Deref type, so it has to be unwrapped first.
#[derive(Debug)]
struct Struct(Box<Enum>);
let thing = Struct(Box::new(Enum::A));
assert_matches!(thing, Struct(deref!(Enum::A)));§Partial struct matching
#[derive(Debug)]
struct Type {
a: i32,
b: i32,
}
let thing = Type { a: 1, b: 2 };
assert_matches!(thing, Type { a: 1, .. });