1

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()
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user318904
  • 2,968
  • 4
  • 28
  • 37

2 Answers2

4

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
1

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.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204