1
2#[macro_export]
24macro_rules! unroll {
25 (for $v:ident in 0..0 $c:block) => {};
26
27 (for $v:ident < $max:tt in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => {
28 {
29 let step = $val;
30 let start = $start;
31 let end = start + ($end - start) / step;
32 unroll! {
33 for val < $max in start..end {
34 let $v: usize = ((val - start) * step) + start;
35
36 $($c)*
37 }
38 }
39 }
40 };
41
42 (for $v:ident in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => {
43 unroll! {
44 for $v < $end in ($start..$end).step_by($val) {$($c)*}
45 }
46 };
47
48 (for $v:ident in ($start:tt..$end:tt) {$($c:tt)*}) => {
49 unroll!{
50 for $v in $start..$end {$($c)*}
51 }
52 };
53
54 (for $v:ident in $start:tt..$end:tt {$($c:tt)*}) => {
55 #[allow(non_upper_case_globals)]
56 #[allow(unused_comparisons)]
57 {
58 unroll!(@$v, 0, $end, {
59 if $v >= $start {$($c)*}
60 }
61 );
62 }
63 };
64
65 (for $v:ident < $max:tt in $start:tt..$end:tt $c:block) => {
66 #[allow(non_upper_case_globals)]
67 {
68 let range = $start..$end;
69 assert!(
70 $max >= range.end,
71 "`{}` out of range `{:?}`",
72 stringify!($max),
73 range,
74 );
75 unroll!(
76 @$v,
77 0,
78 $max,
79 {
80 if $v >= range.start && $v < range.end {
81 $c
82 }
83 }
84 );
85 }
86 };
87
88 (for $v:ident in 0..$end:tt {$($statement:tt)*}) => {
89 #[allow(non_upper_case_globals)]
90 { unroll!(@$v, 0, $end, {$($statement)*}); }
91 };
92
93 (@$v:ident, $a:expr, 0, $c:block) => {
94 { const $v: usize = $a; $c }
95 };
96
97 (@$v:ident, $a:expr, 1, $c:block) => {
98 { const $v: usize = $a; $c }
99 };
100
101 (@$v:ident, $a:expr, 2, $c:block) => {
102 { const $v: usize = $a; $c }
103 { const $v: usize = $a + 1; $c }
104 };
105
106 (@$v:ident, $a:expr, 3, $c:block) => {
107 { const $v: usize = $a; $c }
108 { const $v: usize = $a + 1; $c }
109 { const $v: usize = $a + 2; $c }
110 };
111
112 (@$v:ident, $a:expr, 4, $c:block) => {
113 { const $v: usize = $a; $c }
114 { const $v: usize = $a + 1; $c }
115 { const $v: usize = $a + 2; $c }
116 { const $v: usize = $a + 3; $c }
117 };
118
119 (@$v:ident, $a:expr, 5, $c:block) => {
120 { const $v: usize = $a; $c }
121 { const $v: usize = $a + 1; $c }
122 { const $v: usize = $a + 2; $c }
123 { const $v: usize = $a + 3; $c }
124 { const $v: usize = $a + 4; $c }
125 };
126
127 (@$v:ident, $a:expr, 6, $c:block) => {
128 { const $v: usize = $a; $c }
129 { const $v: usize = $a + 1; $c }
130 { const $v: usize = $a + 2; $c }
131 { const $v: usize = $a + 3; $c }
132 { const $v: usize = $a + 4; $c }
133 { const $v: usize = $a + 5; $c }
134 };
135
136 (@$v:ident, $a:expr, 7, $c:block) => {
137 { const $v: usize = $a; $c }
138 { const $v: usize = $a + 1; $c }
139 { const $v: usize = $a + 2; $c }
140 { const $v: usize = $a + 3; $c }
141 { const $v: usize = $a + 4; $c }
142 { const $v: usize = $a + 5; $c }
143 { const $v: usize = $a + 6; $c }
144 };
145
146 (@$v:ident, $a:expr, 8, $c:block) => {
147 { const $v: usize = $a; $c }
148 { const $v: usize = $a + 1; $c }
149 { const $v: usize = $a + 2; $c }
150 { const $v: usize = $a + 3; $c }
151 { const $v: usize = $a + 4; $c }
152 { const $v: usize = $a + 5; $c }
153 { const $v: usize = $a + 6; $c }
154 { const $v: usize = $a + 7; $c }
155 };
156
157 (@$v:ident, $a:expr, 9, $c:block) => {
158 { const $v: usize = $a; $c }
159 { const $v: usize = $a + 1; $c }
160 { const $v: usize = $a + 2; $c }
161 { const $v: usize = $a + 3; $c }
162 { const $v: usize = $a + 4; $c }
163 { const $v: usize = $a + 5; $c }
164 { const $v: usize = $a + 6; $c }
165 { const $v: usize = $a + 7; $c }
166 { const $v: usize = $a + 8; $c }
167 };
168
169 (@$v:ident, $a:expr, 10, $c:block) => {
170 { const $v: usize = $a; $c }
171 { const $v: usize = $a + 1; $c }
172 { const $v: usize = $a + 2; $c }
173 { const $v: usize = $a + 3; $c }
174 { const $v: usize = $a + 4; $c }
175 { const $v: usize = $a + 5; $c }
176 { const $v: usize = $a + 6; $c }
177 { const $v: usize = $a + 7; $c }
178 { const $v: usize = $a + 8; $c }
179 { const $v: usize = $a + 9; $c }
180 };
181
182 (@$v:ident, $a:expr, 11, $c:block) => {
183 { const $v: usize = $a; $c }
184 { const $v: usize = $a + 1; $c }
185 { const $v: usize = $a + 2; $c }
186 { const $v: usize = $a + 3; $c }
187 { const $v: usize = $a + 4; $c }
188 { const $v: usize = $a + 5; $c }
189 { const $v: usize = $a + 6; $c }
190 { const $v: usize = $a + 7; $c }
191 { const $v: usize = $a + 8; $c }
192 { const $v: usize = $a + 9; $c }
193 { const $v: usize = $a + 10; $c }
194 };
195
196 (@$v:ident, $a:expr, 12, $c:block) => {
197 { const $v: usize = $a; $c }
198 { const $v: usize = $a + 1; $c }
199 { const $v: usize = $a + 2; $c }
200 { const $v: usize = $a + 3; $c }
201 { const $v: usize = $a + 4; $c }
202 { const $v: usize = $a + 5; $c }
203 { const $v: usize = $a + 6; $c }
204 { const $v: usize = $a + 7; $c }
205 { const $v: usize = $a + 8; $c }
206 { const $v: usize = $a + 9; $c }
207 { const $v: usize = $a + 10; $c }
208 { const $v: usize = $a + 11; $c }
209 };
210
211 (@$v:ident, $a:expr, 13, $c:block) => {
212 { const $v: usize = $a; $c }
213 { const $v: usize = $a + 1; $c }
214 { const $v: usize = $a + 2; $c }
215 { const $v: usize = $a + 3; $c }
216 { const $v: usize = $a + 4; $c }
217 { const $v: usize = $a + 5; $c }
218 { const $v: usize = $a + 6; $c }
219 { const $v: usize = $a + 7; $c }
220 { const $v: usize = $a + 8; $c }
221 { const $v: usize = $a + 9; $c }
222 { const $v: usize = $a + 10; $c }
223 { const $v: usize = $a + 11; $c }
224 { const $v: usize = $a + 12; $c }
225 };
226
227 (@$v:ident, $a:expr, 14, $c:block) => {
228 { const $v: usize = $a; $c }
229 { const $v: usize = $a + 1; $c }
230 { const $v: usize = $a + 2; $c }
231 { const $v: usize = $a + 3; $c }
232 { const $v: usize = $a + 4; $c }
233 { const $v: usize = $a + 5; $c }
234 { const $v: usize = $a + 6; $c }
235 { const $v: usize = $a + 7; $c }
236 { const $v: usize = $a + 8; $c }
237 { const $v: usize = $a + 9; $c }
238 { const $v: usize = $a + 10; $c }
239 { const $v: usize = $a + 11; $c }
240 { const $v: usize = $a + 12; $c }
241 { const $v: usize = $a + 13; $c }
242 };
243
244 (@$v:ident, $a:expr, 15, $c:block) => {
245 { const $v: usize = $a; $c }
246 { const $v: usize = $a + 1; $c }
247 { const $v: usize = $a + 2; $c }
248 { const $v: usize = $a + 3; $c }
249 { const $v: usize = $a + 4; $c }
250 { const $v: usize = $a + 5; $c }
251 { const $v: usize = $a + 6; $c }
252 { const $v: usize = $a + 7; $c }
253 { const $v: usize = $a + 8; $c }
254 { const $v: usize = $a + 9; $c }
255 { const $v: usize = $a + 10; $c }
256 { const $v: usize = $a + 11; $c }
257 { const $v: usize = $a + 12; $c }
258 { const $v: usize = $a + 13; $c }
259 { const $v: usize = $a + 14; $c }
260 };
261
262 (@$v:ident, $a:expr, 16, $c:block) => {
263 { const $v: usize = $a; $c }
264 { const $v: usize = $a + 1; $c }
265 { const $v: usize = $a + 2; $c }
266 { const $v: usize = $a + 3; $c }
267 { const $v: usize = $a + 4; $c }
268 { const $v: usize = $a + 5; $c }
269 { const $v: usize = $a + 6; $c }
270 { const $v: usize = $a + 7; $c }
271 { const $v: usize = $a + 8; $c }
272 { const $v: usize = $a + 9; $c }
273 { const $v: usize = $a + 10; $c }
274 { const $v: usize = $a + 11; $c }
275 { const $v: usize = $a + 12; $c }
276 { const $v: usize = $a + 13; $c }
277 { const $v: usize = $a + 14; $c }
278 { const $v: usize = $a + 15; $c }
279 };
280
281 (@$v:ident, $a:expr, 17, $c:block) => {
282 unroll!(@$v, $a, 16, $c);
283 { const $v: usize = $a + 16; $c }
284 };
285
286 (@$v:ident, $a:expr, 18, $c:block) => {
287 unroll!(@$v, $a, 9, $c);
288 unroll!(@$v, $a + 9, 9, $c);
289 };
290
291 (@$v:ident, $a:expr, 19, $c:block) => {
292 unroll!(@$v, $a, 18, $c);
293 { const $v: usize = $a + 18; $c }
294 };
295
296 (@$v:ident, $a:expr, 20, $c:block) => {
297 unroll!(@$v, $a, 10, $c);
298 unroll!(@$v, $a + 10, 10, $c);
299 };
300
301 (@$v:ident, $a:expr, 21, $c:block) => {
302 unroll!(@$v, $a, 20, $c);
303 { const $v: usize = $a + 20; $c }
304 };
305
306 (@$v:ident, $a:expr, 22, $c:block) => {
307 unroll!(@$v, $a, 11, $c);
308 unroll!(@$v, $a + 11, 11, $c);
309 };
310
311 (@$v:ident, $a:expr, 23, $c:block) => {
312 unroll!(@$v, $a, 22, $c);
313 { const $v: usize = $a + 22; $c }
314 };
315
316 (@$v:ident, $a:expr, 24, $c:block) => {
317 unroll!(@$v, $a, 12, $c);
318 unroll!(@$v, $a + 12, 12, $c);
319 };
320
321 (@$v:ident, $a:expr, 25, $c:block) => {
322 unroll!(@$v, $a, 24, $c);
323 { const $v: usize = $a + 24; $c }
324 };
325
326 (@$v:ident, $a:expr, 26, $c:block) => {
327 unroll!(@$v, $a, 13, $c);
328 unroll!(@$v, $a + 13, 13, $c);
329 };
330
331 (@$v:ident, $a:expr, 27, $c:block) => {
332 unroll!(@$v, $a, 26, $c);
333 { const $v: usize = $a + 26; $c }
334 };
335
336 (@$v:ident, $a:expr, 28, $c:block) => {
337 unroll!(@$v, $a, 14, $c);
338 unroll!(@$v, $a + 14, 14, $c);
339 };
340
341 (@$v:ident, $a:expr, 29, $c:block) => {
342 unroll!(@$v, $a, 28, $c);
343 { const $v: usize = $a + 28; $c }
344 };
345
346 (@$v:ident, $a:expr, 30, $c:block) => {
347 unroll!(@$v, $a, 15, $c);
348 unroll!(@$v, $a + 15, 15, $c);
349 };
350
351 (@$v:ident, $a:expr, 31, $c:block) => {
352 unroll!(@$v, $a, 30, $c);
353 { const $v: usize = $a + 30; $c }
354 };
355
356 (@$v:ident, $a:expr, 32, $c:block) => {
357 unroll!(@$v, $a, 16, $c);
358 unroll!(@$v, $a + 16, 16, $c);
359 };
360
361 (@$v:ident, $a:expr, 33, $c:block) => {
362 unroll!(@$v, $a, 32, $c);
363 { const $v: usize = $a + 32; $c }
364 };
365
366 (@$v:ident, $a:expr, 34, $c:block) => {
367 unroll!(@$v, $a, 17, $c);
368 unroll!(@$v, $a + 17, 17, $c);
369 };
370
371 (@$v:ident, $a:expr, 35, $c:block) => {
372 unroll!(@$v, $a, 34, $c);
373 { const $v: usize = $a + 34; $c }
374 };
375
376 (@$v:ident, $a:expr, 36, $c:block) => {
377 unroll!(@$v, $a, 18, $c);
378 unroll!(@$v, $a + 18, 18, $c);
379 };
380
381 (@$v:ident, $a:expr, 37, $c:block) => {
382 unroll!(@$v, $a, 36, $c);
383 { const $v: usize = $a + 36; $c }
384 };
385
386 (@$v:ident, $a:expr, 38, $c:block) => {
387 unroll!(@$v, $a, 19, $c);
388 unroll!(@$v, $a + 19, 19, $c);
389 };
390
391 (@$v:ident, $a:expr, 39, $c:block) => {
392 unroll!(@$v, $a, 38, $c);
393 { const $v: usize = $a + 38; $c }
394 };
395
396 (@$v:ident, $a:expr, 40, $c:block) => {
397 unroll!(@$v, $a, 20, $c);
398 unroll!(@$v, $a + 20, 20, $c);
399 };
400
401 (@$v:ident, $a:expr, 41, $c:block) => {
402 unroll!(@$v, $a, 40, $c);
403 { const $v: usize = $a + 40; $c }
404 };
405
406 (@$v:ident, $a:expr, 42, $c:block) => {
407 unroll!(@$v, $a, 21, $c);
408 unroll!(@$v, $a + 21, 21, $c);
409 };
410
411 (@$v:ident, $a:expr, 43, $c:block) => {
412 unroll!(@$v, $a, 42, $c);
413 { const $v: usize = $a + 42; $c }
414 };
415
416 (@$v:ident, $a:expr, 44, $c:block) => {
417 unroll!(@$v, $a, 22, $c);
418 unroll!(@$v, $a + 22, 22, $c);
419 };
420
421 (@$v:ident, $a:expr, 45, $c:block) => {
422 unroll!(@$v, $a, 44, $c);
423 { const $v: usize = $a + 44; $c }
424 };
425
426 (@$v:ident, $a:expr, 46, $c:block) => {
427 unroll!(@$v, $a, 23, $c);
428 unroll!(@$v, $a + 23, 23, $c);
429 };
430
431 (@$v:ident, $a:expr, 47, $c:block) => {
432 unroll!(@$v, $a, 46, $c);
433 { const $v: usize = $a + 46; $c }
434 };
435
436 (@$v:ident, $a:expr, 48, $c:block) => {
437 unroll!(@$v, $a, 24, $c);
438 unroll!(@$v, $a + 24, 24, $c);
439 };
440
441 (@$v:ident, $a:expr, 49, $c:block) => {
442 unroll!(@$v, $a, 48, $c);
443 { const $v: usize = $a + 48; $c }
444 };
445
446 (@$v:ident, $a:expr, 50, $c:block) => {
447 unroll!(@$v, $a, 25, $c);
448 unroll!(@$v, $a + 25, 25, $c);
449 };
450
451 (@$v:ident, $a:expr, 51, $c:block) => {
452 unroll!(@$v, $a, 50, $c);
453 { const $v: usize = $a + 50; $c }
454 };
455
456 (@$v:ident, $a:expr, 52, $c:block) => {
457 unroll!(@$v, $a, 26, $c);
458 unroll!(@$v, $a + 26, 26, $c);
459 };
460
461 (@$v:ident, $a:expr, 53, $c:block) => {
462 unroll!(@$v, $a, 52, $c);
463 { const $v: usize = $a + 52; $c }
464 };
465
466 (@$v:ident, $a:expr, 54, $c:block) => {
467 unroll!(@$v, $a, 27, $c);
468 unroll!(@$v, $a + 27, 27, $c);
469 };
470
471 (@$v:ident, $a:expr, 55, $c:block) => {
472 unroll!(@$v, $a, 54, $c);
473 { const $v: usize = $a + 54; $c }
474 };
475
476 (@$v:ident, $a:expr, 56, $c:block) => {
477 unroll!(@$v, $a, 28, $c);
478 unroll!(@$v, $a + 28, 28, $c);
479 };
480
481 (@$v:ident, $a:expr, 57, $c:block) => {
482 unroll!(@$v, $a, 56, $c);
483 { const $v: usize = $a + 56; $c }
484 };
485
486 (@$v:ident, $a:expr, 58, $c:block) => {
487 unroll!(@$v, $a, 29, $c);
488 unroll!(@$v, $a + 29, 29, $c);
489 };
490
491 (@$v:ident, $a:expr, 59, $c:block) => {
492 unroll!(@$v, $a, 58, $c);
493 { const $v: usize = $a + 58; $c }
494 };
495
496 (@$v:ident, $a:expr, 60, $c:block) => {
497 unroll!(@$v, $a, 30, $c);
498 unroll!(@$v, $a + 30, 30, $c);
499 };
500
501 (@$v:ident, $a:expr, 61, $c:block) => {
502 unroll!(@$v, $a, 60, $c);
503 { const $v: usize = $a + 60; $c }
504 };
505
506 (@$v:ident, $a:expr, 62, $c:block) => {
507 unroll!(@$v, $a, 31, $c);
508 unroll!(@$v, $a + 31, 31, $c);
509 };
510
511 (@$v:ident, $a:expr, 63, $c:block) => {
512 unroll!(@$v, $a, 62, $c);
513 { const $v: usize = $a + 62; $c }
514 };
515
516 (@$v:ident, $a:expr, 64, $c:block) => {
517 unroll!(@$v, $a, 32, $c);
518 unroll!(@$v, $a + 32, 32, $c);
519 };
520
521}
522
523
524#[cfg(all(test, feature = "std"))]
525mod tests {
526 #[test]
527 fn invalid_range() {
528 let mut a: Vec<usize> = vec![];
529 unroll! {
530 for i in (5..4) {
531 a.push(i);
532 }
533 }
534 assert_eq!(a, vec![]);
535 }
536
537 #[test]
538 fn start_at_one_with_step() {
539 let mut a: Vec<usize> = vec![];
540 unroll! {
541 for i in (2..4).step_by(1) {
542 a.push(i);
543 }
544 }
545 assert_eq!(a, vec![2, 3]);
546 }
547
548 #[test]
549 fn start_at_one() {
550 let mut a: Vec<usize> = vec![];
551 unroll! {
552 for i in 1..4 {
553 a.push(i);
554 }
555 }
556 assert_eq!(a, vec![1, 2, 3]);
557 }
558
559 #[test]
560 fn test_all() {
561 {
562 let a: Vec<usize> = vec![];
563 unroll! {
564 for i in 0..0 {
565 a.push(i);
566 }
567 }
568 assert_eq!(a, (0..0).collect::<Vec<usize>>());
569 }
570 {
571 let mut a: Vec<usize> = vec![];
572 unroll! {
573 for i in 0..1 {
574 a.push(i);
575 }
576 }
577 assert_eq!(a, (0..1).collect::<Vec<usize>>());
578 }
579 {
580 let mut a: Vec<usize> = vec![];
581 unroll! {
582 for i in 0..64 {
583 a.push(i);
584 }
585 }
586 assert_eq!(a, (0..64).collect::<Vec<usize>>());
587 }
588 {
589 let mut a: Vec<usize> = vec![];
590 let start = 64 / 4;
591 let end = start * 3;
592 unroll! {
593 for i < 64 in start..end {
594 a.push(i);
595 }
596 }
597 assert_eq!(a, (start..end).collect::<Vec<usize>>());
598 }
599 {
600 let mut a: Vec<usize> = vec![];
601 unroll! {
602 for i in (0..64).step_by(2) {
603 a.push(i);
604 }
605 }
606 assert_eq!(a, (0..64 / 2).map(|x| x * 2).collect::<Vec<usize>>());
607 }
608 {
609 let mut a: Vec<usize> = vec![];
610 let start = 64 / 4;
611 let end = start * 3;
612 unroll! {
613 for i < 64 in (start..end).step_by(2) {
614 a.push(i);
615 }
616 }
617 assert_eq!(a, (start..end).filter(|x| x % 2 == 0).collect::<Vec<usize>>());
618 }
619 }
620}