Skip to content

Commit 327c2f8

Browse files
committed
Add documentation for meta variable expressions
1 parent e356977 commit 327c2f8

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
@@ -196,6 +196,220 @@ compiler knows how to expand them properly:
196196
not have the same number. This requirement applies to every layer of nested
197197
repetitions.
198198

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

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

0 commit comments

Comments
 (0)