goertzenator
goertzenator

Reputation: 2039

Can't forward parameters to nested macros

I am working on Rust macros to generate a static array of structures that describe FFI callbacks. What I currently have is...

// some trivial callback functions
extern "C" fn my_fun_1(argc: u32, argv: *const i32) -> i32 { 1 }
extern "C" fn my_fun_2(argc: u32, argv: *const i32) -> i32 { 2 }


// create static array of ErlNifFunc describing above callbacks
nif_init!(b"my_module\0", 
    nif!(b"my_fun_1\0", 3, my_fun_1),
    nif!(b"my_fun_2\0", 5, my_fun_2));

(whole thing is here)

This works because I only need to provide one expansion of the information provided to the nif! macro. But now, in addition to generating an array of structs, I want to work towards generating wrapper functions for the provided functions. So, I can't invoke nif! right away because I now need to do more than one expansion pass on the underlying parameters. I effectively need to move the nif! invocations inside nif_init!, and this is where I drown. I think the top level nif_init! needs to look like this...

nif_init!(b"my_module\0", 
    (b"my_fun_1\0", 3, my_fun_1),
    (b"my_fun_2\0", 5, my_fun_2));

... with the inner parenthesised parameters getting passed on to sub-macros, but I just cannot make it go. The full non-working thing is here. To clarify, this version just tries to do the macro invocation internally. I'm not trying to generate any wrapper functions yet.

Upvotes: 2

Views: 1089

Answers (1)

Shepmaster
Shepmaster

Reputation: 430673

For this case, you can't use parentheses as grouping, you need to use them as part of your macro pattern. I'd avoid using parens to avoid this confusion.

Here, I changed your macro a bit to accept zero-or-more sets of {}. You can macro-iterate over each of them and call your inner macro:

macro_rules! nif_inner {
    ($name:expr, $args:expr, $meth:expr) => ()
}

macro_rules! nif_init {
    ($module:expr, $({ $name:expr, $args:expr, $meth:expr }),*) => (
        $(nif_inner!(name, $args, $meth);)*
    )
}

nif_init!(
    "hello",
    { "name1", 1, true },
    { "name2", 2, false }
);

fn main() {}

Upvotes: 4

Related Questions