1 //! The `select!` macro.
2 
3 /// A simple wrapper around the standard macros.
4 ///
5 /// This is just an ugly workaround until it becomes possible to import macros with `use`
6 /// statements.
7 ///
8 /// TODO(stjepang): Once we bump the minimum required Rust version to 1.30 or newer, we should:
9 ///
10 /// 1. Remove all `#[macro_export(local_inner_macros)]` lines.
11 /// 2. Replace `crossbeam_channel_delegate` with direct macro invocations.
12 #[doc(hidden)]
13 #[macro_export]
14 macro_rules! crossbeam_channel_delegate {
15     (concat($($args:tt)*)) => {
16         concat!($($args)*)
17     };
18     (stringify($($args:tt)*)) => {
19         stringify!($($args)*)
20     };
21     (unreachable($($args:tt)*)) => {
22         unreachable!($($args)*)
23     };
24     (compile_error($($args:tt)*)) => {
25         compile_error!($($args)*)
26     };
27 }
28 
29 /// A helper macro for `select!` to hide the long list of macro patterns from the documentation.
30 ///
31 /// The macro consists of two stages:
32 /// 1. Parsing
33 /// 2. Code generation
34 ///
35 /// The parsing stage consists of these subparts:
36 /// 1. `@list`: Turns a list of tokens into a list of cases.
37 /// 2. `@list_errorN`: Diagnoses the syntax error.
38 /// 3. `@case`: Parses a single case and verifies its argument list.
39 ///
40 /// The codegen stage consists of these subparts:
41 /// 1. `@init`: Attempts to optimize `select!` away and initializes a `Select`.
42 /// 2. `@add`: Adds send/receive operations to the `Select` and starts selection.
43 /// 3. `@complete`: Completes the selected send/receive operation.
44 ///
45 /// If the parsing stage encounters a syntax error or the codegen stage ends up with too many
46 /// cases to process, the macro fails with a compile-time error.
47 #[doc(hidden)]
48 #[macro_export(local_inner_macros)]
49 macro_rules! crossbeam_channel_internal {
50     // The list is empty. Now check the arguments of each processed case.
51     (@list
52         ()
53         ($($head:tt)*)
54     ) => {
55         crossbeam_channel_internal!(
56             @case
57             ($($head)*)
58             ()
59             ()
60         )
61     };
62     // If necessary, insert an empty argument list after `default`.
63     (@list
64         (default => $($tail:tt)*)
65         ($($head:tt)*)
66     ) => {
67         crossbeam_channel_internal!(
68             @list
69             (default() => $($tail)*)
70             ($($head)*)
71         )
72     };
73     // But print an error if `default` is followed by a `->`.
74     (@list
75         (default -> $($tail:tt)*)
76         ($($head:tt)*)
77     ) => {
78         crossbeam_channel_delegate!(compile_error(
79             "expected `=>` after `default` case, found `->`"
80         ))
81     };
82     // Print an error if there's an `->` after the argument list in the default case.
83     (@list
84         (default $args:tt -> $($tail:tt)*)
85         ($($head:tt)*)
86     ) => {
87         crossbeam_channel_delegate!(compile_error(
88             "expected `=>` after `default` case, found `->`"
89         ))
90     };
91     // Print an error if there is a missing result in a recv case.
92     (@list
93         (recv($($args:tt)*) => $($tail:tt)*)
94         ($($head:tt)*)
95     ) => {
96         crossbeam_channel_delegate!(compile_error(
97             "expected `->` after `recv` case, found `=>`"
98         ))
99     };
100     // Print an error if there is a missing result in a send case.
101     (@list
102         (send($($args:tt)*) => $($tail:tt)*)
103         ($($head:tt)*)
104     ) => {
105         crossbeam_channel_delegate!(compile_error(
106             "expected `->` after `send` operation, found `=>`"
107         ))
108     };
109     // Make sure the arrow and the result are not repeated.
110     (@list
111         ($case:ident $args:tt -> $res:tt -> $($tail:tt)*)
112         ($($head:tt)*)
113     ) => {
114         crossbeam_channel_delegate!(compile_error("expected `=>`, found `->`"))
115     };
116     // Print an error if there is a semicolon after the block.
117     (@list
118         ($case:ident $args:tt $(-> $res:pat)* => $body:block; $($tail:tt)*)
119         ($($head:tt)*)
120     ) => {
121         crossbeam_channel_delegate!(compile_error(
122             "did you mean to put a comma instead of the semicolon after `}`?"
123         ))
124     };
125     // The first case is separated by a comma.
126     (@list
127         ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr, $($tail:tt)*)
128         ($($head:tt)*)
129     ) => {
130         crossbeam_channel_internal!(
131             @list
132             ($($tail)*)
133             ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
134         )
135     };
136     // Don't require a comma after the case if it has a proper block.
137     (@list
138         ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:block $($tail:tt)*)
139         ($($head:tt)*)
140     ) => {
141         crossbeam_channel_internal!(
142             @list
143             ($($tail)*)
144             ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
145         )
146     };
147     // Only one case remains.
148     (@list
149         ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr)
150         ($($head:tt)*)
151     ) => {
152         crossbeam_channel_internal!(
153             @list
154             ()
155             ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
156         )
157     };
158     // Accept a trailing comma at the end of the list.
159     (@list
160         ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,)
161         ($($head:tt)*)
162     ) => {
163         crossbeam_channel_internal!(
164             @list
165             ()
166             ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
167         )
168     };
169     // Diagnose and print an error.
170     (@list
171         ($($tail:tt)*)
172         ($($head:tt)*)
173     ) => {
174         crossbeam_channel_internal!(@list_error1 $($tail)*)
175     };
176     // Stage 1: check the case type.
177     (@list_error1 recv $($tail:tt)*) => {
178         crossbeam_channel_internal!(@list_error2 recv $($tail)*)
179     };
180     (@list_error1 send $($tail:tt)*) => {
181         crossbeam_channel_internal!(@list_error2 send $($tail)*)
182     };
183     (@list_error1 default $($tail:tt)*) => {
184         crossbeam_channel_internal!(@list_error2 default $($tail)*)
185     };
186     (@list_error1 $t:tt $($tail:tt)*) => {
187         crossbeam_channel_delegate!(compile_error(
188             crossbeam_channel_delegate!(concat(
189                 "expected one of `recv`, `send`, or `default`, found `",
190                 crossbeam_channel_delegate!(stringify($t)),
191                 "`",
192             ))
193         ))
194     };
195     (@list_error1 $($tail:tt)*) => {
196         crossbeam_channel_internal!(@list_error2 $($tail)*);
197     };
198     // Stage 2: check the argument list.
199     (@list_error2 $case:ident) => {
200         crossbeam_channel_delegate!(compile_error(
201             crossbeam_channel_delegate!(concat(
202                 "missing argument list after `",
203                 crossbeam_channel_delegate!(stringify($case)),
204                 "`",
205             ))
206         ))
207     };
208     (@list_error2 $case:ident => $($tail:tt)*) => {
209         crossbeam_channel_delegate!(compile_error(
210             crossbeam_channel_delegate!(concat(
211                 "missing argument list after `",
212                 crossbeam_channel_delegate!(stringify($case)),
213                 "`",
214             ))
215         ))
216     };
217     (@list_error2 $($tail:tt)*) => {
218         crossbeam_channel_internal!(@list_error3 $($tail)*)
219     };
220     // Stage 3: check the `=>` and what comes after it.
221     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)*) => {
222         crossbeam_channel_delegate!(compile_error(
223             crossbeam_channel_delegate!(concat(
224                 "missing `=>` after `",
225                 crossbeam_channel_delegate!(stringify($case)),
226                 "` case",
227             ))
228         ))
229     };
230     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* =>) => {
231         crossbeam_channel_delegate!(compile_error(
232             "expected expression after `=>`"
233         ))
234     };
235     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:expr; $($tail:tt)*) => {
236         crossbeam_channel_delegate!(compile_error(
237             crossbeam_channel_delegate!(concat(
238                 "did you mean to put a comma instead of the semicolon after `",
239                 crossbeam_channel_delegate!(stringify($body)),
240                 "`?",
241             ))
242         ))
243     };
244     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => recv($($a:tt)*) $($tail:tt)*) => {
245         crossbeam_channel_delegate!(compile_error(
246             "expected an expression after `=>`"
247         ))
248     };
249     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => send($($a:tt)*) $($tail:tt)*) => {
250         crossbeam_channel_delegate!(compile_error(
251             "expected an expression after `=>`"
252         ))
253     };
254     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => default($($a:tt)*) $($tail:tt)*) => {
255         crossbeam_channel_delegate!(compile_error(
256             "expected an expression after `=>`"
257         ))
258     };
259     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident($($a:tt)*) $($tail:tt)*) => {
260         crossbeam_channel_delegate!(compile_error(
261             crossbeam_channel_delegate!(concat(
262                 "did you mean to put a comma after `",
263                 crossbeam_channel_delegate!(stringify($f)),
264                 "(",
265                 crossbeam_channel_delegate!(stringify($($a)*)),
266                 ")`?",
267             ))
268         ))
269     };
270     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!($($a:tt)*) $($tail:tt)*) => {
271         crossbeam_channel_delegate!(compile_error(
272             crossbeam_channel_delegate!(concat(
273                 "did you mean to put a comma after `",
274                 crossbeam_channel_delegate!(stringify($f)),
275                 "!(",
276                 crossbeam_channel_delegate!(stringify($($a)*)),
277                 ")`?",
278             ))
279         ))
280     };
281     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident![$($a:tt)*] $($tail:tt)*) => {
282         crossbeam_channel_delegate!(compile_error(
283             crossbeam_channel_delegate!(concat(
284                 "did you mean to put a comma after `",
285                 crossbeam_channel_delegate!(stringify($f)),
286                 "![",
287                 crossbeam_channel_delegate!(stringify($($a)*)),
288                 "]`?",
289             ))
290         ))
291     };
292     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!{$($a:tt)*} $($tail:tt)*) => {
293         crossbeam_channel_delegate!(compile_error(
294             crossbeam_channel_delegate!(concat(
295                 "did you mean to put a comma after `",
296                 crossbeam_channel_delegate!(stringify($f)),
297                 "!{",
298                 crossbeam_channel_delegate!(stringify($($a)*)),
299                 "}`?",
300             ))
301         ))
302     };
303     (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:tt $($tail:tt)*) => {
304         crossbeam_channel_delegate!(compile_error(
305             crossbeam_channel_delegate!(concat(
306                 "did you mean to put a comma after `",
307                 crossbeam_channel_delegate!(stringify($body)),
308                 "`?",
309             ))
310         ))
311     };
312     (@list_error3 $case:ident($($args:tt)*) -> => $($tail:tt)*) => {
313         crossbeam_channel_delegate!(compile_error("missing pattern after `->`"))
314     };
315     (@list_error3 $case:ident($($args:tt)*) $t:tt $(-> $r:pat)* => $($tail:tt)*) => {
316         crossbeam_channel_delegate!(compile_error(
317             crossbeam_channel_delegate!(concat(
318                 "expected `->`, found `",
319                 crossbeam_channel_delegate!(stringify($t)),
320                 "`",
321             ))
322         ))
323     };
324     (@list_error3 $case:ident($($args:tt)*) -> $t:tt $($tail:tt)*) => {
325         crossbeam_channel_delegate!(compile_error(
326             crossbeam_channel_delegate!(concat(
327                 "expected a pattern, found `",
328                 crossbeam_channel_delegate!(stringify($t)),
329                 "`",
330             ))
331         ))
332     };
333     (@list_error3 recv($($args:tt)*) $t:tt $($tail:tt)*) => {
334         crossbeam_channel_delegate!(compile_error(
335             crossbeam_channel_delegate!(concat(
336                 "expected `->`, found `",
337                 crossbeam_channel_delegate!(stringify($t)),
338                 "`",
339             ))
340         ))
341     };
342     (@list_error3 send($($args:tt)*) $t:tt $($tail:tt)*) => {
343         crossbeam_channel_delegate!(compile_error(
344             crossbeam_channel_delegate!(concat(
345                 "expected `->`, found `",
346                 crossbeam_channel_delegate!(stringify($t)),
347                 "`",
348             ))
349         ))
350     };
351     (@list_error3 recv $args:tt $($tail:tt)*) => {
352         crossbeam_channel_delegate!(compile_error(
353             crossbeam_channel_delegate!(concat(
354                 "expected an argument list after `recv`, found `",
355                 crossbeam_channel_delegate!(stringify($args)),
356                 "`",
357             ))
358         ))
359     };
360     (@list_error3 send $args:tt $($tail:tt)*) => {
361         crossbeam_channel_delegate!(compile_error(
362             crossbeam_channel_delegate!(concat(
363                 "expected an argument list after `send`, found `",
364                 crossbeam_channel_delegate!(stringify($args)),
365                 "`",
366             ))
367         ))
368     };
369     (@list_error3 default $args:tt $($tail:tt)*) => {
370         crossbeam_channel_delegate!(compile_error(
371             crossbeam_channel_delegate!(concat(
372                 "expected an argument list or `=>` after `default`, found `",
373                 crossbeam_channel_delegate!(stringify($args)),
374                 "`",
375             ))
376         ))
377     };
378     (@list_error3 $($tail:tt)*) => {
379         crossbeam_channel_internal!(@list_error4 $($tail)*)
380     };
381     // Stage 4: fail with a generic error message.
382     (@list_error4 $($tail:tt)*) => {
383         crossbeam_channel_delegate!(compile_error("invalid syntax"))
384     };
385 
386     // Success! All cases were parsed.
387     (@case
388         ()
389         $cases:tt
390         $default:tt
391     ) => {
392         crossbeam_channel_internal!(
393             @init
394             $cases
395             $default
396         )
397     };
398 
399     // Check the format of a recv case.
400     (@case
401         (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*)
402         ($($cases:tt)*)
403         $default:tt
404     ) => {
405         crossbeam_channel_internal!(
406             @case
407             ($($tail)*)
408             ($($cases)* recv($r) -> $res => $body,)
409             $default
410         )
411     };
412     // Allow trailing comma...
413     (@case
414         (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*)
415         ($($cases:tt)*)
416         $default:tt
417     ) => {
418         crossbeam_channel_internal!(
419             @case
420             ($($tail)*)
421             ($($cases)* recv($r) -> $res => $body,)
422             $default
423         )
424     };
425     // Print an error if the argument list is invalid.
426     (@case
427         (recv($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*)
428         ($($cases:tt)*)
429         $default:tt
430     ) => {
431         crossbeam_channel_delegate!(compile_error(
432             crossbeam_channel_delegate!(concat(
433                 "invalid argument list in `recv(",
434                 crossbeam_channel_delegate!(stringify($($args)*)),
435                 ")`",
436             ))
437         ))
438     };
439     // Print an error if there is no argument list.
440     (@case
441         (recv $t:tt $($tail:tt)*)
442         ($($cases:tt)*)
443         $default:tt
444     ) => {
445         crossbeam_channel_delegate!(compile_error(
446             crossbeam_channel_delegate!(concat(
447                 "expected an argument list after `recv`, found `",
448                 crossbeam_channel_delegate!(stringify($t)),
449                 "`",
450             ))
451         ))
452     };
453 
454     // Check the format of a send case.
455     (@case
456         (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
457         ($($cases:tt)*)
458         $default:tt
459     ) => {
460         crossbeam_channel_internal!(
461             @case
462             ($($tail)*)
463             ($($cases)* send($s, $m) -> $res => $body,)
464             $default
465         )
466     };
467     // Allow trailing comma...
468     (@case
469         (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*)
470         ($($cases:tt)*)
471         $default:tt
472     ) => {
473         crossbeam_channel_internal!(
474             @case
475             ($($tail)*)
476             ($($cases)* send($s, $m) -> $res => $body,)
477             $default
478         )
479     };
480     // Print an error if the argument list is invalid.
481     (@case
482         (send($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*)
483         ($($cases:tt)*)
484         $default:tt
485     ) => {
486         crossbeam_channel_delegate!(compile_error(
487             crossbeam_channel_delegate!(concat(
488                 "invalid argument list in `send(",
489                 crossbeam_channel_delegate!(stringify($($args)*)),
490                 ")`",
491             ))
492         ))
493     };
494     // Print an error if there is no argument list.
495     (@case
496         (send $t:tt $($tail:tt)*)
497         ($($cases:tt)*)
498         $default:tt
499     ) => {
500         crossbeam_channel_delegate!(compile_error(
501             crossbeam_channel_delegate!(concat(
502                 "expected an argument list after `send`, found `",
503                 crossbeam_channel_delegate!(stringify($t)),
504                 "`",
505             ))
506         ))
507     };
508 
509     // Check the format of a default case.
510     (@case
511         (default() => $body:tt, $($tail:tt)*)
512         $cases:tt
513         ()
514     ) => {
515         crossbeam_channel_internal!(
516             @case
517             ($($tail)*)
518             $cases
519             (default() => $body,)
520         )
521     };
522     // Check the format of a default case with timeout.
523     (@case
524         (default($timeout:expr) => $body:tt, $($tail:tt)*)
525         $cases:tt
526         ()
527     ) => {
528         crossbeam_channel_internal!(
529             @case
530             ($($tail)*)
531             $cases
532             (default($timeout) => $body,)
533         )
534     };
535     // Allow trailing comma...
536     (@case
537         (default($timeout:expr,) => $body:tt, $($tail:tt)*)
538         $cases:tt
539         ()
540     ) => {
541         crossbeam_channel_internal!(
542             @case
543             ($($tail)*)
544             $cases
545             (default($timeout) => $body,)
546         )
547     };
548     // Check for duplicate default cases...
549     (@case
550         (default $($tail:tt)*)
551         $cases:tt
552         ($($def:tt)+)
553     ) => {
554         crossbeam_channel_delegate!(compile_error(
555             "there can be only one `default` case in a `select!` block"
556         ))
557     };
558     // Print an error if the argument list is invalid.
559     (@case
560         (default($($args:tt)*) => $body:tt, $($tail:tt)*)
561         $cases:tt
562         $default:tt
563     ) => {
564         crossbeam_channel_delegate!(compile_error(
565             crossbeam_channel_delegate!(concat(
566                 "invalid argument list in `default(",
567                 crossbeam_channel_delegate!(stringify($($args)*)),
568                 ")`",
569             ))
570         ))
571     };
572     // Print an error if there is an unexpected token after `default`.
573     (@case
574         (default $($tail:tt)*)
575         $cases:tt
576         $default:tt
577     ) => {
578         crossbeam_channel_delegate!(compile_error(
579             crossbeam_channel_delegate!(concat(
580                 "expected an argument list or `=>` after `default`, found `",
581                 crossbeam_channel_delegate!(stringify($t)),
582                 "`",
583             ))
584         ))
585     };
586 
587     // The case was not consumed, therefore it must be invalid.
588     (@case
589         ($case:ident $($tail:tt)*)
590         $cases:tt
591         $default:tt
592     ) => {
593         crossbeam_channel_delegate!(compile_error(
594             crossbeam_channel_delegate!(concat(
595                 "expected one of `recv`, `send`, or `default`, found `",
596                 crossbeam_channel_delegate!(stringify($case)),
597                 "`",
598             ))
599         ))
600     };
601 
602     // Optimize `select!` into `try_recv()`.
603     (@init
604         (recv($r:expr) -> $res:pat => $recv_body:tt,)
605         (default() => $default_body:tt,)
606     ) => {{
607         match $r {
608             ref _r => {
609                 let _r: &$crate::Receiver<_> = _r;
610                 match _r.try_recv() {
611                     ::std::result::Result::Err($crate::TryRecvError::Empty) => {
612                         $default_body
613                     }
614                     _res => {
615                         let _res = _res.map_err(|_| $crate::RecvError);
616                         let $res = _res;
617                         $recv_body
618                     }
619                 }
620             }
621         }
622     }};
623     // Optimize `select!` into `recv()`.
624     (@init
625         (recv($r:expr) -> $res:pat => $body:tt,)
626         ()
627     ) => {{
628         match $r {
629             ref _r => {
630                 let _r: &$crate::Receiver<_> = _r;
631                 let _res = _r.recv();
632                 let $res = _res;
633                 $body
634             }
635         }
636     }};
637     // Optimize `select!` into `recv_timeout()`.
638     (@init
639         (recv($r:expr) -> $res:pat => $recv_body:tt,)
640         (default($timeout:expr) => $default_body:tt,)
641     ) => {{
642         match $r {
643             ref _r => {
644                 let _r: &$crate::Receiver<_> = _r;
645                 match _r.recv_timeout($timeout) {
646                     ::std::result::Result::Err($crate::RecvTimeoutError::Timeout) => {
647                         $default_body
648                     }
649                     _res => {
650                         let _res = _res.map_err(|_| $crate::RecvError);
651                         let $res = _res;
652                         $recv_body
653                     }
654                 }
655             }
656         }
657     }};
658 
659     // // Optimize the non-blocking case with two receive operations.
660     // (@init
661     //     (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
662     //     (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
663     //     (default() => $default_body:tt,)
664     // ) => {{
665     //     match $r1 {
666     //         ref _r1 => {
667     //             let _r1: &$crate::Receiver<_> = _r1;
668     //
669     //             match $r2 {
670     //                 ref _r2 => {
671     //                     let _r2: &$crate::Receiver<_> = _r2;
672     //
673     //                     // TODO(stjepang): Implement this optimization.
674     //                 }
675     //             }
676     //         }
677     //     }
678     // }};
679     // // Optimize the blocking case with two receive operations.
680     // (@init
681     //     (recv($r1:expr) -> $res1:pat => $body1:tt,)
682     //     (recv($r2:expr) -> $res2:pat => $body2:tt,)
683     //     ()
684     // ) => {{
685     //     match $r1 {
686     //         ref _r1 => {
687     //             let _r1: &$crate::Receiver<_> = _r1;
688     //
689     //             match $r2 {
690     //                 ref _r2 => {
691     //                     let _r2: &$crate::Receiver<_> = _r2;
692     //
693     //                     // TODO(stjepang): Implement this optimization.
694     //                 }
695     //             }
696     //         }
697     //     }
698     // }};
699     // // Optimize the case with two receive operations and a timeout.
700     // (@init
701     //     (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
702     //     (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
703     //     (default($timeout:expr) => $default_body:tt,)
704     // ) => {{
705     //     match $r1 {
706     //         ref _r1 => {
707     //             let _r1: &$crate::Receiver<_> = _r1;
708     //
709     //             match $r2 {
710     //                 ref _r2 => {
711     //                     let _r2: &$crate::Receiver<_> = _r2;
712     //
713     //                     // TODO(stjepang): Implement this optimization.
714     //                 }
715     //             }
716     //         }
717     //     }
718     // }};
719 
720     // // Optimize `select!` into `try_send()`.
721     // (@init
722     //     (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,)
723     //     (default() => $default_body:tt,)
724     // ) => {{
725     //     match $s {
726     //         ref _s => {
727     //             let _s: &$crate::Sender<_> = _s;
728     //             // TODO(stjepang): Implement this optimization.
729     //         }
730     //     }
731     // }};
732     // // Optimize `select!` into `send()`.
733     // (@init
734     //     (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
735     //     ()
736     // ) => {{
737     //     match $s {
738     //         ref _s => {
739     //             let _s: &$crate::Sender<_> = _s;
740     //             // TODO(stjepang): Implement this optimization.
741     //         }
742     //     }
743     // }};
744     // // Optimize `select!` into `send_timeout()`.
745     // (@init
746     //     (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
747     //     (default($timeout:expr) => $body:tt,)
748     // ) => {{
749     //     match $s {
750     //         ref _s => {
751     //             let _s: &$crate::Sender<_> = _s;
752     //             // TODO(stjepang): Implement this optimization.
753     //         }
754     //     }
755     // }};
756 
757     // Create a `Select` and add operations to it.
758     (@init
759         ($($cases:tt)*)
760         $default:tt
761     ) => {{
762         #[allow(unused_mut)]
763         let mut _sel = $crate::Select::new();
764         crossbeam_channel_internal!(
765             @add
766             _sel
767             ($($cases)*)
768             $default
769             (
770                 (0usize _oper0)
771                 (1usize _oper1)
772                 (2usize _oper2)
773                 (3usize _oper3)
774                 (4usize _oper4)
775                 (5usize _oper5)
776                 (6usize _oper6)
777                 (7usize _oper7)
778                 (8usize _oper8)
779                 (9usize _oper9)
780                 (10usize _oper10)
781                 (11usize _oper11)
782                 (12usize _oper12)
783                 (13usize _oper13)
784                 (14usize _oper14)
785                 (15usize _oper15)
786                 (16usize _oper16)
787                 (17usize _oper17)
788                 (20usize _oper18)
789                 (19usize _oper19)
790                 (20usize _oper20)
791                 (21usize _oper21)
792                 (22usize _oper22)
793                 (23usize _oper23)
794                 (24usize _oper24)
795                 (25usize _oper25)
796                 (26usize _oper26)
797                 (27usize _oper27)
798                 (28usize _oper28)
799                 (29usize _oper29)
800                 (30usize _oper30)
801                 (31usize _oper31)
802             )
803             ()
804         )
805     }};
806 
807     // Run blocking selection.
808     (@add
809         $sel:ident
810         ()
811         ()
812         $labels:tt
813         $cases:tt
814     ) => {{
815         let _oper: $crate::SelectedOperation<'_> = {
816             let _oper = $sel.select();
817 
818             // Erase the lifetime so that `sel` can be dropped early even without NLL.
819             #[allow(unsafe_code)]
820             unsafe { ::std::mem::transmute(_oper) }
821         };
822 
823         crossbeam_channel_internal! {
824             @complete
825             $sel
826             _oper
827             $cases
828         }
829     }};
830     // Run non-blocking selection.
831     (@add
832         $sel:ident
833         ()
834         (default() => $body:tt,)
835         $labels:tt
836         $cases:tt
837     ) => {{
838         let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
839             let _oper = $sel.try_select();
840 
841             // Erase the lifetime so that `sel` can be dropped early even without NLL.
842             #[allow(unsafe_code)]
843             unsafe { ::std::mem::transmute(_oper) }
844         };
845 
846         match _oper {
847             None => {
848                 ::std::mem::drop($sel);
849                 $body
850             }
851             Some(_oper) => {
852                 crossbeam_channel_internal! {
853                     @complete
854                     $sel
855                     _oper
856                     $cases
857                 }
858             }
859         }
860     }};
861     // Run selection with a timeout.
862     (@add
863         $sel:ident
864         ()
865         (default($timeout:expr) => $body:tt,)
866         $labels:tt
867         $cases:tt
868     ) => {{
869         let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
870             let _oper = $sel.select_timeout($timeout);
871 
872             // Erase the lifetime so that `sel` can be dropped early even without NLL.
873             #[allow(unsafe_code)]
874             unsafe { ::std::mem::transmute(_oper) }
875         };
876 
877         match _oper {
878             ::std::option::Option::None => {
879                 ::std::mem::drop($sel);
880                 $body
881             }
882             ::std::option::Option::Some(_oper) => {
883                 crossbeam_channel_internal! {
884                     @complete
885                     $sel
886                     _oper
887                     $cases
888                 }
889             }
890         }
891     }};
892     // Have we used up all labels?
893     (@add
894         $sel:ident
895         $input:tt
896         $default:tt
897         ()
898         $cases:tt
899     ) => {
900         crossbeam_channel_delegate!(compile_error("too many operations in a `select!` block"))
901     };
902     // Add a receive operation to `sel`.
903     (@add
904         $sel:ident
905         (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*)
906         $default:tt
907         (($i:tt $var:ident) $($labels:tt)*)
908         ($($cases:tt)*)
909     ) => {{
910         match $r {
911             ref _r => {
912                 #[allow(unsafe_code)]
913                 let $var: &$crate::Receiver<_> = unsafe {
914                     let _r: &$crate::Receiver<_> = _r;
915 
916                     // Erase the lifetime so that `sel` can be dropped early even without NLL.
917                     unsafe fn unbind<'a, T>(x: &T) -> &'a T {
918                         ::std::mem::transmute(x)
919                     }
920                     unbind(_r)
921                 };
922                 $sel.recv($var);
923 
924                 crossbeam_channel_internal!(
925                     @add
926                     $sel
927                     ($($tail)*)
928                     $default
929                     ($($labels)*)
930                     ($($cases)* [$i] recv($var) -> $res => $body,)
931                 )
932             }
933         }
934     }};
935     // Add a send operation to `sel`.
936     (@add
937         $sel:ident
938         (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
939         $default:tt
940         (($i:tt $var:ident) $($labels:tt)*)
941         ($($cases:tt)*)
942     ) => {{
943         match $s {
944             ref _s => {
945                 #[allow(unsafe_code)]
946                 let $var: &$crate::Sender<_> = unsafe {
947                     let _s: &$crate::Sender<_> = _s;
948 
949                     // Erase the lifetime so that `sel` can be dropped early even without NLL.
950                     unsafe fn unbind<'a, T>(x: &T) -> &'a T {
951                         ::std::mem::transmute(x)
952                     }
953                     unbind(_s)
954                 };
955                 $sel.send($var);
956 
957                 crossbeam_channel_internal!(
958                     @add
959                     $sel
960                     ($($tail)*)
961                     $default
962                     ($($labels)*)
963                     ($($cases)* [$i] send($var, $m) -> $res => $body,)
964                 )
965             }
966         }
967     }};
968 
969     // Complete a receive operation.
970     (@complete
971         $sel:ident
972         $oper:ident
973         ([$i:tt] recv($r:ident) -> $res:pat => $body:tt, $($tail:tt)*)
974     ) => {{
975         if $oper.index() == $i {
976             let _res = $oper.recv($r);
977             ::std::mem::drop($sel);
978 
979             let $res = _res;
980             $body
981         } else {
982             crossbeam_channel_internal! {
983                 @complete
984                 $sel
985                 $oper
986                 ($($tail)*)
987             }
988         }
989     }};
990     // Complete a send operation.
991     (@complete
992         $sel:ident
993         $oper:ident
994         ([$i:tt] send($s:ident, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
995     ) => {{
996         if $oper.index() == $i {
997             let _res = $oper.send($s, $m);
998             ::std::mem::drop($sel);
999 
1000             let $res = _res;
1001             $body
1002         } else {
1003             crossbeam_channel_internal! {
1004                 @complete
1005                 $sel
1006                 $oper
1007                 ($($tail)*)
1008             }
1009         }
1010     }};
1011     // Panic if we don't identify the selected case, but this should never happen.
1012     (@complete
1013         $sel:ident
1014         $oper:ident
1015         ()
1016     ) => {{
1017         crossbeam_channel_delegate!(unreachable(
1018             "internal error in crossbeam-channel: invalid case"
1019         ))
1020     }};
1021 
1022     // Catches a bug within this macro (should not happen).
1023     (@$($tokens:tt)*) => {
1024         crossbeam_channel_delegate!(compile_error(
1025             crossbeam_channel_delegate!(concat(
1026                 "internal error in crossbeam-channel: ",
1027                 crossbeam_channel_delegate!(stringify(@$($tokens)*)),
1028             ))
1029         ))
1030     };
1031 
1032     // The entry points.
1033     () => {
1034         crossbeam_channel_delegate!(compile_error("empty `select!` block"))
1035     };
1036     ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => {
1037         crossbeam_channel_internal!(
1038             @list
1039             ($($case $(($($args)*))* => { $body },)*)
1040             ()
1041         )
1042     };
1043     ($($tokens:tt)*) => {
1044         crossbeam_channel_internal!(
1045             @list
1046             ($($tokens)*)
1047             ()
1048         )
1049     };
1050 }
1051 
1052 /// Selects from a set of channel operations.
1053 ///
1054 /// This macro allows you to define a set of channel operations, wait until any one of them becomes
1055 /// ready, and finally execute it. If multiple operations are ready at the same time, a random one
1056 /// among them is selected.
1057 ///
1058 /// It is also possible to define a `default` case that gets executed if none of the operations are
1059 /// ready, either right away or for a certain duration of time.
1060 ///
1061 /// An operation is considered to be ready if it doesn't have to block. Note that it is ready even
1062 /// when it will simply return an error because the channel is disconnected.
1063 ///
1064 /// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a
1065 /// dynamically created list of channel operations.
1066 ///
1067 /// [`Select`]: struct.Select.html
1068 ///
1069 /// # Examples
1070 ///
1071 /// Block until a send or a receive operation is selected:
1072 ///
1073 /// ```
1074 /// # #[macro_use]
1075 /// # extern crate crossbeam_channel;
1076 /// # fn main() {
1077 /// use std::thread;
1078 /// use crossbeam_channel::unbounded;
1079 ///
1080 /// let (s1, r1) = unbounded();
1081 /// let (s2, r2) = unbounded();
1082 /// s1.send(10).unwrap();
1083 ///
1084 /// // Since both operations are initially ready, a random one will be executed.
1085 /// select! {
1086 ///     recv(r1) -> msg => assert_eq!(msg, Ok(10)),
1087 ///     send(s2, 20) -> res => {
1088 ///         assert_eq!(res, Ok(()));
1089 ///         assert_eq!(r2.recv(), Ok(20));
1090 ///     }
1091 /// }
1092 /// # }
1093 /// ```
1094 ///
1095 /// Select from a set of operations without blocking:
1096 ///
1097 /// ```
1098 /// # #[macro_use]
1099 /// # extern crate crossbeam_channel;
1100 /// # fn main() {
1101 /// use std::thread;
1102 /// use std::time::Duration;
1103 /// use crossbeam_channel::unbounded;
1104 ///
1105 /// let (s1, r1) = unbounded();
1106 /// let (s2, r2) = unbounded();
1107 ///
1108 /// thread::spawn(move || {
1109 ///     thread::sleep(Duration::from_secs(1));
1110 ///     s1.send(10).unwrap();
1111 /// });
1112 /// thread::spawn(move || {
1113 ///     thread::sleep(Duration::from_millis(500));
1114 ///     s2.send(20).unwrap();
1115 /// });
1116 ///
1117 /// // None of the operations are initially ready.
1118 /// select! {
1119 ///     recv(r1) -> msg => panic!(),
1120 ///     recv(r2) -> msg => panic!(),
1121 ///     default => println!("not ready"),
1122 /// }
1123 /// # }
1124 /// ```
1125 ///
1126 /// Select over a set of operations with a timeout:
1127 ///
1128 /// ```
1129 /// # #[macro_use]
1130 /// # extern crate crossbeam_channel;
1131 /// # fn main() {
1132 /// use std::thread;
1133 /// use std::time::Duration;
1134 /// use crossbeam_channel::unbounded;
1135 ///
1136 /// let (s1, r1) = unbounded();
1137 /// let (s2, r2) = unbounded();
1138 ///
1139 /// thread::spawn(move || {
1140 ///     thread::sleep(Duration::from_secs(1));
1141 ///     s1.send(10).unwrap();
1142 /// });
1143 /// thread::spawn(move || {
1144 ///     thread::sleep(Duration::from_millis(500));
1145 ///     s2.send(20).unwrap();
1146 /// });
1147 ///
1148 /// // None of the two operations will become ready within 100 milliseconds.
1149 /// select! {
1150 ///     recv(r1) -> msg => panic!(),
1151 ///     recv(r2) -> msg => panic!(),
1152 ///     default(Duration::from_millis(100)) => println!("timed out"),
1153 /// }
1154 /// # }
1155 /// ```
1156 ///
1157 /// Optionally add a receive operation to `select!` using [`never`]:
1158 ///
1159 /// ```
1160 /// # #[macro_use]
1161 /// # extern crate crossbeam_channel;
1162 /// # fn main() {
1163 /// use std::thread;
1164 /// use std::time::Duration;
1165 /// use crossbeam_channel::{never, unbounded};
1166 ///
1167 /// let (s1, r1) = unbounded();
1168 /// let (s2, r2) = unbounded();
1169 ///
1170 /// thread::spawn(move || {
1171 ///     thread::sleep(Duration::from_secs(1));
1172 ///     s1.send(10).unwrap();
1173 /// });
1174 /// thread::spawn(move || {
1175 ///     thread::sleep(Duration::from_millis(500));
1176 ///     s2.send(20).unwrap();
1177 /// });
1178 ///
1179 /// // This receiver can be a `Some` or a `None`.
1180 /// let r2 = Some(&r2);
1181 ///
1182 /// // None of the two operations will become ready within 100 milliseconds.
1183 /// select! {
1184 ///     recv(r1) -> msg => panic!(),
1185 ///     recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
1186 /// }
1187 /// # }
1188 /// ```
1189 ///
1190 /// To optionally add a timeout to `select!`, see the [example] for [`never`].
1191 ///
1192 /// [`never`]: fn.never.html
1193 /// [example]: fn.never.html#examples
1194 #[macro_export(local_inner_macros)]
1195 macro_rules! select {
1196     ($($tokens:tt)*) => {
1197         crossbeam_channel_internal!(
1198             $($tokens)*
1199         )
1200     };
1201 }
1202