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