typewit

Macro polymatch

Source
macro_rules! polymatch {
    ($matching:expr; $($match_arms:tt)*) => { ... };
    ($($tt:tt)*) => { ... };
}
Expand description

Match which expands top-level | patterns to multiple match arms.

examples below

§Clarification

“top-level | patterns” means that the | is not inside some other pattern.
E.g.: the pattern in Foo(x) | Bar(x) => is a top-level | pattern.
E.g.: the pattern in (Foo(x) | Bar(x)) => is not a top-level | pattern, because the | is inside parentheses.

§Syntax

This uses a macro_rules!-like syntax for the parameters of this macro

$matched_expression:expr;
    $( $(|)? $($or_pattern:pat_param)|+ $(if $match_guard:expr)? => $arm_expr:expr ),*
    $(,)? 

example demonstrating all of this syntax

§Examples

§Basic

assert_eq!(debugify(Ok(3)), "3");
assert_eq!(debugify(Err("hello")), r#""hello""#);
 
fn debugify(res: Result<u32, &'static str>) -> String {
    typewit::polymatch! {res; 
        Ok(x) | Err(x) => format!("{:?}", x)
    }
}

The above invocation of polymatch expands to:

    match res {
        Ok(x) => format!("{:?}", x),
        Err(x) => format!("{:?}", x),
    }

§Full syntax

Example that uses all of the syntax supported by this macro.

assert_eq!(bar(Foo::Byte(3)), 6);
assert_eq!(bar(Foo::Byte(9)), 18);
assert_eq!(bar(Foo::Byte(10)), 10);
 
assert_eq!(bar(Foo::U16(3)), 6);
assert_eq!(bar(Foo::U16(9)), 18);
assert_eq!(bar(Foo::U16(10)), 10);
 
assert_eq!(bar(Foo::U32(3)), 0);
 
assert_eq!(bar(Foo::Long(3)), 0);
 
enum Foo {
    Byte(u8),
    U16(u16),
    U32(u32),
    Long(u64),
}
 
const fn bar(foo: Foo) -> u64 {
    typewit::polymatch! {foo;
        // top-level  `|` patterns generate a match arm for every alternate pattern
        | Foo::Byte(x) 
        | Foo::U16(x) 
        if x < 10 
        => (x as u64) * 2,
 
        Foo::Byte(x) | Foo::U16(x) => { x as u64 }
 
        // `|` inside patterns behaves like in regular `match` expressions
        (Foo::U32(_) | Foo::Long(_)) => 0
    }
}

The above invocation of polymatch expands to:

    match foo {
        Foo::Byte(x) if x < 10  => (x as u64) * 2,
        Foo::U16(x) if x < 10  => (x as u64) * 2,
 
        Foo::Byte(x) => { x as u64 }
        Foo::U16(x) => { x as u64 }
 
        (Foo::U32(_) | Foo::Long(_)) => 0
    }