Can Rust macros expand like C preprocessor macros for hex numbers?

Viewed 658

I'm looking to create a Rust macro that can do what this does in C.

#define V(a,b,c,d) 0x##a##b##c##d

Which when called with:

V(7B,B0,B0,CB)

Will simply have the following hexadecimal number placed in the code at compile time:

0x7BaB0bB0cCDd

Trying something like this:

macro_rules! gen_hex_num {
    ($a:expr , $b:expr , $c:expr , $d:expr) => (
        0x($a)a($b)b($c)c($d)d
    )
}

Produces an error:

error: macro expansion ignores token `a` and any following
 --> src/main.rs:3:16
  |
3 |         0x($a)a($b)b($c)c($d)d
  |               ^
  |
note: caused by the macro expansion here; the usage of `gen_hex_num!` is 
likely invalid in expression context

Documentation and other questions don't seem to cover this scenario.

1 Answers

Nope.

Rust macros can only process and generate whole tokens, not token fragments. Something like 7b is not a token, so you won't be able to write a macro that would match it.

It seems like the main reason to use this macro in C is to make the number more readable. That isn't really necessary in Rust, because underscores are allowed in numeric literals. So you can just write 0x7b_b0_b0_cb instead.

You can approximate the original macro by accepting numbers and doing math, something like the following:

macro_rules! gen_hex_num {
    ($a:expr, $b:expr, $c:expr, $d:expr) => {
        ($a << 24) | ($b << 16) | ($c << 8) | ($d)
    }
}

But you have to call it like gen_hex_num!(0x7B, 0xB0, 0xB0, 0xCB), which probably defeats the purpose.

Related