I have a set of items that I want to execute the same code for in different places in my codebase.
Let's say they are methods for my Lua scripting API:
trait Method {
/// Name of the method
const NAME: &'static str;
/// Help text for the method
const HELP: &'static str;
/// Arguments the method takes when called
type Args;
/// Return type
type Ret: IntoLuaMulti<'static>;
/// The function that gets called
fn call<'a>(lua: &Lua, exec: &mut LuaExecContext, args: Self::Args) -> mlua::Result<Self::Ret>;
}
Now I create types for each method that I want to define, and implement this trait for each. For the sake of brevity, let's just name the types Method1, Method2, Method3, etc...
.
Now, at one place in my code I need to add the methods to my Lua user type. It looks like this for a single item:
methods.add_method_mut(Method1::NAME, Method1::call);
I don't want to do this manually for every single type. I found a crate called forr that offers a nice macro that lets me generate code for each item.
forr::forr! {$t:ty in [Method1, Method2, Method3, Method4, Method5, Method6, ...] $* {
methods.add_method_mut($t::NAME, $t::call);
}};
Problem solved, right? Well, partially.
Now I want to add a help section somewhere else that lists each method, and shows help for them.
forr::forr! {$t:ty in [Method1, Method2, Method3, Method4, Method5, Method6, ...] $* {
ui.label($t::NAME);
ui.label($t::HELP);
}};
Notice how I have to repeat all the items.
What if I stored them in a macro?
macro_rules! methods {
() => {
[Method1, Method2, Method3, Method4, Method5, Method6, ...]
};
}
...
forr::forr! {$t:ty in methods!() $* {
methods.add_method_mut($t::NAME, $t::call);
}};
error: unexpected token: expected `[...]`
Nope, that doesn't work, because the macro isn't eagerly evaluated by the procedural macro, so I can't do this.
Is there a way to avoid having to repeat myself?