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