Search code examples
rustmacrosrust-macros

How do I provide optional generics as macro_rules arguments?


I want to use macro_rules to create an implementation for a trait. The types should be given as macro arguments. However, some of those types may contain lifetimes, so I need them. I also have a generic type from inside the macro. The result should look like

impl<T> Foo<T> for MyType { .. }
// Or with lifetime:
impl<'a, 'b, T> Foo<T> for LifetimeType<'a, 'b> { .. }

How do I structure the macro and how do I call it?


Solution

  • You can use the lifetime specifier to match lifetimes in macro arguments:

    trait Foo{}
    
    macro_rules!impl_foo {
        ($($l:lifetime),*; $t:tt) => { impl<$($l),*> Foo for $t<$($l),*> {} };
        ($t:ty) => { impl Foo for $t {} };
    }
    

    And call it like this:

    impl_foo!(A);
    impl_foo!('a, 'b; B);
    

    Playground

    Note that the only place I could find that talked of the lifetime specifier for captures is the associated RFC. It is in particular conspicuously missing from The little book of Rust macros, even though it was merged in 2016…