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: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, clippy::zero_repeat_side_effects)]
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]
1111macro_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]
1132macro_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}