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