Skip to main content

crossbeam_channel/
select_macro.rs

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