-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathquick-intro-to-macros.html
1781 lines (1506 loc) · 130 KB
/
quick-intro-to-macros.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="rustdoc">
<title>A Quick Intro to Rust Macros</title>
</head>
<body class="rustdoc">
<!--[if lte IE 8]>
<div class="warning">
This old browser is unsupported and will most likely display funky
things.
</div>
<![endif]-->
<h1 class="title">A Quick Intro to Rust Macros</h1>
<nav id="TOC"><ul>
<li><a href="#macro-mechanics">1 Macro Mechanics</a><ul></ul></li>
<li><a href="#construction">2 Construction</a><ul></ul></li>
<li><a href="#indexing-and-shuffling">3 Indexing and Shuffling</a><ul>
<li><a href="#substitution">3.1 Substitution</a><ul></ul></li>
<li><a href="#being-hygienic">3.2 Being Hygienic</a><ul></ul></li></ul></li>
<li><a href="#the-nuclear-option">4 The Nuclear Option</a><ul></ul></li>
<li><a href="#some-more-gotchas">5 Some More Gotchas</a><ul></ul></li>
<li><a href="#distribution">6 Distribution</a><ul></ul></li>
<li><a href="#postscript">7 Postscript</a><ul></ul></li></ul></nav><!-- DO-NOT-TEST -->
<style type="text/css">
/**
* Copyright 2013 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
* With elements taken from Bootstrap v3.0.2 (MIT licensed).
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
*:not(body) {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* General structure */
body {
margin: 0 auto;
padding: 0 15px;
font-family: "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 18px;
color: #333;
line-height: 1.428571429;
}
@media (min-width: 768px) {
body {
max-width: 750px;
}
}
h1, h2, h3, h4, h5, h6, nav, #versioninfo {
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
color: black;
font-weight: 400;
line-height: 1.1;
}
h1, h2, h3 {
margin-top: 20px;
margin-bottom: 15px;
}
h1 {
margin-bottom: 20px;
}
h4, h5, h6 {
margin-top: 12px;
margin-bottom: 10px;
padding: 5px 10px;
}
h5, h6 {
text-decoration: underline;
}
h1 {
font-size: 28px;
font-weight: 500;
padding: .1em .4em;
border-bottom: 2px solid #ddd;
}
h1.title {
line-height: 1.5em;
}
h2 {
font-size: 26px;
padding: .2em .5em;
border-bottom: 1px solid #ddd;
}
h3 {
font-size: 24px;
padding: .2em .7em;
border-bottom: 1px solid #DDE8FC;
}
h4 {
font-size: 22px;
}
h5 {
font-size: 20px;
}
h6 {
font-size: 18px;
}
@media (min-width: 992px) {
h1 {
font-size: 36px;
}
h2 {
font-size: 30px;
}
h3 {
font-size: 26px;
}
}
nav {
column-count: 2;
-moz-column-count: 2;
-webkit-column-count: 2;
font-size: 15px;
margin: 0 0 1em 0;
}
p {
margin: 0 0 1em 0;
}
strong {
font-weight: bold;
}
em {
font-style: italic;
}
footer {
border-top: 1px solid #ddd;
font-size: 14.3px;
font-style: italic;
padding-top: 5px;
margin-top: 3em;
margin-bottom: 1em;
}
/* Links layout */
a {
text-decoration: none;
color: #428BCA;
background: transparent;
}
a:hover, a:focus {
color: #2A6496;
text-decoration: underline;
}
a:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
a:hover, a:active {
outline: 0;
}
h1 a:link, h1 a:visited, h2 a:link, h2 a:visited,
h3 a:link, h3 a:visited, h4 a:link, h4 a:visited,
h5 a:link, h5 a:visited {color: black;}
h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover,
h5 a:hover {text-decoration: none;}
/* Code */
pre, code {
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", monospace;
}
pre {
border-left: 2px solid #eee;
white-space: pre-wrap;
padding: 14px;
padding-right: 0;
margin: 20px 0;
font-size: 13px;
word-break: break-all;
word-wrap: break-word;
}
code {
padding: 0 2px;
color: #8D1A38;
white-space: pre-wrap;
}
pre code {
padding: 0;
font-size: inherit;
color: inherit;
}
a > code {
color: #428BCA;
}
/* Code highlighting */
pre.rust .kw { color: #8959A8; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
pre.rust .number, pre.rust .string { color: #718C00; }
pre.rust .self, pre.rust .boolval, pre.rust .prelude-val,
pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
pre.rust .lifetime { color: #B76514; }
/* The rest */
#versioninfo {
text-align: center;
margin: 0.5em;
font-size: 1.1em;
}
@media (min-width: 992px) {
#versioninfo {
font-size: 0.8em;
position: fixed;
bottom: 0px;
right: 0px;
}
.white-sticker {
background-color: #fff;
margin: 2px;
padding: 0 2px;
border-radius: .2em;
}
}
#versioninfo a.hash {
color: gray;
font-size: 80%;
}
blockquote {
color: #000;
margin: 20px 0;
padding: 15px 20px;
background-color: #f2f7f9;
border-top: .1em solid #e5eef2;
border-bottom: .1em solid #e5eef2;
}
blockquote p {
font-size: 17px;
font-weight: 300;
line-height: 1.4;
}
blockquote p:last-child {
margin-bottom: 0;
}
ul, ol {
padding-left: 25px;
}
ul ul, ol ul, ul ol, ol ol {
margin-bottom: 0;
}
dl {
margin-bottom: 20px;
}
dd {
margin-left: 0;
}
nav ul {
list-style-type: none;
margin: 0;
padding-left: 0px;
}
/* Only display one level of hierarchy in the TOC */
nav ul ul {
display: none;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eeeeee;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
table tr.odd {
background: #eee;
}
table td,
table th {
border: 1px solid #ddd;
padding: 5px;
}
/* Code snippets */
.rusttest { display: none; }
pre.rust { position: relative; }
.test-arrow {
display: inline-block;
position: absolute;
top: 0;
right: 10px;
font-size: 150%;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
.unstable-feature {
border: 2px solid red;
padding: 5px;
}
@media (min-width: 1170px) {
pre {
font-size: 15px;
}
}
@media print {
* {
text-shadow: none !important;
color: #000 !important;
background: transparent !important;
box-shadow: none !important;
}
a, a:visited {
text-decoration: underline;
}
p a[href]:after {
content: " (" attr(href) ")";
}
footer a[href]:after {
content: "";
}
a[href^="javascript:"]:after, a[href^="#"]:after {
content: "";
}
pre, blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
@page {
margin: 2cm .5cm;
}
h1:not(.title), h2, h3 {
border-bottom: 0px none;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3 {
page-break-after: avoid;
}
table {
border-collapse: collapse !important;
}
table td, table th {
background-color: #fff !important;
}
}
#keyword-table-marker + table thead { display: none; }
#keyword-table-marker + table td { border: none; }
#keyword-table-marker + table {
margin-left: 2em;
margin-bottom: 1em;
}
</style>
<style type="text/css">
/* Customisations. */
.small-code code {
font-size: 60%;
}
table pre.rust {
margin: 0;
border: 0;
}
table.parse-table tbody > tr > td:nth-child(1) > code:nth-of-type(2) {
color: black;
margin-top: -0.7em;
margin-bottom: -0.6em;
}
table.parse-table tbody > tr > td:nth-child(1) > code {
display: block;
}
table.parse-table tbody > tr > td:nth-child(2) > code {
display: block;
}
.katex {
font: 400 1.21em/1.2 KaTeX_Main;
white-space: nowrap;
font-family: "Cambria Math", "Cambria", serif;
}
.katex .vlist > span > {
display: inline-block;
}
.mathit {
font-style: italic;
}
.katex .reset-textstyle.scriptstyle {
font-size: 0.7em;
}
.katex .reset-textstyle.textstyle {
font-size: 1em;
}
.katex .textstyle > .mord + .mrel {
margin-left: 0.27778em;
}
.katex .textstyle > .mrel + .minner, .katex .textstyle > .mrel + .mop, .katex .textstyle > .mrel + .mopen, .katex .textstyle > .mrel + .mord {
margin-left: 0.27778em;
}
.katex .textstyle > .mclose + .minner, .katex .textstyle > .minner + .mop, .katex .textstyle > .minner + .mord, .katex .textstyle > .mpunct + .mclose, .katex .textstyle > .mpunct + .minner, .katex .textstyle > .mpunct + .mop, .katex .textstyle > .mpunct + .mopen, .katex .textstyle > .mpunct + .mord, .katex .textstyle > .mpunct + .mpunct, .katex .textstyle > .mpunct + .mrel {
margin-left: 0.16667em;
}
.katex .textstyle > .mord + .mbin {
margin-left: 0.22222em;
}
.katex .textstyle > .mbin + .minner, .katex .textstyle > .mbin + .mop, .katex .textstyle > .mbin + .mopen, .katex .textstyle > .mbin + .mord {
margin-left: 0.22222em;
}
</style>
<blockquote>
<p><strong>Note</strong>: This article is for an obsolete version of Rust, and has been superceded by the slightly less misleadingly named <a href="https://danielkeep.github.io/practical-intro-to-macros.html">"A Practical Intro to Macros in Rust 1.0"</a>.</p>
</blockquote>
<p></p>
<blockquote>
<p><strong>Note</strong>: This article exists as an additional resource for learning about macros in Rust. There is also the <a href="http://doc.rust-lang.org/guide-macros.html">official Rust Macros Guide</a>.</p>
</blockquote>
<p>I think I might be weird. It seems like almost the first thing I do when encountering a new language is go hunting for metaprogramming facilities. This is usually followed by working out how to abuse them to do hideous, evil things.</p>
<p>I've become quite enamoured with Rust lately, due in no small part to its interesting macro system. On a whim the other night, I decided to see about duplicating the functionality of D's <code>std.range.recurrence</code> function in Rust. I was rather chuffed with the result, and thought that it might serve as a nice little, non-trivial example of how to construct macros in Rust.</p>
<p>The TLDR of this article, then, is that we will construct a macro that lets us easily define recurrence relation iterators in Rust, with the following syntax:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>let</span> <span class='ident'>fib</span> <span class='op'>=</span> <span class='macro'>recurrence</span><span class='macro'>!</span>(<span class='ident'>a</span>[<span class='ident'>n</span>]: <span class='ident'>u64</span> <span class='op'>=</span> <span class='number'>0</span>, <span class='number'>1</span> ... <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>]);
<span class='kw'>for</span> <span class='ident'>e</span> <span class='kw'>in</span> <span class='ident'>fib</span>.<span class='ident'>take</span>(<span class='number'>10</span>) { <span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>e</span>) }
</pre>
<blockquote>
<p><strong>Note</strong>: don't panic! What follows is the only time D or math will be talked about.</p>
</blockquote>
<p>For context, <code>std.range.recurrence</code> is a templated function which returns an iterator (called a "range" in D parlance) that yields successive elements of a recurrence relation. If you aren't familiar, a recurrence relation is a sequence where each value is defined in terms of one or more <em>previous</em> values, with one or more initial values to get the whole thing started. For example, the <a href="https://en.wikipedia.org/wiki/Fibonacci_number">Fibonacci sequence</a> can be defined by the relation:</p>
<div class="katex" style="font-size: 100%; text-align: center;">
<span class="katex"><span class="katex-inner"><span style="height: 0.68333em;" class="strut"></span><span style="height: 0.891661em; vertical-align: -0.208331em;" class="strut bottom"></span><span class="base textstyle uncramped"><span class="reset-textstyle displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right: 0.13889em;">F</span><span class="vlist"><span style="top: 0.15em; margin-right: 0.05em; margin-left: -0.13889em;" class=""><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit">n</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span></span></span></span><span class="mrel">=</span><span class="mord">0</span><span class="mpunct">,</span><span class="mord">1</span><span class="mpunct">,</span><span class="mpunct">…</span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right: 0.13889em;">F</span><span class="vlist"><span style="top: 0.15em; margin-right: 0.05em; margin-left: -0.13889em;" class=""><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">n</span><span class="mbin">−</span><span class="mord">1</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span></span></span></span><span class="mbin">+</span><span class="mord"><span class="mord mathit" style="margin-right: 0.13889em;">F</span><span class="vlist"><span style="top: 0.15em; margin-right: 0.05em; margin-left: -0.13889em;" class=""><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">n</span><span class="mbin">-</span><span class="mord">2</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size: 0em;" class=""></span></span></span></span></span></span></span></span></span></span>
</div>
<p>The way it works in D is that the user provides the template with a string literal which contains an expression defining the recurrence. The expression uses the fixed names <code>a</code> and <code>n</code> to refer to the sequence and the value currently being computed. The template expands to a function which is then called with the initial elements of the sequence. So, the Fibonacci sequence would be written, with <code>recurrence</code> in D as:</p>
<pre><code class="language-{d}">// a[0] = 0, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
auto fib = recurrence!("a[n-1] + a[n-2]")(0, 1);
// print the first 10 Fibonacci numbers
foreach (e; take(fib, 10)) { writeln(e); }
</code></pre>
<h1 id="macro-mechanics" class='section-header'><a
href="#macro-mechanics">1 Macro Mechanics</a></h1>
<p>Before going into the construction of the <code>recurrence!</code> macro, it may be helpful to understand how macros in Rust work. If you're already comfortable with this, feel free to skip this section.</p>
<p>A macro invocation in Rust is, in contrast to something like C, not a wholly separate pass over the source code. Macro invocations are actually a normal part of the compiler's AST representation. This means that invocations can <em>only</em> appear in positions where they're explicitly supported. Currently, they can appear in place of items, methods, statements, expressions, and patterns. Note that, as a consequence of this, there are some things you can't do with macros, such as generate the identifier for a function declaration.</p>
<p>However, the status of macro invocations as first-class members of the AST means that the Rust parser has to be able to parse them into something sensible, even when they use syntax that Rust itself doesn't support. The way this is done is by parsing the contents of an invocation into "token trees". If we take the <code>fib</code> example above, given the invocation:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='macro'>recurrence</span><span class='macro'>!</span>(<span class='ident'>a</span>[<span class='ident'>n</span>]: <span class='ident'>u64</span> <span class='op'>=</span> <span class='number'>0</span>, <span class='number'>1</span> ... <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>])
</pre>
<p>the invocation arguments stored in the AST look something like:</p>
<pre><code class="language-{text}">[ `a` `[ ]` `:` `u64` `=` `0` `,` `1` `...` `a` `[ ]` `+` `a` `[ ]` ]
^ ^ |
[ `n` ] [ `n` `-` `1` ] ^
[ `n` `-` `2` ]
</code></pre>
<p>Sequences enclosed by parentheses, braces, or brackets become a single logical "token tree" node. This is how the parser keeps track of how deep into a macro invocation it is, and when to stop parsing it. This is <em>also</em> why your macro syntax must have balanced parens, braces, and brackets.</p>
<p>When it comes time to expand a macro invocation, the compiler feeds the parsed token trees into the macro, which must expand to a new sequence of token trees which can be parsed as an AST node that matches the invocation's position. In other words, if you have a macro invocation in expression position, the token trees which it expands to <em>must</em> be parseable as an expression.</p>
<p>This means that not only is <em>where</em> you can use a macro restricted, you also <em>cannot</em> have a macro which expands to something that isn't a complete, valid Rust construct.</p>
<h1 id="construction" class='section-header'><a
href="#construction">2 Construction</a></h1>
<p>Usually, when working on a new macro, the first thing I do is decide what the macro invocation should look like. In this specific case, my first attempt looked like this:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='comment'>/*
let fib = recurrence![a[n] = 0, 1, ..., a[n-1] + a[n-2]];
for e in fib.take(10) { println!("{}", e) }
*/</span>
</pre>
<p>From that, we can take a stab at how the macro should be defined, even if we aren't sure of the actual expansion. This is useful because if you can't figure out how to parse the input syntax, then <em>maybe</em> you need to change it.</p>
<pre id='rust-example-rendered' class='rust '>
<span class='macro'>macro_rules</span><span class='macro'>!</span> <span class='ident'>recurrence</span> {
( <span class='ident'>a</span>[<span class='ident'>n</span>] <span class='op'>=</span> $(<span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>inits</span>:<span class='ident'>expr</span>),<span class='op'>+</span> , ... , <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>recur</span>:<span class='ident'>expr</span> ) <span class='op'>=></span> { <span class='comment'>/* ... */</span> };
}
</pre>
<p>Assuming you aren't familiar with the syntax, allow me to elucidate. This is defining a macro using the <code>macro_rules</code> machinery (there is one other way to define macros, but we'll come back to that) called <code>recurrence</code>. This macro has a single parsing rule. That rule says the input to the macro must match:</p>
<ul>
<li>the literal token sequence <code>a [ n ] =</code>,</li>
<li>a repeating (the <code>$( ... )</code>) sequence, using <code>,</code> as a separator, and one or more (<code>+</code>) repeats of:
<ul>
<li>a valid <em>expression</em> captured into the variable <code>inits</code> (<code>$inits:expr</code>)</li>
</ul></li>
<li>the literal token sequence <code>, ... ,</code>,</li>
<li>a valid <em>expression</em> captured into the variable <code>recur</code> (<code>$recur:expr</code>).</li>
</ul>
<p>Finally, the rule says that <em>if</em> the input matches this rule, then the macro invocation should be replaced by the token sequence <code>/* ... */</code>.</p>
<p>It's worth noting that <code>inits</code>, as implied by the name, actually contains <em>all</em> the expressions that match in this position, not just the first or last. What's more, it captures them <em>as a sequence</em> as opposed to, say, irreversibly pasting them all together. Also note that you can do "zero or more" with a repetition by using <code>*</code> instead of <code>+</code>.</p>
<p>As an exercise, let's take the proposed input and feed it through the rule, to see how it is processed. The "Position" column will show which part of the syntax pattern needs to be matched against next, denoted by a "⌂". Note that in some cases, there might be more than one possible "next" element to match against. "Input" will contain all of the tokens that have <em>not</em> been consumed yet. <code>inits</code> and <code>recur</code> will contain the contents of those bindings.</p>
<table class="parse-table">
<thead>
<tr>
<th>Position</th>
<th>Input</th>
<th><code>inits</code></th>
<th><code>recur</code></th>
</tr>
</thead>
<tbody class="small-code">
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code>⌂</code></td>
<td><code>a[n] = 0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>[n] = 0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>n] = 0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>] = 0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>= 0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>0, 1, ..., a[n-1] + a[n-2]</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂ ⌂</code></td>
<td><code>, 1, ..., a[n-1] + a[n-2]</code></td>
<td><code>0</code></td>
<td></td>
</tr>
<tr>
<td colspan="4" style="font-size:.7em;"><em>Note</em>: there are two ⌂ here, because
a comma could mean <em>either</em> another element in the
repetition, <em>or</em> the comma <em>after</em> the
repetition.</td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂ ⌂</code></td>
<td><code>1, ..., a[n-1] + a[n-2]</code></td>
<td><code>0</code></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂ ⌂</code></td>
<td><code>, ..., a[n-1] + a[n-2]</code></td>
<td><code>0</code>, <code>1</code></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂ ⌂</code></td>
<td><code>..., a[n-1] + a[n-2]</code></td>
<td><code>0</code>, <code>1</code></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>, a[n-1] + a[n-2]</code></td>
<td><code>0</code>, <code>1</code></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td><code>a[n-1] + a[n-2]</code></td>
<td><code>0</code>, <code>1</code></td>
<td></td>
</tr>
<tr>
<td><code>a[n] = $($inits:expr),+ , ... , $recur:expr</code>
<code> ⌂</code></td>
<td></td>
<td><code>0</code>, <code>1</code></td>
<td><code>a[n-1] + a[n-2]</code></td>
</tr>
</tbody>
</table>
<p>Now, let's begin writing the final, fully expanded form. For this expansion, I was looking for something like:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>let</span> <span class='ident'>fib</span> <span class='op'>=</span> {
<span class='kw'>struct</span> <span class='ident'>Recurrence</span> {
<span class='ident'>mem</span>: [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>pos</span>: <span class='ident'>uint</span>,
}
</pre>
<p>This will be the actual iterator type. <code>mem</code> will be the memo buffer to hold the last few values so the recurrence can be computed. <code>pos</code> is to keep track of the value of <code>n</code>.</p>
<blockquote>
<p><strong>Aside</strong>: I've chosen <code>u64</code> as a "sufficiently large" type for the elements of this sequence. Don't worry about how this will work out for <em>other</em> sequences; we'll come to it.</p>
</blockquote>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>impl</span> <span class='ident'>Iterator</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>Recurrence</span> {
<span class='attribute'>#[<span class='ident'>inline</span>]</span>
<span class='kw'>fn</span> <span class='ident'>next</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>) <span class='op'>-></span> <span class='prelude-ty'>Option</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> {
<span class='kw'>if</span> <span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'><</span> <span class='number'>2</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='self'>self</span>.<span class='ident'>pos</span>];
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
</pre>
<p>We need a branch to yield the initial values of the sequence; nothing tricky.</p>
<pre id='rust-example-rendered' class='rust '>
} <span class='kw'>else</span> {
<span class='kw'>let</span> <span class='ident'>a</span> <span class='op'>=</span> <span class='comment'>/* something */</span>;
<span class='kw'>let</span> <span class='ident'>n</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>pos</span>;
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> (<span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>]);
<span class='self'>self</span>.<span class='ident'>mem</span>.<span class='ident'>TODO_shuffle_down_and_append</span>(<span class='ident'>next_val</span>);
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
}
}
}
</pre>
<p>This is a bit harder; we'll come back and look at <em>how</em> exactly to define <code>a</code>. Also, <code>TODO_shuffle_down_and_append</code> is another placeholder; I want something that places <code>next_val</code> on the end of the array, shuffling the rest down by one space, dropping the 0th element.</p>
<pre id='rust-example-rendered' class='rust '>
<span class='ident'>Recurrence</span> { <span class='ident'>mem</span>: [<span class='number'>0</span>, <span class='number'>1</span>], <span class='ident'>pos</span>: <span class='number'>0</span> }
};
<span class='kw'>for</span> <span class='ident'>e</span> <span class='kw'>in</span> <span class='ident'>fib</span>.<span class='ident'>take</span>(<span class='number'>10</span>) { <span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>e</span>) }
</pre>
<p>Lastly, return an instance of our new structure, which can then be iterated over. The complete expansion is:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>let</span> <span class='ident'>fib</span> <span class='op'>=</span> {
<span class='kw'>struct</span> <span class='ident'>Recurrence</span> {
<span class='ident'>mem</span>: [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>pos</span>: <span class='ident'>uint</span>,
}
<span class='kw'>impl</span> <span class='ident'>Iterator</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>Recurrence</span> {
<span class='attribute'>#[<span class='ident'>inline</span>]</span>
<span class='kw'>fn</span> <span class='ident'>next</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>) <span class='op'>-></span> <span class='prelude-ty'>Option</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> {
<span class='kw'>if</span> <span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'><</span> <span class='number'>2</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='self'>self</span>.<span class='ident'>pos</span>];
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
} <span class='kw'>else</span> {
<span class='kw'>let</span> <span class='ident'>a</span> <span class='op'>=</span> <span class='comment'>/* something */</span>;
<span class='kw'>let</span> <span class='ident'>n</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>pos</span>;
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> (<span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>]);
<span class='self'>self</span>.<span class='ident'>mem</span>.<span class='ident'>TODO_shuffle_down_and_append</span>(<span class='ident'>next_val</span>.<span class='ident'>clone</span>());
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
}
}
}
<span class='ident'>Recurrence</span> { <span class='ident'>mem</span>: [<span class='number'>0</span>, <span class='number'>1</span>], <span class='ident'>pos</span>: <span class='number'>0</span> }
};
<span class='kw'>for</span> <span class='ident'>e</span> <span class='kw'>in</span> <span class='ident'>fib</span>.<span class='ident'>take</span>(<span class='number'>10</span>) { <span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>e</span>) }
</pre>
<blockquote>
<p><strong>Aside</strong>: Yes, this <em>does</em> mean we're defining a different <code>Recurrence</code> struct and its implementation for each macro invocation. Most of this will optimise away in the final binary, with some judicious use of <code>#[inline]</code> attributes.</p>
</blockquote>
<p>It's also useful to check your expansion as you're writing it. If you see anything in the expansion that needs to vary with the invocation, but <em>isn't</em> in the actual macro syntax, you should work out where to introduce it. In this case, we've added <code>u64</code>, but that's not neccesarily what the user wants, nor is it in the macro syntax. So let's fix that.</p>
<pre id='rust-example-rendered' class='rust '>
<span class='macro'>macro_rules</span><span class='macro'>!</span> <span class='ident'>recurrence</span> {
( <span class='ident'>a</span>[<span class='ident'>n</span>]: <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>sty</span>:<span class='ident'>ty</span> <span class='op'>=</span> $(<span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>inits</span>:<span class='ident'>expr</span>),<span class='op'>+</span> , ... , <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>recur</span>:<span class='ident'>expr</span> ) <span class='op'>=></span> { <span class='comment'>/* ... */</span> };
}
<span class='comment'>/*
let fib = recurrence![a[n]: u64 = 0, 1, ..., a[n-1] + a[n-2]];
for e in fib.take(10) { println!("{}", e) }
*/</span>
</pre>
<p>Here, I've added a new capture: <code>sty</code> which should be a type.</p>
<blockquote>
<p><strong>Aside</strong>: if you're wondering, the bit after the colon in a capture can be any of the following:</p>
<ul>
<li><code>item</code>: an item, like a function, struct, module, etc.</li>
<li><code>block</code>: a block (<em>i.e.</em> a block of statments and/or an expression, surrounded by braces)</li>
<li><code>stmt</code>: a statement</li>
<li><code>pat</code>: a pattern</li>
<li><code>expr</code>: an expression</li>
<li><code>ty</code>: a type</li>
<li><code>ident</code>: an identifier</li>
<li><code>path</code>: a path (<em>e.g.</em> <code>foo</code>, <code>::std::mem::replace</code>, <code>transmute::<_, int></code>, ...)</li>
<li><code>meta</code>: a meta item; the things that go inside <code>#[...]</code> and <code>#![...]</code> attributes</li>
<li><code>tt</code>: a single token tree</li>
<li><code>matchers</code>: a matching pair of tokens; <code>(...)</code>, <code>{...}</code>, or <code>[...]</code></li>
</ul>
</blockquote>
<h1 id="indexing-and-shuffling" class='section-header'><a
href="#indexing-and-shuffling">3 Indexing and Shuffling</a></h1>
<p>I will skim a bit over this part, since it's effectively tangential to the macro stuff. We want to make it so that whatever <code>a</code> is, we can index it directly, and it will act as a sliding window keeping the last few (in this case, 2) elements of the sequence.</p>
<p>We can do this pretty easily with a wrapper type:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>struct</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='lifetime'>'a</span> [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>offset</span>: <span class='ident'>uint</span>,
}
<span class='kw'>impl</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> <span class='ident'>Index</span><span class='op'><</span><span class='ident'>uint</span>, <span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='attribute'>#[<span class='ident'>inline</span>(<span class='ident'>always</span>)]</span>
<span class='kw'>fn</span> <span class='ident'>index</span><span class='op'><</span><span class='lifetime'>'b</span><span class='op'>></span>(<span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='self'>self</span>, <span class='ident'>index</span>: <span class='kw-2'>&</span><span class='ident'>uint</span>) <span class='op'>-></span> <span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='ident'>u64</span> {
<span class='kw'>let</span> <span class='ident'>real_index</span> <span class='op'>=</span> <span class='op'>*</span><span class='ident'>index</span> <span class='op'>-</span> <span class='self'>self</span>.<span class='ident'>offset</span> <span class='op'>+</span> <span class='number'>2</span>;
<span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>slice</span>[<span class='ident'>real_index</span>]
}
}
</pre>
<blockquote>
<p><strong>Aside</strong>: since lifetimes come up <em>a lot</em> with people new to Rust, a quick explanation: <code>'a</code> and <code>'b</code> are lifetime parameters that are used to track where a reference (<em>i.e.</em> a borrowed pointer to some data) is valid. In this case, <code>IndexOffset</code> borrows a reference to our iterator's data, so it needs to keep track of how long it's allowed to hold that reference for, using <code>'a</code>.</p>
<p><code>'b</code> is used because the <code>Index</code> trait (which is how subscript syntax is actually implemented) is <em>also</em> parameterised on a lifetime, on account of returning a borrowed reference. <code>'a</code> and <code>'b</code> are not necessarily the same thing in all cases. The borrow checker will make sure that even though we don't explicitly relate <code>'a</code> and <code>'b</code> to one another, we don't accidentally violate memory safety.</p>
</blockquote>
<p>This changes the definition of <code>a</code> to:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='kw'>let</span> <span class='ident'>a</span> <span class='op'>=</span> <span class='ident'>IndexOffset</span> { <span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>mem</span>, <span class='ident'>offset</span>: <span class='ident'>n</span> };
</pre>
<p>The only remaining question is what to do about <code>TODO_shuffle_down_and_append</code>. I wasn't able to find a method in the standard library with exactly the semantics I wanted, but it isn't hard to do by hand.</p>
<pre id='rust-example-rendered' class='rust '>
{
<span class='kw'>use</span> <span class='ident'>std</span>::<span class='ident'>mem</span>::<span class='ident'>swap</span>;
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span> <span class='op'>=</span> <span class='ident'>next_val</span>;
<span class='kw'>for</span> <span class='ident'>i</span> <span class='kw'>in</span> <span class='ident'>range</span>(<span class='number'>0</span>, <span class='number'>2</span>).<span class='ident'>rev</span>() {
<span class='ident'>swap</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span>, <span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='ident'>i</span>]);
}
}
</pre>
<p>This swaps the new value into the end of the array, swapping the other elements down one space.</p>
<blockquote>
<p><strong>Aside</strong>: doing it this way means that this code will work for non-copyable types, as well, since they <em>can</em> be swapped.</p>
</blockquote>
<p>The complete expansion now looks like this:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='attribute'>#<span class='op'>!</span>[<span class='ident'>feature</span>(<span class='ident'>macro_rules</span>)]</span>
<span class='macro'>macro_rules</span><span class='macro'>!</span> <span class='ident'>recurrence</span> {
( <span class='ident'>a</span>[<span class='ident'>n</span>]: <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>sty</span>:<span class='ident'>ty</span> <span class='op'>=</span> $(<span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>inits</span>:<span class='ident'>expr</span>),<span class='op'>+</span> , ... , <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>recur</span>:<span class='ident'>expr</span> ) <span class='op'>=></span> { <span class='comment'>/* ... */</span> };
}
<span class='kw'>fn</span> <span class='ident'>main</span>() {
<span class='comment'>/*
let fib = recurrence![a[n]: u64 = 0, 1, ..., a[n-1] + a[n-2]];
for e in fib.take(10) { println!("{}", e) }
*/</span>
<span class='kw'>let</span> <span class='ident'>fib</span> <span class='op'>=</span> {
<span class='kw'>struct</span> <span class='ident'>Recurrence</span> {
<span class='ident'>mem</span>: [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>pos</span>: <span class='ident'>uint</span>,
}
<span class='kw'>struct</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='lifetime'>'a</span> [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>offset</span>: <span class='ident'>uint</span>,
}
<span class='kw'>impl</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> <span class='ident'>Index</span><span class='op'><</span><span class='ident'>uint</span>, <span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='attribute'>#[<span class='ident'>inline</span>(<span class='ident'>always</span>)]</span>
<span class='kw'>fn</span> <span class='ident'>index</span><span class='op'><</span><span class='lifetime'>'b</span><span class='op'>></span>(<span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='self'>self</span>, <span class='ident'>index</span>: <span class='kw-2'>&</span><span class='ident'>uint</span>) <span class='op'>-></span> <span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='ident'>u64</span> {
<span class='kw'>let</span> <span class='ident'>real_index</span> <span class='op'>=</span> <span class='op'>*</span><span class='ident'>index</span> <span class='op'>-</span> <span class='self'>self</span>.<span class='ident'>offset</span> <span class='op'>+</span> <span class='number'>2</span>;
<span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>slice</span>[<span class='ident'>real_index</span>]
}
}
<span class='kw'>impl</span> <span class='ident'>Iterator</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>Recurrence</span> {
<span class='attribute'>#[<span class='ident'>inline</span>]</span>
<span class='kw'>fn</span> <span class='ident'>next</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>) <span class='op'>-></span> <span class='prelude-ty'>Option</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> {
<span class='kw'>if</span> <span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'><</span> <span class='number'>2</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='self'>self</span>.<span class='ident'>pos</span>];
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
} <span class='kw'>else</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> {
<span class='kw'>let</span> <span class='ident'>n</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>pos</span>;
<span class='kw'>let</span> <span class='ident'>a</span> <span class='op'>=</span> <span class='ident'>IndexOffset</span> { <span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>mem</span>, <span class='ident'>offset</span>: <span class='ident'>n</span> };
(<span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>])
};
{
<span class='kw'>use</span> <span class='ident'>std</span>::<span class='ident'>mem</span>::<span class='ident'>swap</span>;
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span> <span class='op'>=</span> <span class='ident'>next_val</span>;
<span class='kw'>for</span> <span class='ident'>i</span> <span class='kw'>in</span> <span class='ident'>range</span>(<span class='number'>0</span>, <span class='number'>2</span>).<span class='ident'>rev</span>() {
<span class='ident'>swap</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span>, <span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='ident'>i</span>]);
}
}
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
}
}
}
<span class='ident'>Recurrence</span> { <span class='ident'>mem</span>: [<span class='number'>0</span>, <span class='number'>1</span>], <span class='ident'>pos</span>: <span class='number'>0</span> }
};
<span class='kw'>for</span> <span class='ident'>e</span> <span class='kw'>in</span> <span class='ident'>fib</span>.<span class='ident'>take</span>(<span class='number'>10</span>) { <span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>e</span>) }
}
</pre>
<p>Note that I've changed the order of the declarations of <code>n</code> and <code>a</code>, as well as wrapped them (along with the recurrence expression) in a block. The reason for the first should be obvious (<code>n</code> needs to be defined first so I can use it for <code>a</code>). The reason for the second is that the borrowed reference <code>&self.mem</code> will prevent the swaps later on from happening (you cannot mutate something that is aliased elsewhere). The block ensures that the <code>&self.mem</code> borrow expires before then.</p>
<p>Incidentally, the only reason the code that does the <code>mem</code> swaps is in a block is to narrow the scope in which <code>std::mem::swap</code> is available, for the sake of being tidy.</p>
<p>If we take this code and run it, we get:</p>
<pre><code class="language-{text}">0
1
1
2
3
5
8
13
21
34
</code></pre>
<p>Success! Now, let's copy & paste this into the macro expansion, and replace the expanded code with an invocation. This gives us:</p>
<pre id='rust-example-rendered' class='rust '>
<span class='attribute'>#<span class='op'>!</span>[<span class='ident'>feature</span>(<span class='ident'>macro_rules</span>)]</span>
<span class='macro'>macro_rules</span><span class='macro'>!</span> <span class='ident'>recurrence</span> {
( <span class='ident'>a</span>[<span class='ident'>n</span>]: <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>sty</span>:<span class='ident'>ty</span> <span class='op'>=</span> $(<span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>inits</span>:<span class='ident'>expr</span>),<span class='op'>+</span> , ... , <span class='macro-nonterminal'>$</span><span class='macro-nonterminal'>recur</span>:<span class='ident'>expr</span> ) <span class='op'>=></span> {
{
<span class='kw'>struct</span> <span class='ident'>Recurrence</span> {
<span class='ident'>mem</span>: [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>pos</span>: <span class='ident'>uint</span>,
}
<span class='kw'>struct</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='lifetime'>'a</span> [<span class='ident'>u64</span>, ..<span class='number'>2</span>],
<span class='ident'>offset</span>: <span class='ident'>uint</span>,
}
<span class='kw'>impl</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> <span class='ident'>Index</span><span class='op'><</span><span class='ident'>uint</span>, <span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>IndexOffset</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> {
<span class='attribute'>#[<span class='ident'>inline</span>(<span class='ident'>always</span>)]</span>
<span class='kw'>fn</span> <span class='ident'>index</span><span class='op'><</span><span class='lifetime'>'b</span><span class='op'>></span>(<span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='self'>self</span>, <span class='ident'>index</span>: <span class='kw-2'>&</span><span class='ident'>uint</span>) <span class='op'>-></span> <span class='kw-2'>&</span><span class='lifetime'>'b</span> <span class='ident'>u64</span> {
<span class='kw'>let</span> <span class='ident'>real_index</span> <span class='op'>=</span> <span class='op'>*</span><span class='ident'>index</span> <span class='op'>-</span> <span class='self'>self</span>.<span class='ident'>offset</span> <span class='op'>+</span> <span class='number'>2</span>;
<span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>slice</span>[<span class='ident'>real_index</span>]
}
}
<span class='kw'>impl</span> <span class='ident'>Iterator</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> <span class='kw'>for</span> <span class='ident'>Recurrence</span> {
<span class='attribute'>#[<span class='ident'>inline</span>]</span>
<span class='kw'>fn</span> <span class='ident'>next</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>) <span class='op'>-></span> <span class='prelude-ty'>Option</span><span class='op'><</span><span class='ident'>u64</span><span class='op'>></span> {
<span class='kw'>if</span> <span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'><</span> <span class='number'>2</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='self'>self</span>.<span class='ident'>pos</span>];
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
} <span class='kw'>else</span> {
<span class='kw'>let</span> <span class='ident'>next_val</span> <span class='op'>=</span> {
<span class='kw'>let</span> <span class='ident'>n</span> <span class='op'>=</span> <span class='self'>self</span>.<span class='ident'>pos</span>;
<span class='kw'>let</span> <span class='ident'>a</span> <span class='op'>=</span> <span class='ident'>IndexOffset</span> { <span class='ident'>slice</span>: <span class='kw-2'>&</span><span class='self'>self</span>.<span class='ident'>mem</span>, <span class='ident'>offset</span>: <span class='ident'>n</span> };
(<span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>1</span>] <span class='op'>+</span> <span class='ident'>a</span>[<span class='ident'>n</span><span class='op'>-</span><span class='number'>2</span>])
};
{
<span class='kw'>use</span> <span class='ident'>std</span>::<span class='ident'>mem</span>::<span class='ident'>swap</span>;
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span> <span class='op'>=</span> <span class='ident'>next_val</span>;
<span class='kw'>for</span> <span class='ident'>i</span> <span class='kw'>in</span> <span class='ident'>range</span>(<span class='number'>0</span>, <span class='number'>2</span>).<span class='ident'>rev</span>() {
<span class='ident'>swap</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='ident'>swap_tmp</span>, <span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>.<span class='ident'>mem</span>[<span class='ident'>i</span>]);
}
}
<span class='self'>self</span>.<span class='ident'>pos</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='prelude-val'>Some</span>(<span class='ident'>next_val</span>)
}
}
}
<span class='ident'>Recurrence</span> { <span class='ident'>mem</span>: [<span class='number'>0</span>, <span class='number'>1</span>], <span class='ident'>pos</span>: <span class='number'>0</span> }
}
};