I have a trait with a large number of associated types. I want a function that uses those associated types on both sides of a where clause bound:
trait Kind {
type A;
type B;
// 20+ more types
}
trait Bound<T> {}
fn example<K1, K2>()
where
K1: Kind,
K2: Kind,
K1::A: Bound<K2::A>,
K1::B: Bound<K2::B>,
// 20+ more bounds
{
}
Typing out all the bounds will be slightly brittle, so I'd like to create a macro to generate this:
fn example<K1, K2>()
where
K1: Kind,
K2: Kind,
how_do_i_write_this!(K1, K2, Bound, [A, B, /* 20+ more types */])
{
}
However, calling a macro on the right-hand side of the where clause bound results in an error:
macro_rules! bound {
() => { std::fmt::Debug };
}
fn another_example()
where
u8: bound!(),
{}
error: expected one of `(`, `+`, `,`, `::`, `;`, `<`, or `{`, found `!`
--> src/lib.rs:7:14
|
7 | u8: bound!(),
| ^ expected one of 7 possible tokens
Is there any clever macro trickery that will allow me to DRY up this code?
I'm OK with the exact placement or arguments of the macro changing. For example, the macro generating the entire fn would be acceptable.
If this is not possible, I can use a build script, but I'd rather keep the code co-located if possible.
Quote from the Rust Reference on macros:
According to this, is not possible to invoke a macro in the context of a trait bound, so you can't have the exact syntax you used. However, you can invoke a macro in the context of an item and have the macro generate the function including the trait bounds:
Playground
This has the signature you want. Note that you may need to slightly modify the matcher if you want this to work with other functions (for example, functions with parameters, functions that use generic lifetimes and the like – anything that isn't more or less syntactically equivalent to the
example()declaration).