Search code examples
rustmacrosrust-macrosrust-decl-macros

Can I define a macro which will expand into a function call?


I've (naively) tried this, but it doesn't print anything to the screen:

macro_rules! foo {
    ($suffix:tt, $arg:expr) => {
        concat!("foo", $suffix, "(", $arg, ")");
    };
}

fn foo_i32(x: i32) {
    println!("i32 {}", x);
}

fn foo_bool(x: bool) {
    println!("bool {}", x);
}

fn main() {
    foo!("bool", true);
    foo!("i32", 1);
}

Solution

  • Yes, and no.

    First of, concat! generates a string, so your code is essentially the same as if you wrote:

    fn main() {
        "foobool(true)";
        "fooi32(1)";
    }
    

    which is a no-op.

    To generate Rust code, the macro does not need to involve strings at all:

    macro_rules! foo {
        ($suffix:tt, $arg:expr) => {
            $suffix($arg);
        };
    }
    

    which you could call as foo!(foo_bool, true);.

    If however you want to construct the name foo_bool from foo and bool, you need to use concat_idents, which is currently unstable and unlikely to get stable any time soon (because it causes some hygiene issues):

    #![feature(concat_idents)]
    
    macro_rules! foo {
        ($suffix:tt, $arg:expr) => {
            concat_idents!(foo_, $suffix)($arg);
        };
    }
    
    fn foo_i32(x: i32) {
        println!("i32 {}", x);
    }
    
    fn foo_bool(x: bool) {
        println!("bool {}", x);
    }
    
    fn main() {
        foo!(bool, true);
        foo!(i32, 1);
    }