Search code examples
macrosrust

How to get index of macro repetition single element


I need to get index of macro repetition element to write next code:

struct A {
    data: [i32; 3]
}

macro_rules! tst {
    ( $( $n:ident ),* ) => {
        impl A {
            $(
                fn $n(self) -> i32 {
                    self.data[?] // here I need the index
                }
            )*
        }
    }
}

I know one way to do it: just tell user to write index by hands:

( $( $i:ident => $n:ident ),* )

But is there a more elegant way which does not require user's action?


Solution

  • The easiest way is to use recursion, like so:

    struct A {
        data: [i32; 3]
    }
    
    macro_rules! tst {
        (@step $_idx:expr,) => {};
    
        (@step $idx:expr, $head:ident, $($tail:ident,)*) => {
            impl A {
                fn $head(&self) -> i32 {
                    self.data[$idx]
                }
            }
    
            tst!(@step $idx + 1usize, $($tail,)*);
        };
    
        ($($n:ident),*) => {
            tst!(@step 0usize, $($n,)*);
        }
    }
    
    tst!(one, two, three);
    
    fn main() {
        let a = A { data: [10, 20, 30] };
        println!("{:?}", (a.one(), a.two(), a.three()));
    }
    

    Note that I changed the method to take &self instead of self, since it made writing the example in the main function easier. :)

    Each step in the recursion just adds 1 to the index. It is a good idea to use "typed" integer literals to avoid compilation slowdown due to lots and lots of integer inference.