4

Essentially I have a macro that looks like:

macro_rules! my_macro {
  ( $expr:expr; $( $pat:pat ),* ) => {
    match $expr {
      $(
        $pat => $(some-macro-magic-here),
      )*
    }
  }
}

Is there anything that can go into $(some-macro-magic-here), so that

my_macro!(foo; A, B, C)

will expand to

match foo {
  A => 2,
  B => 4,
  C => 6,
}

?

Is there some other way I might be able to get a similar feature that effectively lets me "enumerate" over the sequence of inputs for the macro?

I think I could probably write a recursive macro to get a similar effect, but I'm wondering if there's a more elegant/idiomatic way about it than what I'm thinking of

math4tots
  • 8,540
  • 14
  • 58
  • 95

2 Answers2

2

Because macros aren't allowed to store or manipulate "variables" in any form, this problem becomes very difficult. You could, however, use an iterator to do something to the same effect, by creating an iterator that "enumerates" over the input the way you want it (using std::iter::successors, for example), and simply calling iterator.next().unwrap() in $(some-macro-magic-here).

EvilTak
  • 7,091
  • 27
  • 36
1

You cannot create such match statement as Rust do not allow creating match branches via macro, aka this will not work right now:

match val {
    my_macro! (A, B, C)
}

However in this case we can "hack it around" by using nested if let blocks and using recursive macro:

macro_rules! my_macro {
  ($expr:expr; $($pat:pat),*) => {
    my_macro!($expr; 2, 2; $($pat),*)
  };
  ($expr:expr; $curr:expr, $step:literal; $pat:pat) => {
    if let $pat = $expr {
        $curr
    } else {
        unreachable!()
    }
  };
  ($expr:expr; $curr:expr, $step:literal; $pat:pat, $($rest:pat),*) => {
    if let $pat = $expr {
        $curr
    } else {
        my_macro! ($expr; $curr+$step, $step; $($rest),*)
    }
  }
}

Playground

It will generate the nested entries with enough 2 added to create the expected constants. Alternatively you could replace that with multiplication, but it should be optimised out by the compiler anyway.

Hauleth
  • 22,873
  • 4
  • 61
  • 112