Provides an expression macro try_match
that matches a pattern on a given
expression and returns the bound variables in Ok(_)
if successful.
```rust use trymatch::trymatch;
enum Enum
// The right-hand side of =>
if successful
asserteq!(trymatch!(Var1(42), Var1(x) => x), Ok(42));
asserteq!(trymatch!(Var2::
// Err(input)
on failure
asserteq!(trymatch!(Var2::
// Supports if
guard
asserteq!(trymatch!(Var1(42), Var1(x) if x < 20 => x), Err(Var1(42)));
```
=>
and the part that comes after can be omitted (requires implicit_map
feature, which is enabled by default; you can disable it to skip the
compilation of the internal procedural macro):
``rust
//
()` if there are no bound variables
asserteq!(trymatch!(Var1(42), Var1(_)), Ok(()));
// The bound variable if there is exactly one bound variables asserteq!(trymatch!(Var1(42), Var1(x)), Ok(42)); asserteq!(trymatch!(Var1(42), Var1(x) if x < 20), Err(Var1(42)));
// An anonymous struct if there are multiple bound variables let vars = trymatch!(Var1((12, 34)), Var1((a, b))).unwrap(); asserteq!((vars.a, vars.b), (12, 34)); ```
It produces a tuple if you name the bound variables like _0
, _1
, _2
,
...:
```rust let (a, b) = trymatch!(Var1((12, 34)), Var1((0, 1))).unwrap(); asserteq!((a, b), (12, 34));
trymatch!(Var1((12, 34)), Var1((0, 1)) if _0 == _1).unwraperr(); ```
It's an error to specify non-contiguous binding indices:
rust
let _ = try_match!(Var1((12, 34)), Var1((_0, _2)));
rust
let _ = try_match!(Var1((12, 34)), Var1((_0, _9223372036854775808)));
When using implicit mapping, bind variables defined inside macros are
not recognized because at the point of try_match
's macro expansion,
inner macros are not expended yet.
This macro moves a value out of the place represented by the input expression to return it on failure. Make sure to pass a reference if this is not desired.
rust
let array = [Some(UncopyValue), None];
// ERROR: Can't move out of `array[0]`
let _: &UncopyValue = try_match!(array[0], Some(ref x)).unwrap();
rust
let _: &UncopyValue = try_match!(&array[0], Some(x)).unwrap();
Iterator::filter_map
rust
let array = [Var1(42), Var2, Var1(10)];
let filtered: Vec<_> = array
.iter()
.filter_map(|x| try_match!(x, &Var1(_0) if _0 > 20).ok())
.collect();
assert_eq!(filtered, [42]);
Iterator::map
+ Fallible Iterator::collect
```rust
let array = [Var1(42), Var2, Var1(10)];
let filtered: Result
// Var2
is the first value that doesn't match
assert_eq!(filtered, Err(&Var2));
```
```rust
impl
fn is_var2(&self) -> bool {
matches!(self, Var2)
}
}
let enums = [Var1(42), Var2]; asserteq!(enums[0].var1(), Some(&42)); asserteq!(enums[1].var1(), None);
assert!(!enums[0].isvar2()); assert!(enums[1].isvar2()); ```
```rust fn thisfnexpectsvar1(foo: &Enum<[u8; 4]>) { let (i0, i1) = trymatch!(foo, &Var1([_0, _, _, _1])).unwrap();
// Once RFC 1303 is stabilized, you can do instead:
// let &Var1([i0, _, _, i1]) = foo else { panic!("{:?}", foo) };
assert_eq!((i0, i1), (42, 45));
}
thisfnexpects_var1(&Var1([42, 43, 44, 45])); ```
[matcher::matches!
][] (now incorporated into the standard library as
[core::matches!
][]) is similar but only returns bool
indicating whether
matching was successful or not.
rust
if_rust_version! { >= 1.42 {
let success1 = matches!(Some(42), Some(_));
let success2 = try_match!(Some(42), Some(_)).is_ok();
assert_eq!(success1, success2);
} }
[bind_match::bind_match!
][] and [extract::extract!
][] use the same
syntax (except for implicit mapping) but return Some(expr)
on success
instead.
License: MIT/Apache-2.0