How do I get an identifer from an expression argument in a macro?

994 Views Asked by At

I have a constant value defined by a variable:

const VAL: usize = 32;

I want to make a function like this:

macro_rules! valfn {
    ($val:expr) => {
        pub fn $val () -> () {   // here val needs to be a ident
            some_other_fn($val)  // here it needs to be a expr
        }
    };
}

valfn!(VAL);

Bonus points if I can do some manipulation of the ident value one way or the other to avoid clashing definitions. Could I shadow a variable with a function definition? Probably not...

const VAL: usize = 32;
valfn!(VAL); // creates: fn VAL()

or

const VAL_: usize = 32;
valfn!(VAL_); // creates: fn VAL()
2

There are 2 best solutions below

0
On BEST ANSWER

In the macro, an ident is a valid expr, so you can just use ident.

macro_rules! valfn {
    ($val: ident => {
        pub fn $val () -> () {
            some_other_fn($val)
        }
    };
}

You can add a module to avoid naming conflicts, or any of the other suggestions from Shepmaster's answer.

0
On

Accept a token tree and then interpret it twice, once as an ident and once as an expr:

macro_rules! valfn {
    ($val:tt) => { valfn!(@ $val, $val); };
    (@ $vali:ident, $vale:expr) => {};
}

To avoid the name conflict, use one of the many mentioned solutions linked below. One example is the paste crate:

use paste::paste; // 1.0.4

fn some_other_fn(_: usize) {}

const VAL: usize = 32;

macro_rules! valfn {
    ($val:tt) => { valfn!(@ $val, $val); };
    (@ $vali:ident, $vale:expr) => {
        paste! {
            pub fn [<$vali:lower _fn>]() {
                some_other_fn($vale);
            }
        }
    };
}

valfn!(VAL);

fn main() {
    val_fn();
}

See also: