# Provide enumerate and len for macro \* and +

**URL:** <https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202>\
**Category:** language design\
**Created:** [January 18, 2024, 8:31pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202 "2024-01-18T20:31:07Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dwarsloeper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dwarsloeper/32/11073_2.png) [@Dwarsloeper](https://internals.rust-lang.org/u/Dwarsloeper)\
**Post date:** [January 18, 2024, 8:31pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202/1 "2024-01-18T20:31:07Z")

</div>

One sometimes needs to know the current index and/or the length of a repetition. There are clever but cludgy ways to achieve this, which make a macro even less readable.

It would be very useful and much easier for the macro engine to provide these values. I would suggest `$.var` for the index (at which point of the repetition are we) and `$#var` for the length (what number of elements are there.) These syntaxes are currently not possible, hence backwards compatible.

This should also work for nested repetitions, as shown in this example, which has an outer repeat of paren lists and an inner one of all but the 1st literal in each:

```rust
macro_rules! x {
    ($(($a:literal $($b:literal)+))+) => {
        $($(println!("{} ({}/{}) -- {} ({}/{})", $a, $.a, $#a, $b, $.b, $#b);)+)+
        // .. ## .. ## --- --- --- ---
    }
}
x!((27 4 5 6)
   (49 7 8 9 0));

```

```plaintext
27 (0/2) -- 4 (0/3)
27 (0/2) -- 5 (1/3)
27 (0/2) -- 6 (2/3)
49 (1/2) -- 7 (0/4)
49 (1/2) -- 8 (1/4)
49 (1/2) -- 9 (2/4)
49 (1/2) -- 0 (3/4)

```

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [January 18, 2024, 8:55pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202/2 "2024-01-18T20:55:06Z")

</div>

See [RFC 3086](https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html) and its tracking issue:

> <https://github.com/rust-lang/rust/issues/83527>
>
> This is a tracking issue for the RFC "3086" (rust-lang/rfcs#3086).
> The feature …gate for the issue is \`#!\[feature(macro\_metavar\_expr)\]\`.
> 
> \### About tracking issues
> 
> Tracking issues are used to record the overall progress of implementation.
> They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
> A tracking issue is however \*not\* meant for large scale discussion, questions, or bug reports about a feature.
> Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
> 
> \### Steps
> 
> \- \[\] Implement the RFC (cc @markbt -- has there been work done here already?)
> \- \[\] Adjust documentation (\[see instructions on rustc-dev-guide\]\[doc-guide\])
> \- \[\] Stabilization PR (\[see instructions on rustc-dev-guide\]\[stabilization-guide\])
> 
> \[stabilization-guide\]: https://rustc-dev-guide.rust-lang.org/stabilization\_guide.html#stabilization-pr
> \[doc-guide\]: https://rustc-dev-guide.rust-lang.org/stabilization\_guide.html#documentation-prs
> 
> \### Unresolved questions and bugs
> 
> \- \[\] \[Figure out problems around hygiene\](https://github.com/rust-lang/rust/issues/83527#issuecomment-1073506711)
> 
> \### Implementation history
> 
> \<!--
> Include a list of all the PRs that were involved in implementing the feature.
> \--\>

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [January 18, 2024, 9:36pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202/3 "2024-01-18T21:36:02Z")

</div>

More concretely, here's how your macro could look: [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6ba0c3bfe352f38a2acca9507ddc580c)

```rust
macro_rules! x {
    ($(($a:literal $($b:literal)+))+) => {
        $($(println!("{} ({}/{}) -- {} ({}/{})",
            $a, ${index(1)}, ${length(1)}, $b, ${index()}, ${length()});)+)+
    }
}

```

---

<div class="post-metadata">

**Author:** ![Dwarsloeper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dwarsloeper/32/11073_2.png) [@Dwarsloeper](https://internals.rust-lang.org/u/Dwarsloeper)\
**Post date:** [January 18, 2024, 10:47pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202/4 "2024-01-18T22:47:14Z")

</div>

Thanks for pointing it out! The tracking issue is beyond bewildering, especially as it seems to be changing over time.

This example you give here, however is clear and something I can grok. 😀

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [April 17, 2024, 10:47pm UTC](https://internals.rust-lang.org/t/provide-enumerate-and-len-for-macro-and/20202/5 "2024-04-17T22:47:16Z")

</div>

Closed on April 17, 2024, 10:47pm UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
