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: &$crate::internal::SelectHandle = &$crate::never::<()>();
689
690 #[allow(unused_mut)]
691 let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN];
692
693 $crate::crossbeam_channel_internal!(
694 @add
695 _sel
696 ($($cases)*)
697 $default
698 (
699 (0usize _oper0)
700 (1usize _oper1)
701 (2usize _oper2)
702 (3usize _oper3)
703 (4usize _oper4)
704 (5usize _oper5)
705 (6usize _oper6)
706 (7usize _oper7)
707 (8usize _oper8)
708 (9usize _oper9)
709 (10usize _oper10)
710 (11usize _oper11)
711 (12usize _oper12)
712 (13usize _oper13)
713 (14usize _oper14)
714 (15usize _oper15)
715 (16usize _oper16)
716 (17usize _oper17)
717 (18usize _oper18)
718 (19usize _oper19)
719 (20usize _oper20)
720 (21usize _oper21)
721 (22usize _oper22)
722 (23usize _oper23)
723 (24usize _oper24)
724 (25usize _oper25)
725 (26usize _oper26)
726 (27usize _oper27)
727 (28usize _oper28)
728 (29usize _oper29)
729 (30usize _oper30)
730 (31usize _oper31)
731 )
732 ()
733 )
734 }};
735
736 // Count the listed cases.
737 (@count ()) => {
738 0
739 };
740 (@count ($oper:ident $args:tt -> $res:pat => $body:tt, $($cases:tt)*)) => {
741 1 + $crate::crossbeam_channel_internal!(@count ($($cases)*))
742 };
743
744 // Run blocking selection.
745 (@add
746 $sel:ident
747 ()
748 ()
749 $labels:tt
750 $cases:tt
751 ) => {{
752 let _oper: $crate::SelectedOperation<'_> = {
753 let _oper = $crate::internal::select(&mut $sel);
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);
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);
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.
989///
990/// It is also possible to define a `default` case that gets executed if none of the operations are
991/// ready, either right away or for a certain duration of time.
992///
993/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even
994/// when it will simply return an error because the channel is disconnected.
995///
996/// The `select!` macro is a convenience wrapper around [`Select`]. However, it cannot select over a
997/// dynamically created list of channel operations.
998///
999/// [`Select`]: super::Select
1000///
1001/// # Examples
1002///
1003/// Block until a send or a receive operation is selected:
1004///
1005/// ```
1006/// use crossbeam_channel::{select, unbounded};
1007///
1008/// let (s1, r1) = unbounded();
1009/// let (s2, r2) = unbounded();
1010/// s1.send(10).unwrap();
1011///
1012/// // Since both operations are initially ready, a random one will be executed.
1013/// select! {
1014/// recv(r1) -> msg => assert_eq!(msg, Ok(10)),
1015/// send(s2, 20) -> res => {
1016/// assert_eq!(res, Ok(()));
1017/// assert_eq!(r2.recv(), Ok(20));
1018/// }
1019/// }
1020/// ```
1021///
1022/// Select from a set of operations without blocking:
1023///
1024/// ```
1025/// use std::thread;
1026/// use std::time::Duration;
1027/// use crossbeam_channel::{select, unbounded};
1028///
1029/// let (s1, r1) = unbounded();
1030/// let (s2, r2) = unbounded();
1031///
1032/// thread::spawn(move || {
1033/// thread::sleep(Duration::from_secs(1));
1034/// s1.send(10).unwrap();
1035/// });
1036/// thread::spawn(move || {
1037/// thread::sleep(Duration::from_millis(500));
1038/// s2.send(20).unwrap();
1039/// });
1040///
1041/// // None of the operations are initially ready.
1042/// select! {
1043/// recv(r1) -> msg => panic!(),
1044/// recv(r2) -> msg => panic!(),
1045/// default => println!("not ready"),
1046/// }
1047/// ```
1048///
1049/// Select over a set of operations with a timeout:
1050///
1051/// ```
1052/// use std::thread;
1053/// use std::time::Duration;
1054/// use crossbeam_channel::{select, unbounded};
1055///
1056/// let (s1, r1) = unbounded();
1057/// let (s2, r2) = unbounded();
1058///
1059/// thread::spawn(move || {
1060/// thread::sleep(Duration::from_secs(1));
1061/// s1.send(10).unwrap();
1062/// });
1063/// thread::spawn(move || {
1064/// thread::sleep(Duration::from_millis(500));
1065/// s2.send(20).unwrap();
1066/// });
1067///
1068/// // None of the two operations will become ready within 100 milliseconds.
1069/// select! {
1070/// recv(r1) -> msg => panic!(),
1071/// recv(r2) -> msg => panic!(),
1072/// default(Duration::from_millis(100)) => println!("timed out"),
1073/// }
1074/// ```
1075///
1076/// Optionally add a receive operation to `select!` using [`never`]:
1077///
1078/// ```
1079/// use std::thread;
1080/// use std::time::Duration;
1081/// use crossbeam_channel::{select, never, unbounded};
1082///
1083/// let (s1, r1) = unbounded();
1084/// let (s2, r2) = unbounded();
1085///
1086/// thread::spawn(move || {
1087/// thread::sleep(Duration::from_secs(1));
1088/// s1.send(10).unwrap();
1089/// });
1090/// thread::spawn(move || {
1091/// thread::sleep(Duration::from_millis(500));
1092/// s2.send(20).unwrap();
1093/// });
1094///
1095/// // This receiver can be a `Some` or a `None`.
1096/// let r2 = Some(&r2);
1097///
1098/// // None of the two operations will become ready within 100 milliseconds.
1099/// select! {
1100/// recv(r1) -> msg => panic!(),
1101/// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
1102/// }
1103/// ```
1104///
1105/// To optionally add a timeout to `select!`, see the [example] for [`never`].
1106///
1107/// [`never`]: super::never
1108/// [example]: super::never#examples
1109#[macro_export]
1110macro_rules! select {
1111 ($($tokens:tt)*) => {
1112 $crate::crossbeam_channel_internal!(
1113 $($tokens)*
1114 )
1115 };
1116}
1117