1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//! Provides an expression macro `try_match` that matches a pattern on a given
//! expression and returns the bound variables in `Ok(_)` if successful.
//!
//! # Basic Usage
//!
//! ## Explicit Mapping
//!
//! ```
//! use try_match::try_match;
//!
//! #[derive(Copy, Clone, Debug, PartialEq)]
//! enum Enum<T> { Var1(T), Var2 }
//! use Enum::{Var1, Var2};
//!
//! // The right-hand side of `=>` if successful
//! assert_eq!(try_match!(Var1(42),    Var1(x) => x),     Ok(42));
//! assert_eq!(try_match!(Var2::<u32>, Var2    => "yay"), Ok("yay"));
//!
//! // `Err(input)` on failure
//! assert_eq!(try_match!(Var2::<u32>, Var1(x) => x),     Err(Var2));
//! assert_eq!(try_match!(Var1(42),    Var2    => "yay"), Err(Var1(42)));
//!
//! // Supports `if` guard
//! assert_eq!(try_match!(Var1(42), Var1(x) if x < 20 => x), Err(Var1(42)));
//! ```
//!
//! ## Implicit Mapping
//!
//! `=>` 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):
//!
//! ```
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! // `()` if there are no bound variables
//! assert_eq!(try_match!(Var1(42), Var1(_)), Ok(()));
//!
//! // The bound variable if there is exactly one bound variables
//! assert_eq!(try_match!(Var1(42), Var1(x)), Ok(42));
//! assert_eq!(try_match!(Var1(42), Var1(x) if x < 20), Err(Var1(42)));
//!
//! // An anonymous struct if there are multiple bound variables
//! let vars = try_match!(Var1((12, 34)), Var1((a, b))).unwrap();
//! assert_eq!((vars.a, vars.b), (12, 34));
//! ```
//!
//! It produces a tuple if you name the bound variables like `_0`, `_1`, `_2`,
//! ...:
//!
//! ```
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! let (a, b) = try_match!(Var1((12, 34)), Var1((_0, _1))).unwrap();
//! assert_eq!((a, b), (12, 34));
//!
//! try_match!(Var1((12, 34)), Var1((_0, _1)) if _0 == _1).unwrap_err();
//! ```
//!
//! It's an error to specify non-contiguous binding indices:
//!
//! ```compile_fail
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! let _ = try_match!(Var1((12, 34)), Var1((_0, _2)));
//! ```
//!
//! ```compile_fail
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! let _ = try_match!(Var1((12, 34)), Var1((_0, _9223372036854775808)));
//! ```
//!
//! # Quirks
//!
//! 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.
//!
//! ```compile_fail
//! # use try_match::try_match;
//! #[derive(Debug)] struct UncopyValue;
//! let array = [Some(UncopyValue), None];
//! // ERROR: Can't move out of `array[0]`
//! let _: &UncopyValue = try_match!(array[0], Some(ref x)).unwrap();
//! ```
//!
//! ```
//! # use try_match::try_match;
//! # #[derive(Debug)] struct UncopyValue;
//! # let array = [Some(UncopyValue), None];
//! let _: &UncopyValue = try_match!(&array[0], Some(x)).unwrap();
//! ```
//!
//! # Applications
//!
//! ## `Iterator::filter_map`
//!
//! ```rust
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! 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
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! let array = [Var1(42), Var2, Var1(10)];
//! let filtered: Result<Vec<_>, _> = array
//!     .iter()
//!     .map(|x| try_match!(x, &Var1(_0) if _0 > 20))
//!     .collect();
//!
//! // `Var2` is the first value that doesn't match
//! assert_eq!(filtered, Err(&Var2));
//! ```
//!
//! ## Extract Variants
//!
//! ```rust
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! impl<T> Enum<T> {
//!     fn var1(&self) -> Option<&T> {
//!         try_match!(self, Var1(_0)).ok()
//!     }
//!
//!     fn is_var2(&self) -> bool {
//!         matches!(self, Var2)
//!     }
//! }
//!
//! let enums = [Var1(42), Var2];
//! 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
//! # use try_match::try_match;
//! # #[derive(Debug, PartialEq)] enum Enum<T> { Var1(T), Var2 }
//! # use Enum::{Var1, Var2};
//! fn this_fn_expects_var1(foo: &Enum<[u8; 4]>) {
//!     let (i0, i1) = try_match!(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));
//! }
//!
//! this_fn_expects_var1(&Var1([42, 43, 44, 45]));
//! ```
//!
//! # Related Work
//!
//! [`matcher::matches!`][] (now incorporated into the standard library as
//! [`core::matches!`][]) is similar but only returns `bool` indicating whether
//! matching was successful or not.
//!
//! ```
//! # use try_match::try_match;
//! 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.
//!
//! [`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
//!
#![no_std]
#![forbid(unsafe_code)]

/// Try to match `$in` against a given pattern `$p`. Produces `Ok($out)` if
/// successful; `Err($in)` otherwise.
///
/// `=> $out` can be left out, in which case it's implied based on the number of
/// bound variables in `$p`:
///
/// - If there are no bound variables, it is implied to be `()`.
/// - If there is exactly one bound variable `var`, it is implied to be `var`.
/// - If there are multiple bound variables `var1, var2, ...`, it is implied to
///   be `AnonymousType { var1, var2 }`.
///
/// `AnonymousType` implements `Clone`, `Copy`, and `Debug`.
///
/// See [the crate-level documentation](index.html) for examples.
#[macro_export]
macro_rules! try_match {
    ($in:expr, $(|)? $($p:pat)|+ $(if $guard:expr)? => $out:expr) => {
        match $in {
            $($p)|+ $(if $guard)? => ::core::result::Result::Ok($out),
            in_value => ::core::result::Result::Err(in_value),
        }
    };

    ($in:expr, $(|)? $($p:pat)|+ $(if $guard:expr)?) => {
        $crate::implicit_try_match!($in, $($p)|+ $(if $guard)?)
    };
}

#[cfg(feature = "implicit_map")]
#[macro_export]
#[doc(hidden)]
macro_rules! implicit_try_match {
    ($in:expr, $($p:tt)*) => {
        $crate::implicit_try_match_inner!($in, $($p)*)
    };
}

#[cfg(not(feature = "implicit_map"))]
#[macro_export]
#[doc(hidden)]
macro_rules! implicit_try_match {
    ($($_:tt)*) => {
        compile_error!(
            "can't use the implicit mapping form of `try_match!` because \
             the feature `implicit_map` is disabled"
        )
    };
}

/// Pattern: `$p:pat`
///
/// The produced expression evaluates to `Ok(_)` using bound variables on a
/// successful match on the given value.
///
/// - If there are no bound variables, it generates `()`.
/// - If there is exactly one bound variables `var`, it generates `var`.
/// - If there are multiple bound variables `var1, var2, ...`, it generates
///   `SomeType { var1, var2 }`.
///
/// Otherwise, the expression evaluates to `Err($in)`.
#[cfg(feature = "implicit_map")]
#[doc(hidden)]
pub use try_match_inner::implicit_try_match_inner;