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
#![no_std]

/// Matches an expression to any of the patterns and executes the same expression arm for any match.
///
/// This macro allows you to use the same expression arm for different types
/// by creating the same match arm for each of the patterns separated by `|`.
/// A standard match statement only allows such patterns for the same type:
///
/// ```compile_fail
/// let result: Result<i64, i32> = Err(42);
/// let int: i64 = match result { Ok(i) | Err(i) => i.into() }; // does not compile!
/// ```
///
/// ```
/// # use match_any::match_any;
/// let result: Result<i64, i32> = Err(42);
/// let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); // compiles just fine
/// assert_eq!(int, 42);
/// ```
///
/// # Examples
///
/// ```
/// use match_any::match_any;
///
/// enum Id { U8(u8), I16(i16), I32(i32) }
/// use Id::*;
///
/// let id = Id::I16(-2);
/// let id: i32 = match_any!(id, U8(x) | I16(x) | I32(x) => x.into());
/// assert_eq!(id, -2);
/// ```
///
/// With multiple match arms:
///
/// ```
/// use core::convert::TryFrom;
/// use match_any::match_any;
///
/// enum Id { U8(u8), I16(i16), I32(i32), U64(u64) }
/// use Id::*;
///
/// let id = Id::I32(-3);
/// let id: i32 = match_any!(id,
///     U8(a) | I16(a) | I32(a) => a.into(),
///     U64(b) => i32::try_from(b).unwrap_or(0)
/// );
/// assert_eq!(id, -3);
/// ```
///
/// # Macro Expansion
///
/// ```
/// # use match_any::match_any;
/// let result: Result<i32, i32> = Err(42);
/// match_any!(result, Ok(i) | Err(i) => Some(i));
/// ```
/// expands to
/// ```
/// let result: Result<i32, i32> = Err(42);
/// match result { Ok(i) => Some(i), Err(i) => Some(i) };
/// ```
///
/// # Enum Dispatch
///
/// Similarly to the [enum_dispatch crate](https://crates.io/crates/enum_dispatch),
/// this macro can be used to implement "enum dispatch" as an alternative to dynamic dispatch.
/// The major difference between the enum_dispatch crate and this macro is,
/// that enum_dispatch provides a _procedural_ macro, while this is a _declarative_ macro.
/// This allows enum_dispatch to reduce the boilerplate code a lot more than match_any.
/// However IDE support should be a bit better with match_any.
///
/// ## Enum Dispatch Example
///
/// ```
/// use match_any::match_any;
///
/// trait IntId {
///     fn int_id(&self) -> i32;
/// }
///
/// impl IntId for u64 {
///     fn int_id(&self) -> i32 { 64 }
/// }
///
/// impl IntId for u32 {
///     fn int_id(&self) -> i32 { 32 }
/// }
///
/// enum IntIdKind { U64(u64), U32(u32) }
///
/// impl IntId for IntIdKind {
///     fn int_id(&self) -> i32 {
///         use IntIdKind::*;
///         match_any!(self, U64(i) | U32(i) => i.int_id())
///     }
/// }
///
/// let int_id_kind = IntIdKind::U32(0);
/// assert_eq!(int_id_kind.int_id(), 32); // enum dispatch
/// let int_id_box: Box<dyn IntId> = Box::new(0_u32);
/// assert_eq!(int_id_box.int_id(), 32); // dynamic dispatch
/// ```
#[macro_export]
macro_rules! match_any {
    ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
        match $expr {
            $(
                $( $pat => $expr_arm, )+
            )+
        }
    };
}