• it/its

// the deer!
// plural deer therian θΔ, trans demigirl
// stray pet with a keyboard
// i'm 20 & account is 18+!
name-color: #ebe41e
// yeah



poliorcetics
@poliorcetics

One repeating pain point of Rust macro is that knowing in which iteration you are is not readily available (yet, there is RFC 3086).

Getting the length of anything is the simplest (playground link):

macro_rules! length_of_repetition {
    ($($tt:tt);*) => {
        [$(length_of_repetition!(@inner $tt)),*].len()
    };
    (@inner $tt:tt) => {()};
}

fn main() {
    println!(
        "L1: {}, L2: {}",
        length_of_repetition!(a; b; c; d),
        length_of_repetition!(1; 2; "hello"; { 42 = 34 }),
    );
}

Getting the index is trickier but there is an easy case: tuples (of ident notably, for generics in structs for example) ! Playground link 2

macro_rules! tuple_indexes {
    ( $($tuple_ident:ident),* ) => {
        #[repr(usize)]
        #[allow(non_camel_case_types)]
        enum Indexes {
            $($tuple_ident),*
        }

        const LEN: usize = [$(Indexes::$tuple_ident),*].len();

        $(
            println!("{} / {} is {}", Indexes::$tuple_ident as usize + 1, LEN, stringify!($tuple_ident));
        )*
    };
}

fn main() {
    tuple_indexes!(a, b, c, d, e, f, g, h);
}

Finally, it's possible to get the counter for anything that way (Playroung link):

macro_rules! with_indexes {
    // Public interface of your macro
    ($($tt:tt);*) => {
        let mut index: isize = -1_isize;

        with_indexes!(
            @inner
            $({
                { index += 1_isize; index };
                $tt
            });*
        )
    };
    // Real implementation with index
    (@inner $({$index:expr; $tt:tt});*) => {
        const LEN: usize = [$(with_indexes!(@len $tt)),*].len();

        $(
            println!("{} / {} : {}", $index + 1, LEN, stringify!($tt));
        )*
    };
    (@len $tt:tt) => { () };
}

fn main() {
    with_indexes!(
        a;
        (42 + 32);
        "i am alive";
        "the cat does not want to leave my laps";
        (use std::env);
        { const A: usize = 42; A * A }
    );
}

Depending on the macro and optimization level, the index computation may be done at compile time.

I applied the first 2 in https://github.com/yoshuawuyts/futures-concurrency/pull/99 to great success and I haven't needed the third yet but at least you now know it exists 🦀 !


You must log in to comment.