Skip to content

Commit a26329f

Browse files
committed
Add documentation for meta variable expressions
1 parent 824b915 commit a26329f

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed

src/macros-by-example.md

+214
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,220 @@ compiler knows how to expand them properly:
195195
not have the same number. This requirement applies to every layer of nested
196196
repetitions.
197197

198+
## Meta variable expressions
199+
200+
Give access to additional metadata about meta variables that otherwise would be difficult or even impossible to get through elements such as `count` or `index`.
201+
202+
### count($ident, depth)
203+
204+
Expands to an unsuffixed integer literal representing the number of times a ***meta variable*** repeats in total.
205+
206+
The output of `count` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
207+
208+
```rust
209+
macro_rules! count_idents {
210+
( $( $i:ident ),* ) => {
211+
${count($i)}
212+
};
213+
}
214+
215+
fn main() {
216+
assert_eq!(count_idents!(a, b, c), 3);
217+
}
218+
```
219+
220+
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted.
221+
222+
```rust
223+
macro_rules! no_repetition0 {
224+
( $( $a:ident: $( $b:literal ),* );+ ) => {
225+
[${count($b)}]
226+
};
227+
}
228+
229+
macro_rules! no_repetition1 {
230+
( $( $a:ident: $( $b:literal ),* );+ ) => {
231+
[${count($b, 1)}]
232+
};
233+
}
234+
235+
macro_rules! outermost {
236+
( $( $a:ident: $( $b:literal ),* );+ ) => {
237+
[$( ${ignore($a)} ${count($b)}, )+]
238+
};
239+
}
240+
241+
fn main() {
242+
// 1 2 3 4 5 = 5 elements
243+
assert_eq!(no_repetition0!(a: 1, 2, 3; b: 4, 5), [5]);
244+
245+
// a b = 2 elements
246+
assert_eq!(no_repetition1!(a: 1, 2, 3; b: 4, 5), [2]);
247+
248+
// 1 2 3 = 3 elements
249+
// 4 5 = 2 elements
250+
assert_eq!(outermost!(a: 1, 2, 3; b: 4, 5), [3, 2]);
251+
}
252+
```
253+
254+
`count` can not be placed inside the innermost repetition.
255+
256+
### ignore($ident)
257+
258+
Binds a meta variable for repetition, but expands to nothing.
259+
260+
```rust
261+
macro_rules! count {
262+
( $( $i:stmt ),* ) => {{
263+
0 $( + 1 ${ignore($i)} )*
264+
}};
265+
}
266+
267+
fn main() {
268+
assert_eq!(count!(if true {} else {}, let _: () = (), || false), 3);
269+
}
270+
```
271+
272+
Sometimes it is desired to repeat an expansion the same number of times as a meta variable repeats but without actually expanding the meta variable. It may be possible to work around this by expanding the meta variable in an expression like `{ let _ = $x; 1 }`, where the expanded value of `$x` is ignored, but this is only possible if what `$x` expands to is valid in this kind of expression.
273+
274+
The `ignore` meta variable acts as if ident was used for the purposes of repetition, but expands to nothing.
275+
276+
### index(depth)
277+
278+
Expands to an unsuffixed integer literal representing the current iteration index of a ***repetition*** at the given depth.
279+
280+
The output of `index` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
281+
282+
```rust
283+
trait Length {
284+
fn length(&self) -> usize;
285+
}
286+
287+
macro_rules! impl_tuple {
288+
( $( $name:ident ),* ) => {
289+
impl<$( $name, )*> Length for ($( $name, )*)
290+
where
291+
$( $name: AsRef<[u8]>, )*
292+
{
293+
fn length(&self) -> usize {
294+
let mut sum: usize = 0;
295+
$({
296+
${ignore($name)}
297+
sum = sum.wrapping_add(self.${index()}.as_ref().len());
298+
})*
299+
sum
300+
}
301+
}
302+
};
303+
}
304+
305+
impl_tuple!(A, B);
306+
307+
fn main() {
308+
assert_eq!((&[1, 2, 3][..], &[4, 5][..]).length(), 5);
309+
}
310+
```
311+
312+
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted.
313+
314+
```rust
315+
macro_rules! innermost0 {
316+
( $( $a:ident: $( $b:literal ),* );+ ) => {
317+
[$( $( ${ignore($b)} ${index()}, )* )+]
318+
};
319+
}
320+
321+
macro_rules! innermost1 {
322+
( $( $a:ident: $( $b:literal ),* );+ ) => {
323+
[$( $( ${ignore($b)} ${index(1)}, )* )+]
324+
};
325+
}
326+
327+
macro_rules! outermost {
328+
( $( $a:ident: $( $b:literal ),* );+ ) => {
329+
[$( ${ignore($a)} ${index()}, )+]
330+
};
331+
}
332+
333+
fn main() {
334+
// 1 2 3 = 3 elements
335+
// 4 5 = 2 elements
336+
//
337+
// Increasing list from the innermost loop refering innermost indexes
338+
assert_eq!(innermost0!(a: 1, 2, 3; b: 4, 5), [0, 1, 2, 0, 1]);
339+
340+
// a b = 2 elements
341+
//
342+
// Increasing list from the innermost loop refering outermost indexes
343+
assert_eq!(innermost1!(a: 1, 2, 3; b: 4, 5), [0, 0, 0, 1, 1]);
344+
345+
// a b = 2 elements
346+
//
347+
// Increasing list from the outermost loop refering outermost indexes
348+
assert_eq!(outermost!(a: 1, 2, 3; b: 4, 5), [0, 1]);
349+
}
350+
```
351+
352+
### length(depth)
353+
354+
Expands to an unsuffixed integer literal representing the sum or length of a ***repetition*** at a given depth.
355+
356+
The output of `length` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
357+
358+
```rust
359+
macro_rules! array {
360+
( $( $i:ident ),* ) => {
361+
[${length()}, )*]
362+
};
363+
}
364+
365+
fn main() {
366+
assert_eq!(array!(A, B, C), [3, 3, 3]);
367+
}
368+
```
369+
370+
If repetitions are nested, then the optional depth parameter can be used to limit the number of nested repetitions that are counted.
371+
372+
```rust
373+
macro_rules! innermost0 {
374+
( $( $a:ident: $( $b:literal ),* );+ ) => {
375+
[$( $( ${ignore($b)} ${length()}, )* )+]
376+
};
377+
}
378+
379+
macro_rules! innermost1 {
380+
( $( $a:ident: $( $b:literal ),* );+ ) => {
381+
[$( $( ${ignore($b)} ${length(1)}, )* )+]
382+
};
383+
}
384+
385+
macro_rules! outermost {
386+
( $( $a:ident: $( $b:literal ),* );+ ) => {
387+
[$( ${ignore($a)} ${length()}, )+]
388+
};
389+
}
390+
391+
fn main() {
392+
// 1 2 3 = 3 elements
393+
// 4 5 = 2 elements
394+
//
395+
// 3 and 2 elements repeating 3 and 2 times in the innermost loop
396+
assert_eq!(innermost0!(a: 1, 2, 3; b: 4, 5), [3, 3, 3, 2, 2]);
397+
398+
// a b = 2 elements
399+
//
400+
// 2 elements repeating 5 times in the innermost loop
401+
assert_eq!(innermost1!(a: 1, 2, 3; b: 4, 5), [2, 2, 2, 2, 2]);
402+
403+
// a b = 2 elements
404+
//
405+
// 2 elements repeating 2 times in the outermost loop
406+
assert_eq!(outermost!(a: 1, 2, 3; b: 4, 5), [2, 2]);
407+
}
408+
```
409+
410+
Contrary to `count`, `length` must be placed inside a repetition.
411+
198412
## Scoping, Exporting, and Importing
199413

200414
For historical reasons, the scoping of macros by example does not work entirely

0 commit comments

Comments
 (0)