Search code examples
rustmacrosrust-macros

How to make rust macro optional token produce code when not present?


Here is the classic situation :

macro_rules! foo {
    ($a:tt $(b:tt)?) => {
        do_something_with_a($a);
        $(do_something_with_b($b);)?
    }
}

But what if you want this:

macro_rules! foo {
    ($a:tt) => {
        do_something_with_a($a);
        do_something_when_b_is_absent();
    }
    ($a:tt b:tt) => {
        do_something_with_a($a);
        do_something_with_b($b);
    }
}

How to avoid code repetition here ?

Is there a way to do something like:

macro_rules! foo {
    ($a:tt $(b:tt)?) => {
        do_something_with_a($a);
        $(do_something_with_b($b);)?
        ${if(
            eq(count(b), 0),
            {do_something_when_b_is_absent();}
        )}
    }
}

My guess is no, but I could be surprised :)


Solution

  • You could do this using @internal to differentiate between the 2 cases, or use a different macro for the other cases:

    macro_rules! foo {
        (@internal ) => {
            do_something_when_b_is_absent();
        };
        (@internal $b:tt) => {
            do_something_with_b($b);
        };
        ($a:tt $($b:tt)?) => {
            do_something_with_a($a);
            foo!(@internal $($b)?);
        };
    }