Macro for multiple dynamic argument dispatch

Hello,

I created a macro based on the suggestion from @h2co3 in this thread: https://users.rust-lang.org/t/dyn-dispatch-on-multiple-types

My code is here: GitHub - luketpeterson/double_dyn: Macro for implementing functions with multiple dynamic argument dispatch

@h2co3's suggested approach compiles to very reasonable code, but it had the drawback of requiring a dense implementation matrix. In other words, to support a new A type, it was necessary to add a new function to the "Level 1 Trait" and therefore touch every single implementation. To add a new B type, it's necessary to implement the corresponding function for every A type. So the number of functions grows as n^2 where n is the number of supported types.

This macro still ends up generating all those functions, but at least the clutter is hidden away.

An example macro invocation looks like this:

double_dyn!{
    type A: MyTraitA;
    type B: MyTraitB: std::fmt::Display;

    fn multiply(a: &dyn MyTraitA, b: &dyn MyTraitB) -> Box<dyn MyTraitB>;

    impl for <i32, String>
    {
        fn multiply(a: &i32, b: &String) -> Box<dyn MyTraitB> {
            let multiplied_val = *a * b.parse::<i32>().unwrap();
            Box::new(multiplied_val.to_string())
        }
    }

    impl for <[i8, i16, i32, i64, i128], [f32, f64]>
    {
        fn multiply(a: &#A, b: &#B) -> Box<dyn MyTraitB> {
            Box::new((*a as #B) * *b)
        }
    }
}

let val = multiply(&2, &7.5);

So: I'm looking for suggestions on:

  1. Ways to make the syntax "Rustier".
  2. Whether this is useful to you, or changes I could make so it would be more useful
  3. If there might be a way to spread the implementation across multiple macro invocations. i.e. to add additional impls to functions defined in another block. i.e. does anyone know a robust work-around for Crate local state for procedural macros? · Issue #44034 · rust-lang/rust · GitHub ?

Any thoughts are appreciated.

Thank you.