# try_match [docs.rs](https://docs.rs/try_match/) Fallible pattern matching with a function-like syntax ## Basic Usage ### Macros ```rust use try_match::{try_match, match_ok, unwrap_match}; #[derive(Copy, Clone, Debug, PartialEq)] enum Enum { Var0, Var1(i32), Var2(i32, i32) } use Enum::*; // `try_match!` returns `Result`: `Ok(bindings)` on success or // `Err(input_value)` otherwise assert_eq!(try_match!(Var1(42), Var1(x)), Ok(42)); assert_eq!(try_match!(Var0, Var1(x)), Err(Var0)); // `match_ok!` returns `Option` assert_eq!(match_ok!(Var1(42), Var1(x)), Some(42)); assert_eq!(match_ok!(Var0, Var1(x)), None); // `match_or_default!` returns a default value on failure assert_eq!(match_or_default!(Var1(42), Var1(x)), 42); assert_eq!(match_or_default!(Var0, Var1(x)), 0); // `unwrap_match!` panics on failure: assert_eq!(unwrap_match!(Var1(42), Var1(x)), 42); /* unwrap_match!(Var0, Var1(x)); */ // this will panic ``` Match guards (`if `) are supported: ```rust assert_eq!(match_ok!(Var1(42), Var1(x)), Some(42)); assert_eq!(match_ok!(Var1(42), Var1(x) if x < 20), None); ``` ### Bindings ```rust // Returns `()` (wrapped by `Ok(_)`) if there are no bound variables assert_eq!(unwrap_match!(Var1(42), Var1(_)), ()); // ... the bound value if there is exactly one binding assert_eq!(unwrap_match!(Var1(42), Var1(x)), 42); // ... an anonymous struct if there are multiple bindings let vars = unwrap_match!(Var2(12, 34), Var2(a, b)); assert_eq!((vars.a, vars.b), (12, 34)); // ... or a tuple if the binding names are numeric let (a, b) = unwrap_match!(Var2(12, 34), Var2(_0, _1)); assert_eq!((a, b), (12, 34)); // An optional `=>` clause specifies an explicit mapping assert_eq!(unwrap_match!(Var1(42), Var1(x) => x + 1), 43); assert_eq!(unwrap_match!(Var0, Var0 => "yay"), "yay"); ``` ### Partial Application ```rust // Omit the scrutinee expression to produce a closure let _: Option = match_ok!(Var1(42), Var1(x)); let _: fn(Enum) -> Option = match_ok!( , Var1(x)); ``` ## Applications ### `Iterator::filter_map` ```rust let array = [Var1(42), Var0, Var1(10)]; let filtered: Vec<_> = array .iter() .filter_map(match_ok!(, &Var1(_0) if _0 > 20)) .collect(); assert_eq!(filtered, [42]); ``` ### `Iterator::map` + Fallible `Iterator::collect` ```rust let array = [Var1(42), Var0, Var1(10)]; let filtered: Result, _> = array .iter() .map(try_match!(, &Var1(_0) if _0 > 20)) .collect(); // `Var0` is the first value that doesn't match assert_eq!(filtered, Err(&Var0)); ``` ### Extract Variants ```rust impl Enum { fn var1(&self) -> Option<&i32> { match_ok!(self, Var1(_0)) } fn is_var2(&self) -> bool { matches!(self, Var0) } } let enums = [Var1(42), Var0]; assert_eq!(enums[0].var1(), Some(&42)); assert_eq!(enums[1].var1(), None); assert!(!enums[0].is_var2()); assert!(enums[1].is_var2()); ``` ### Expect Certain Variants ```rust fn this_fn_expects_var2(foo: &Enum) { let i = unwrap_match!(foo, &Var2(42, _0)); // Alternatively, you could use let-else (stabilized in Rust 1.65.0): // let &Var2(42, i) = foo else { panic!("{foo:?}") }; assert_eq!(i, 84); } this_fn_expects_var2(&Var2(42, 84)); ``` ## Related Works [`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 let success1 = matches!(Some(42), Some(_)); let success2 = match_ok!(Some(42), Some(_)).is_some(); assert_eq!(success1, success2); ``` [`bind_match::bind_match!`][] and [`extract::extract!`][] behave in the same way as `match_ok!` except for the lack of implicit mapping and partial application. [`variant::get_variant!`][] from the `extract_variant` crate offers a similar functionality to `match_ok!`. It supports implicit mapping but uses different rules to handle multiple bindings. [`core::matches!`]: https://doc.rust-lang.org/1.56.0/core/macro.matches.html [`matcher::matches!`]: https://crates.io/crates/matches [`bind_match::bind_match!`]: https://crates.io/crates/bind_match [`extract::extract!`]: https://crates.io/crates/extract_macro [`variant::get_variant!`]: https://crates.io/crates/extract-variant/1.0.0 ## License MIT/Apache-2.0