1 //! The `select!` macro.
3 /// A simple wrapper around the standard macros.
5 /// This is just an ugly workaround until it becomes possible to import macros with `use`
8 /// TODO(stjepang): Once we bump the minimum required Rust version to 1.30 or newer, we should:
10 /// 1. Remove all `#[macro_export(local_inner_macros)]` lines.
11 /// 2. Replace `crossbeam_channel_delegate` with direct macro invocations.
14 macro_rules
! crossbeam_channel_delegate
{
15 (concat($
($args
:tt
)*)) => {
18 (stringify($
($args
:tt
)*)) => {
21 (unreachable($
($args
:tt
)*)) => {
22 unreachable
!($
($args
)*)
24 (compile_error($
($args
:tt
)*)) => {
25 compile_error
!($
($args
)*)
29 /// A helper macro for `select!` to hide the long list of macro patterns from the documentation.
31 /// The macro consists of two stages:
33 /// 2. Code generation
35 /// The parsing stage consists of these subparts:
36 /// 1. `@list`: Turns a list of tokens into a list of cases.
37 /// 2. `@list_errorN`: Diagnoses the syntax error.
38 /// 3. `@case`: Parses a single case and verifies its argument list.
40 /// The codegen stage consists of these subparts:
41 /// 1. `@init`: Attempts to optimize `select!` away and initializes the list of handles.
42 /// 1. `@count`: Counts the listed cases.
43 /// 3. `@add`: Adds send/receive operations to the list of handles and starts selection.
44 /// 4. `@complete`: Completes the selected send/receive operation.
46 /// If the parsing stage encounters a syntax error or the codegen stage ends up with too many
47 /// cases to process, the macro fails with a compile-time error.
49 #[macro_export(local_inner_macros)]
50 macro_rules
! crossbeam_channel_internal
{
51 // The list is empty. Now check the arguments of each processed case.
56 crossbeam_channel_internal
!(
63 // If necessary, insert an empty argument list after `default`.
65 (default => $
($tail
:tt
)*)
68 crossbeam_channel_internal
!(
70 (default() => $
($tail
)*)
74 // But print an error if `default` is followed by a `->`.
76 (default -> $
($tail
:tt
)*)
79 crossbeam_channel_delegate
!(compile_error(
80 "expected `=>` after `default` case, found `->`"
83 // Print an error if there's an `->` after the argument list in the default case.
85 (default $args
:tt
-> $
($tail
:tt
)*)
88 crossbeam_channel_delegate
!(compile_error(
89 "expected `=>` after `default` case, found `->`"
92 // Print an error if there is a missing result in a recv case.
94 (recv($
($args
:tt
)*) => $
($tail
:tt
)*)
97 crossbeam_channel_delegate
!(compile_error(
98 "expected `->` after `recv` case, found `=>`"
101 // Print an error if there is a missing result in a send case.
103 (send($
($args
:tt
)*) => $
($tail
:tt
)*)
106 crossbeam_channel_delegate
!(compile_error(
107 "expected `->` after `send` operation, found `=>`"
110 // Make sure the arrow and the result are not repeated.
112 ($case
:ident $args
:tt
-> $res
:tt
-> $
($tail
:tt
)*)
115 crossbeam_channel_delegate
!(compile_error("expected `=>`, found `->`"))
117 // Print an error if there is a semicolon after the block.
119 ($case
:ident $args
:tt $
(-> $res
:pat
)* => $body
:block
; $
($tail
:tt
)*)
122 crossbeam_channel_delegate
!(compile_error(
123 "did you mean to put a comma instead of the semicolon after `}`?"
126 // The first case is separated by a comma.
128 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
, $
($tail
:tt
)*)
131 crossbeam_channel_internal
!(
134 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
137 // Don't require a comma after the case if it has a proper block.
139 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:block $
($tail
:tt
)*)
142 crossbeam_channel_internal
!(
145 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
148 // Only one case remains.
150 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
)
153 crossbeam_channel_internal
!(
156 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
159 // Accept a trailing comma at the end of the list.
161 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
,)
164 crossbeam_channel_internal
!(
167 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
170 // Diagnose and print an error.
175 crossbeam_channel_internal
!(@list_error1 $
($tail
)*)
177 // Stage 1: check the case type.
178 (@list_error1 recv $
($tail
:tt
)*) => {
179 crossbeam_channel_internal
!(@list_error2 recv $
($tail
)*)
181 (@list_error1 send $
($tail
:tt
)*) => {
182 crossbeam_channel_internal
!(@list_error2 send $
($tail
)*)
184 (@list_error1
default $
($tail
:tt
)*) => {
185 crossbeam_channel_internal
!(@list_error2
default $
($tail
)*)
187 (@list_error1 $t
:tt $
($tail
:tt
)*) => {
188 crossbeam_channel_delegate
!(compile_error(
189 crossbeam_channel_delegate
!(concat(
190 "expected one of `recv`, `send`, or `default`, found `",
191 crossbeam_channel_delegate
!(stringify($t
)),
196 (@list_error1 $
($tail
:tt
)*) => {
197 crossbeam_channel_internal
!(@list_error2 $
($tail
)*);
199 // Stage 2: check the argument list.
200 (@list_error2 $case
:ident
) => {
201 crossbeam_channel_delegate
!(compile_error(
202 crossbeam_channel_delegate
!(concat(
203 "missing argument list after `",
204 crossbeam_channel_delegate
!(stringify($case
)),
209 (@list_error2 $case
:ident
=> $
($tail
:tt
)*) => {
210 crossbeam_channel_delegate
!(compile_error(
211 crossbeam_channel_delegate
!(concat(
212 "missing argument list after `",
213 crossbeam_channel_delegate
!(stringify($case
)),
218 (@list_error2 $
($tail
:tt
)*) => {
219 crossbeam_channel_internal
!(@list_error3 $
($tail
)*)
221 // Stage 3: check the `=>` and what comes after it.
222 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)*) => {
223 crossbeam_channel_delegate
!(compile_error(
224 crossbeam_channel_delegate
!(concat(
225 "missing `=>` after `",
226 crossbeam_channel_delegate
!(stringify($case
)),
231 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* =>) => {
232 crossbeam_channel_delegate
!(compile_error(
233 "expected expression after `=>`"
236 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $body
:expr
; $
($tail
:tt
)*) => {
237 crossbeam_channel_delegate
!(compile_error(
238 crossbeam_channel_delegate
!(concat(
239 "did you mean to put a comma instead of the semicolon after `",
240 crossbeam_channel_delegate
!(stringify($body
)),
245 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => recv($
($a
:tt
)*) $
($tail
:tt
)*) => {
246 crossbeam_channel_delegate
!(compile_error(
247 "expected an expression after `=>`"
250 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => send($
($a
:tt
)*) $
($tail
:tt
)*) => {
251 crossbeam_channel_delegate
!(compile_error(
252 "expected an expression after `=>`"
255 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => default($
($a
:tt
)*) $
($tail
:tt
)*) => {
256 crossbeam_channel_delegate
!(compile_error(
257 "expected an expression after `=>`"
260 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident($
($a
:tt
)*) $
($tail
:tt
)*) => {
261 crossbeam_channel_delegate
!(compile_error(
262 crossbeam_channel_delegate
!(concat(
263 "did you mean to put a comma after `",
264 crossbeam_channel_delegate
!(stringify($f
)),
266 crossbeam_channel_delegate
!(stringify($
($a
)*)),
271 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
!($
($a
:tt
)*) $
($tail
:tt
)*) => {
272 crossbeam_channel_delegate
!(compile_error(
273 crossbeam_channel_delegate
!(concat(
274 "did you mean to put a comma after `",
275 crossbeam_channel_delegate
!(stringify($f
)),
277 crossbeam_channel_delegate
!(stringify($
($a
)*)),
282 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
![$
($a
:tt
)*] $
($tail
:tt
)*) => {
283 crossbeam_channel_delegate
!(compile_error(
284 crossbeam_channel_delegate
!(concat(
285 "did you mean to put a comma after `",
286 crossbeam_channel_delegate
!(stringify($f
)),
288 crossbeam_channel_delegate
!(stringify($
($a
)*)),
293 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
!{$($a:tt)*} $
($tail
:tt
)*) => {
294 crossbeam_channel_delegate
!(compile_error(
295 crossbeam_channel_delegate
!(concat(
296 "did you mean to put a comma after `",
297 crossbeam_channel_delegate
!(stringify($f
)),
299 crossbeam_channel_delegate
!(stringify($
($a
)*)),
304 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $body
:tt $
($tail
:tt
)*) => {
305 crossbeam_channel_delegate
!(compile_error(
306 crossbeam_channel_delegate
!(concat(
307 "did you mean to put a comma after `",
308 crossbeam_channel_delegate
!(stringify($body
)),
313 (@list_error3 $case
:ident($
($args
:tt
)*) -> => $
($tail
:tt
)*) => {
314 crossbeam_channel_delegate
!(compile_error("missing pattern after `->`"))
316 (@list_error3 $case
:ident($
($args
:tt
)*) $t
:tt $
(-> $r
:pat
)* => $
($tail
:tt
)*) => {
317 crossbeam_channel_delegate
!(compile_error(
318 crossbeam_channel_delegate
!(concat(
319 "expected `->`, found `",
320 crossbeam_channel_delegate
!(stringify($t
)),
325 (@list_error3 $case
:ident($
($args
:tt
)*) -> $t
:tt $
($tail
:tt
)*) => {
326 crossbeam_channel_delegate
!(compile_error(
327 crossbeam_channel_delegate
!(concat(
328 "expected a pattern, found `",
329 crossbeam_channel_delegate
!(stringify($t
)),
334 (@list_error3
recv($
($args
:tt
)*) $t
:tt $
($tail
:tt
)*) => {
335 crossbeam_channel_delegate
!(compile_error(
336 crossbeam_channel_delegate
!(concat(
337 "expected `->`, found `",
338 crossbeam_channel_delegate
!(stringify($t
)),
343 (@list_error3
send($
($args
:tt
)*) $t
:tt $
($tail
:tt
)*) => {
344 crossbeam_channel_delegate
!(compile_error(
345 crossbeam_channel_delegate
!(concat(
346 "expected `->`, found `",
347 crossbeam_channel_delegate
!(stringify($t
)),
352 (@list_error3 recv $args
:tt $
($tail
:tt
)*) => {
353 crossbeam_channel_delegate
!(compile_error(
354 crossbeam_channel_delegate
!(concat(
355 "expected an argument list after `recv`, found `",
356 crossbeam_channel_delegate
!(stringify($args
)),
361 (@list_error3 send $args
:tt $
($tail
:tt
)*) => {
362 crossbeam_channel_delegate
!(compile_error(
363 crossbeam_channel_delegate
!(concat(
364 "expected an argument list after `send`, found `",
365 crossbeam_channel_delegate
!(stringify($args
)),
370 (@list_error3
default $args
:tt $
($tail
:tt
)*) => {
371 crossbeam_channel_delegate
!(compile_error(
372 crossbeam_channel_delegate
!(concat(
373 "expected an argument list or `=>` after `default`, found `",
374 crossbeam_channel_delegate
!(stringify($args
)),
379 (@list_error3 $
($tail
:tt
)*) => {
380 crossbeam_channel_internal
!(@list_error4 $
($tail
)*)
382 // Stage 4: fail with a generic error message.
383 (@list_error4 $
($tail
:tt
)*) => {
384 crossbeam_channel_delegate
!(compile_error("invalid syntax"))
387 // Success! All cases were parsed.
393 crossbeam_channel_internal
!(
400 // Check the format of a recv case.
402 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
406 crossbeam_channel_internal
!(
409 ($
($cases
)* recv($r
) -> $res
=> $body
,)
413 // Allow trailing comma...
415 (recv($r
:expr
,) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
419 crossbeam_channel_internal
!(
422 ($
($cases
)* recv($r
) -> $res
=> $body
,)
426 // Print an error if the argument list is invalid.
428 (recv($
($args
:tt
)*) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
432 crossbeam_channel_delegate
!(compile_error(
433 crossbeam_channel_delegate
!(concat(
434 "invalid argument list in `recv(",
435 crossbeam_channel_delegate
!(stringify($
($args
)*)),
440 // Print an error if there is no argument list.
442 (recv $t
:tt $
($tail
:tt
)*)
446 crossbeam_channel_delegate
!(compile_error(
447 crossbeam_channel_delegate
!(concat(
448 "expected an argument list after `recv`, found `",
449 crossbeam_channel_delegate
!(stringify($t
)),
455 // Check the format of a send case.
457 (send($s
:expr
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
461 crossbeam_channel_internal
!(
464 ($
($cases
)* send($s
, $m
) -> $res
=> $body
,)
468 // Allow trailing comma...
470 (send($s
:expr
, $m
:expr
,) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
474 crossbeam_channel_internal
!(
477 ($
($cases
)* send($s
, $m
) -> $res
=> $body
,)
481 // Print an error if the argument list is invalid.
483 (send($
($args
:tt
)*) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
487 crossbeam_channel_delegate
!(compile_error(
488 crossbeam_channel_delegate
!(concat(
489 "invalid argument list in `send(",
490 crossbeam_channel_delegate
!(stringify($
($args
)*)),
495 // Print an error if there is no argument list.
497 (send $t
:tt $
($tail
:tt
)*)
501 crossbeam_channel_delegate
!(compile_error(
502 crossbeam_channel_delegate
!(concat(
503 "expected an argument list after `send`, found `",
504 crossbeam_channel_delegate
!(stringify($t
)),
510 // Check the format of a default case.
512 (default() => $body
:tt
, $
($tail
:tt
)*)
516 crossbeam_channel_internal
!(
520 (default() => $body
,)
523 // Check the format of a default case with timeout.
525 (default($timeout
:expr
) => $body
:tt
, $
($tail
:tt
)*)
529 crossbeam_channel_internal
!(
533 (default($timeout
) => $body
,)
536 // Allow trailing comma...
538 (default($timeout
:expr
,) => $body
:tt
, $
($tail
:tt
)*)
542 crossbeam_channel_internal
!(
546 (default($timeout
) => $body
,)
549 // Check for duplicate default cases...
551 (default $
($tail
:tt
)*)
555 crossbeam_channel_delegate
!(compile_error(
556 "there can be only one `default` case in a `select!` block"
559 // Print an error if the argument list is invalid.
561 (default($
($args
:tt
)*) => $body
:tt
, $
($tail
:tt
)*)
565 crossbeam_channel_delegate
!(compile_error(
566 crossbeam_channel_delegate
!(concat(
567 "invalid argument list in `default(",
568 crossbeam_channel_delegate
!(stringify($
($args
)*)),
573 // Print an error if there is an unexpected token after `default`.
575 (default $t
:tt $
($tail
:tt
)*)
579 crossbeam_channel_delegate
!(compile_error(
580 crossbeam_channel_delegate
!(concat(
581 "expected an argument list or `=>` after `default`, found `",
582 crossbeam_channel_delegate
!(stringify($t
)),
588 // The case was not consumed, therefore it must be invalid.
590 ($case
:ident $
($tail
:tt
)*)
594 crossbeam_channel_delegate
!(compile_error(
595 crossbeam_channel_delegate
!(concat(
596 "expected one of `recv`, `send`, or `default`, found `",
597 crossbeam_channel_delegate
!(stringify($case
)),
603 // Optimize `select!` into `try_recv()`.
605 (recv($r
:expr
) -> $res
:pat
=> $recv_body
:tt
,)
606 (default() => $default_body
:tt
,)
610 let _r
: &$
crate::Receiver
<_
> = _r
;
611 match _r
.try_recv() {
612 ::std
::result
::Result
::Err($
crate::TryRecvError
::Empty
) => {
616 let _res
= _res
.map_err(|_
| $
crate::RecvError
);
624 // Optimize `select!` into `recv()`.
626 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
,)
631 let _r
: &$
crate::Receiver
<_
> = _r
;
632 let _res
= _r
.recv();
638 // Optimize `select!` into `recv_timeout()`.
640 (recv($r
:expr
) -> $res
:pat
=> $recv_body
:tt
,)
641 (default($timeout
:expr
) => $default_body
:tt
,)
645 let _r
: &$
crate::Receiver
<_
> = _r
;
646 match _r
.recv_timeout($timeout
) {
647 ::std
::result
::Result
::Err($
crate::RecvTimeoutError
::Timeout
) => {
651 let _res
= _res
.map_err(|_
| $
crate::RecvError
);
660 // // Optimize the non-blocking case with two receive operations.
662 // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
663 // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
664 // (default() => $default_body:tt,)
668 // let _r1: &$crate::Receiver<_> = _r1;
672 // let _r2: &$crate::Receiver<_> = _r2;
674 // // TODO(stjepang): Implement this optimization.
680 // // Optimize the blocking case with two receive operations.
682 // (recv($r1:expr) -> $res1:pat => $body1:tt,)
683 // (recv($r2:expr) -> $res2:pat => $body2:tt,)
688 // let _r1: &$crate::Receiver<_> = _r1;
692 // let _r2: &$crate::Receiver<_> = _r2;
694 // // TODO(stjepang): Implement this optimization.
700 // // Optimize the case with two receive operations and a timeout.
702 // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
703 // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
704 // (default($timeout:expr) => $default_body:tt,)
708 // let _r1: &$crate::Receiver<_> = _r1;
712 // let _r2: &$crate::Receiver<_> = _r2;
714 // // TODO(stjepang): Implement this optimization.
721 // // Optimize `select!` into `try_send()`.
723 // (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,)
724 // (default() => $default_body:tt,)
728 // let _s: &$crate::Sender<_> = _s;
729 // // TODO(stjepang): Implement this optimization.
733 // // Optimize `select!` into `send()`.
735 // (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
740 // let _s: &$crate::Sender<_> = _s;
741 // // TODO(stjepang): Implement this optimization.
745 // // Optimize `select!` into `send_timeout()`.
747 // (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
748 // (default($timeout:expr) => $body:tt,)
752 // let _s: &$crate::Sender<_> = _s;
753 // // TODO(stjepang): Implement this optimization.
758 // Create the list of handles and add operations to it.
763 const _LEN
: usize = crossbeam_channel_internal
!(@
count ($
($cases
)*));
764 let _handle
: &$
crate::internal
::SelectHandle
= &$
crate::never
::<()>();
767 let mut _sel
= [(_handle
, 0, ::std
::ptr
::null()); _LEN
];
769 crossbeam_channel_internal
!(
812 // Count the listed cases.
816 (@
count ($oper
:ident $args
:tt
-> $res
:pat
=> $body
:tt
, $
($cases
:tt
)*)) => {
817 1 + crossbeam_channel_internal
!(@
count ($
($cases
)*))
820 // Run blocking selection.
828 let _oper
: $
crate::SelectedOperation
<'_
> = {
829 let _oper
= $
crate::internal
::select(&mut $sel
);
831 // Erase the lifetime so that `sel` can be dropped early even without NLL.
832 #[allow(unsafe_code)]
833 unsafe { ::std::mem::transmute(_oper) }
836 crossbeam_channel_internal
! {
843 // Run non-blocking selection.
847 (default() => $body
:tt
,)
851 let _oper
: ::std
::option
::Option
<$
crate::SelectedOperation
<'_
>> = {
852 let _oper
= $
crate::internal
::try_select(&mut $sel
);
854 // Erase the lifetime so that `sel` can be dropped early even without NLL.
855 #[allow(unsafe_code)]
856 unsafe { ::std::mem::transmute(_oper) }
865 crossbeam_channel_internal
! {
874 // Run selection with a timeout.
878 (default($timeout
:expr
) => $body
:tt
,)
882 let _oper
: ::std
::option
::Option
<$
crate::SelectedOperation
<'_
>> = {
883 let _oper
= $
crate::internal
::select_timeout(&mut $sel
, $timeout
);
885 // Erase the lifetime so that `sel` can be dropped early even without NLL.
886 #[allow(unsafe_code)]
887 unsafe { ::std::mem::transmute(_oper) }
891 ::std
::option
::Option
::None
=> {
895 ::std
::option
::Option
::Some(_oper
) => {
896 crossbeam_channel_internal
! {
905 // Have we used up all labels?
913 crossbeam_channel_delegate
!(compile_error("too many operations in a `select!` block"))
915 // Add a receive operation to `sel`.
918 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
920 (($i
:tt $var
:ident
) $
($labels
:tt
)*)
925 #[allow(unsafe_code)]
926 let $var
: &$
crate::Receiver
<_
> = unsafe {
927 let _r
: &$
crate::Receiver
<_
> = _r
;
929 // Erase the lifetime so that `sel` can be dropped early even without NLL.
930 unsafe fn unbind
<'a
, T
>(x
: &T
) -> &'a T
{
931 ::std
::mem
::transmute(x
)
935 $sel
[$i
] = ($var
, $i
, $var
as *const $
crate::Receiver
<_
> as *const u8);
937 crossbeam_channel_internal
!(
943 ($
($cases
)* [$i
] recv($var
) -> $res
=> $body
,)
948 // Add a send operation to `sel`.
951 (send($s
:expr
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
953 (($i
:tt $var
:ident
) $
($labels
:tt
)*)
958 #[allow(unsafe_code)]
959 let $var
: &$
crate::Sender
<_
> = unsafe {
960 let _s
: &$
crate::Sender
<_
> = _s
;
962 // Erase the lifetime so that `sel` can be dropped early even without NLL.
963 unsafe fn unbind
<'a
, T
>(x
: &T
) -> &'a T
{
964 ::std
::mem
::transmute(x
)
968 $sel
[$i
] = ($var
, $i
, $var
as *const $
crate::Sender
<_
> as *const u8);
970 crossbeam_channel_internal
!(
976 ($
($cases
)* [$i
] send($var
, $m
) -> $res
=> $body
,)
982 // Complete a receive operation.
986 ([$i
:tt
] recv($r
:ident
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
988 if $oper
.index() == $i
{
989 let _res
= $oper
.recv($r
);
995 crossbeam_channel_internal
! {
1003 // Complete a send operation.
1007 ([$i
:tt
] send($s
:ident
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
1009 if $oper
.index() == $i
{
1010 let _res
= $oper
.send($s
, $m
);
1016 crossbeam_channel_internal
! {
1024 // Panic if we don't identify the selected case, but this should never happen.
1030 crossbeam_channel_delegate
!(unreachable(
1031 "internal error in crossbeam-channel: invalid case"
1035 // Catches a bug within this macro (should not happen).
1036 (@$
($tokens
:tt
)*) => {
1037 crossbeam_channel_delegate
!(compile_error(
1038 crossbeam_channel_delegate
!(concat(
1039 "internal error in crossbeam-channel: ",
1040 crossbeam_channel_delegate
!(stringify(@$
($tokens
)*)),
1045 // The entry points.
1047 crossbeam_channel_delegate
!(compile_error("empty `select!` block"))
1049 ($
($case
:ident $
(($
($args
:tt
)*))* => $body
:expr $
(,)*)*) => {
1050 crossbeam_channel_internal
!(
1052 ($
($case $
(($
($args
)*))* => { $body }
,)*)
1056 ($
($tokens
:tt
)*) => {
1057 crossbeam_channel_internal
!(
1065 /// Selects from a set of channel operations.
1067 /// This macro allows you to define a set of channel operations, wait until any one of them becomes
1068 /// ready, and finally execute it. If multiple operations are ready at the same time, a random one
1069 /// among them is selected.
1071 /// It is also possible to define a `default` case that gets executed if none of the operations are
1072 /// ready, either right away or for a certain duration of time.
1074 /// An operation is considered to be ready if it doesn't have to block. Note that it is ready even
1075 /// when it will simply return an error because the channel is disconnected.
1077 /// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a
1078 /// dynamically created list of channel operations.
1080 /// [`Select`]: struct.Select.html
1084 /// Block until a send or a receive operation is selected:
1088 /// # extern crate crossbeam_channel;
1090 /// use std::thread;
1091 /// use crossbeam_channel::unbounded;
1093 /// let (s1, r1) = unbounded();
1094 /// let (s2, r2) = unbounded();
1095 /// s1.send(10).unwrap();
1097 /// // Since both operations are initially ready, a random one will be executed.
1099 /// recv(r1) -> msg => assert_eq!(msg, Ok(10)),
1100 /// send(s2, 20) -> res => {
1101 /// assert_eq!(res, Ok(()));
1102 /// assert_eq!(r2.recv(), Ok(20));
1108 /// Select from a set of operations without blocking:
1112 /// # extern crate crossbeam_channel;
1114 /// use std::thread;
1115 /// use std::time::Duration;
1116 /// use crossbeam_channel::unbounded;
1118 /// let (s1, r1) = unbounded();
1119 /// let (s2, r2) = unbounded();
1121 /// thread::spawn(move || {
1122 /// thread::sleep(Duration::from_secs(1));
1123 /// s1.send(10).unwrap();
1125 /// thread::spawn(move || {
1126 /// thread::sleep(Duration::from_millis(500));
1127 /// s2.send(20).unwrap();
1130 /// // None of the operations are initially ready.
1132 /// recv(r1) -> msg => panic!(),
1133 /// recv(r2) -> msg => panic!(),
1134 /// default => println!("not ready"),
1139 /// Select over a set of operations with a timeout:
1143 /// # extern crate crossbeam_channel;
1145 /// use std::thread;
1146 /// use std::time::Duration;
1147 /// use crossbeam_channel::unbounded;
1149 /// let (s1, r1) = unbounded();
1150 /// let (s2, r2) = unbounded();
1152 /// thread::spawn(move || {
1153 /// thread::sleep(Duration::from_secs(1));
1154 /// s1.send(10).unwrap();
1156 /// thread::spawn(move || {
1157 /// thread::sleep(Duration::from_millis(500));
1158 /// s2.send(20).unwrap();
1161 /// // None of the two operations will become ready within 100 milliseconds.
1163 /// recv(r1) -> msg => panic!(),
1164 /// recv(r2) -> msg => panic!(),
1165 /// default(Duration::from_millis(100)) => println!("timed out"),
1170 /// Optionally add a receive operation to `select!` using [`never`]:
1174 /// # extern crate crossbeam_channel;
1176 /// use std::thread;
1177 /// use std::time::Duration;
1178 /// use crossbeam_channel::{never, unbounded};
1180 /// let (s1, r1) = unbounded();
1181 /// let (s2, r2) = unbounded();
1183 /// thread::spawn(move || {
1184 /// thread::sleep(Duration::from_secs(1));
1185 /// s1.send(10).unwrap();
1187 /// thread::spawn(move || {
1188 /// thread::sleep(Duration::from_millis(500));
1189 /// s2.send(20).unwrap();
1192 /// // This receiver can be a `Some` or a `None`.
1193 /// let r2 = Some(&r2);
1195 /// // None of the two operations will become ready within 100 milliseconds.
1197 /// recv(r1) -> msg => panic!(),
1198 /// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
1203 /// To optionally add a timeout to `select!`, see the [example] for [`never`].
1205 /// [`never`]: fn.never.html
1206 /// [example]: fn.never.html#examples
1207 #[macro_export(local_inner_macros)]
1208 macro_rules
! select
{
1209 ($
($tokens
:tt
)*) => {
1210 crossbeam_channel_internal
!(