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 a `Select`.
42 /// 2. `@add`: Adds send/receive operations to the `Select` and starts selection.
43 /// 3. `@complete`: Completes the selected send/receive operation.
45 /// If the parsing stage encounters a syntax error or the codegen stage ends up with too many
46 /// cases to process, the macro fails with a compile-time error.
48 #[macro_export(local_inner_macros)]
49 macro_rules
! crossbeam_channel_internal
{
50 // The list is empty. Now check the arguments of each processed case.
55 crossbeam_channel_internal
!(
62 // If necessary, insert an empty argument list after `default`.
64 (default => $
($tail
:tt
)*)
67 crossbeam_channel_internal
!(
69 (default() => $
($tail
)*)
73 // But print an error if `default` is followed by a `->`.
75 (default -> $
($tail
:tt
)*)
78 crossbeam_channel_delegate
!(compile_error(
79 "expected `=>` after `default` case, found `->`"
82 // Print an error if there's an `->` after the argument list in the default case.
84 (default $args
:tt
-> $
($tail
:tt
)*)
87 crossbeam_channel_delegate
!(compile_error(
88 "expected `=>` after `default` case, found `->`"
91 // Print an error if there is a missing result in a recv case.
93 (recv($
($args
:tt
)*) => $
($tail
:tt
)*)
96 crossbeam_channel_delegate
!(compile_error(
97 "expected `->` after `recv` case, found `=>`"
100 // Print an error if there is a missing result in a send case.
102 (send($
($args
:tt
)*) => $
($tail
:tt
)*)
105 crossbeam_channel_delegate
!(compile_error(
106 "expected `->` after `send` operation, found `=>`"
109 // Make sure the arrow and the result are not repeated.
111 ($case
:ident $args
:tt
-> $res
:tt
-> $
($tail
:tt
)*)
114 crossbeam_channel_delegate
!(compile_error("expected `=>`, found `->`"))
116 // Print an error if there is a semicolon after the block.
118 ($case
:ident $args
:tt $
(-> $res
:pat
)* => $body
:block
; $
($tail
:tt
)*)
121 crossbeam_channel_delegate
!(compile_error(
122 "did you mean to put a comma instead of the semicolon after `}`?"
125 // The first case is separated by a comma.
127 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
, $
($tail
:tt
)*)
130 crossbeam_channel_internal
!(
133 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
136 // Don't require a comma after the case if it has a proper block.
138 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:block $
($tail
:tt
)*)
141 crossbeam_channel_internal
!(
144 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
147 // Only one case remains.
149 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
)
152 crossbeam_channel_internal
!(
155 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
158 // Accept a trailing comma at the end of the list.
160 ($case
:ident ($
($args
:tt
)*) $
(-> $res
:pat
)* => $body
:expr
,)
163 crossbeam_channel_internal
!(
166 ($
($head
)* $
case ($
($args
)*) $
(-> $res
)* => { $body }
,)
169 // Diagnose and print an error.
174 crossbeam_channel_internal
!(@list_error1 $
($tail
)*)
176 // Stage 1: check the case type.
177 (@list_error1 recv $
($tail
:tt
)*) => {
178 crossbeam_channel_internal
!(@list_error2 recv $
($tail
)*)
180 (@list_error1 send $
($tail
:tt
)*) => {
181 crossbeam_channel_internal
!(@list_error2 send $
($tail
)*)
183 (@list_error1
default $
($tail
:tt
)*) => {
184 crossbeam_channel_internal
!(@list_error2
default $
($tail
)*)
186 (@list_error1 $t
:tt $
($tail
:tt
)*) => {
187 crossbeam_channel_delegate
!(compile_error(
188 crossbeam_channel_delegate
!(concat(
189 "expected one of `recv`, `send`, or `default`, found `",
190 crossbeam_channel_delegate
!(stringify($t
)),
195 (@list_error1 $
($tail
:tt
)*) => {
196 crossbeam_channel_internal
!(@list_error2 $
($tail
)*);
198 // Stage 2: check the argument list.
199 (@list_error2 $case
:ident
) => {
200 crossbeam_channel_delegate
!(compile_error(
201 crossbeam_channel_delegate
!(concat(
202 "missing argument list after `",
203 crossbeam_channel_delegate
!(stringify($case
)),
208 (@list_error2 $case
:ident
=> $
($tail
:tt
)*) => {
209 crossbeam_channel_delegate
!(compile_error(
210 crossbeam_channel_delegate
!(concat(
211 "missing argument list after `",
212 crossbeam_channel_delegate
!(stringify($case
)),
217 (@list_error2 $
($tail
:tt
)*) => {
218 crossbeam_channel_internal
!(@list_error3 $
($tail
)*)
220 // Stage 3: check the `=>` and what comes after it.
221 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)*) => {
222 crossbeam_channel_delegate
!(compile_error(
223 crossbeam_channel_delegate
!(concat(
224 "missing `=>` after `",
225 crossbeam_channel_delegate
!(stringify($case
)),
230 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* =>) => {
231 crossbeam_channel_delegate
!(compile_error(
232 "expected expression after `=>`"
235 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $body
:expr
; $
($tail
:tt
)*) => {
236 crossbeam_channel_delegate
!(compile_error(
237 crossbeam_channel_delegate
!(concat(
238 "did you mean to put a comma instead of the semicolon after `",
239 crossbeam_channel_delegate
!(stringify($body
)),
244 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => recv($
($a
:tt
)*) $
($tail
:tt
)*) => {
245 crossbeam_channel_delegate
!(compile_error(
246 "expected an expression after `=>`"
249 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => send($
($a
:tt
)*) $
($tail
:tt
)*) => {
250 crossbeam_channel_delegate
!(compile_error(
251 "expected an expression after `=>`"
254 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => default($
($a
:tt
)*) $
($tail
:tt
)*) => {
255 crossbeam_channel_delegate
!(compile_error(
256 "expected an expression after `=>`"
259 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident($
($a
:tt
)*) $
($tail
:tt
)*) => {
260 crossbeam_channel_delegate
!(compile_error(
261 crossbeam_channel_delegate
!(concat(
262 "did you mean to put a comma after `",
263 crossbeam_channel_delegate
!(stringify($f
)),
265 crossbeam_channel_delegate
!(stringify($
($a
)*)),
270 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
!($
($a
:tt
)*) $
($tail
:tt
)*) => {
271 crossbeam_channel_delegate
!(compile_error(
272 crossbeam_channel_delegate
!(concat(
273 "did you mean to put a comma after `",
274 crossbeam_channel_delegate
!(stringify($f
)),
276 crossbeam_channel_delegate
!(stringify($
($a
)*)),
281 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
![$
($a
:tt
)*] $
($tail
:tt
)*) => {
282 crossbeam_channel_delegate
!(compile_error(
283 crossbeam_channel_delegate
!(concat(
284 "did you mean to put a comma after `",
285 crossbeam_channel_delegate
!(stringify($f
)),
287 crossbeam_channel_delegate
!(stringify($
($a
)*)),
292 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $f
:ident
!{$($a:tt)*} $
($tail
:tt
)*) => {
293 crossbeam_channel_delegate
!(compile_error(
294 crossbeam_channel_delegate
!(concat(
295 "did you mean to put a comma after `",
296 crossbeam_channel_delegate
!(stringify($f
)),
298 crossbeam_channel_delegate
!(stringify($
($a
)*)),
303 (@list_error3 $case
:ident($
($args
:tt
)*) $
(-> $r
:pat
)* => $body
:tt $
($tail
:tt
)*) => {
304 crossbeam_channel_delegate
!(compile_error(
305 crossbeam_channel_delegate
!(concat(
306 "did you mean to put a comma after `",
307 crossbeam_channel_delegate
!(stringify($body
)),
312 (@list_error3 $case
:ident($
($args
:tt
)*) -> => $
($tail
:tt
)*) => {
313 crossbeam_channel_delegate
!(compile_error("missing pattern after `->`"))
315 (@list_error3 $case
:ident($
($args
:tt
)*) $t
:tt $
(-> $r
:pat
)* => $
($tail
:tt
)*) => {
316 crossbeam_channel_delegate
!(compile_error(
317 crossbeam_channel_delegate
!(concat(
318 "expected `->`, found `",
319 crossbeam_channel_delegate
!(stringify($t
)),
324 (@list_error3 $case
:ident($
($args
:tt
)*) -> $t
:tt $
($tail
:tt
)*) => {
325 crossbeam_channel_delegate
!(compile_error(
326 crossbeam_channel_delegate
!(concat(
327 "expected a pattern, found `",
328 crossbeam_channel_delegate
!(stringify($t
)),
333 (@list_error3
recv($
($args
:tt
)*) $t
:tt $
($tail
:tt
)*) => {
334 crossbeam_channel_delegate
!(compile_error(
335 crossbeam_channel_delegate
!(concat(
336 "expected `->`, found `",
337 crossbeam_channel_delegate
!(stringify($t
)),
342 (@list_error3
send($
($args
:tt
)*) $t
:tt $
($tail
:tt
)*) => {
343 crossbeam_channel_delegate
!(compile_error(
344 crossbeam_channel_delegate
!(concat(
345 "expected `->`, found `",
346 crossbeam_channel_delegate
!(stringify($t
)),
351 (@list_error3 recv $args
:tt $
($tail
:tt
)*) => {
352 crossbeam_channel_delegate
!(compile_error(
353 crossbeam_channel_delegate
!(concat(
354 "expected an argument list after `recv`, found `",
355 crossbeam_channel_delegate
!(stringify($args
)),
360 (@list_error3 send $args
:tt $
($tail
:tt
)*) => {
361 crossbeam_channel_delegate
!(compile_error(
362 crossbeam_channel_delegate
!(concat(
363 "expected an argument list after `send`, found `",
364 crossbeam_channel_delegate
!(stringify($args
)),
369 (@list_error3
default $args
:tt $
($tail
:tt
)*) => {
370 crossbeam_channel_delegate
!(compile_error(
371 crossbeam_channel_delegate
!(concat(
372 "expected an argument list or `=>` after `default`, found `",
373 crossbeam_channel_delegate
!(stringify($args
)),
378 (@list_error3 $
($tail
:tt
)*) => {
379 crossbeam_channel_internal
!(@list_error4 $
($tail
)*)
381 // Stage 4: fail with a generic error message.
382 (@list_error4 $
($tail
:tt
)*) => {
383 crossbeam_channel_delegate
!(compile_error("invalid syntax"))
386 // Success! All cases were parsed.
392 crossbeam_channel_internal
!(
399 // Check the format of a recv case.
401 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
405 crossbeam_channel_internal
!(
408 ($
($cases
)* recv($r
) -> $res
=> $body
,)
412 // Allow trailing comma...
414 (recv($r
:expr
,) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
418 crossbeam_channel_internal
!(
421 ($
($cases
)* recv($r
) -> $res
=> $body
,)
425 // Print an error if the argument list is invalid.
427 (recv($
($args
:tt
)*) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
431 crossbeam_channel_delegate
!(compile_error(
432 crossbeam_channel_delegate
!(concat(
433 "invalid argument list in `recv(",
434 crossbeam_channel_delegate
!(stringify($
($args
)*)),
439 // Print an error if there is no argument list.
441 (recv $t
:tt $
($tail
:tt
)*)
445 crossbeam_channel_delegate
!(compile_error(
446 crossbeam_channel_delegate
!(concat(
447 "expected an argument list after `recv`, found `",
448 crossbeam_channel_delegate
!(stringify($t
)),
454 // Check the format of a send case.
456 (send($s
:expr
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
460 crossbeam_channel_internal
!(
463 ($
($cases
)* send($s
, $m
) -> $res
=> $body
,)
467 // Allow trailing comma...
469 (send($s
:expr
, $m
:expr
,) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
473 crossbeam_channel_internal
!(
476 ($
($cases
)* send($s
, $m
) -> $res
=> $body
,)
480 // Print an error if the argument list is invalid.
482 (send($
($args
:tt
)*) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
486 crossbeam_channel_delegate
!(compile_error(
487 crossbeam_channel_delegate
!(concat(
488 "invalid argument list in `send(",
489 crossbeam_channel_delegate
!(stringify($
($args
)*)),
494 // Print an error if there is no argument list.
496 (send $t
:tt $
($tail
:tt
)*)
500 crossbeam_channel_delegate
!(compile_error(
501 crossbeam_channel_delegate
!(concat(
502 "expected an argument list after `send`, found `",
503 crossbeam_channel_delegate
!(stringify($t
)),
509 // Check the format of a default case.
511 (default() => $body
:tt
, $
($tail
:tt
)*)
515 crossbeam_channel_internal
!(
519 (default() => $body
,)
522 // Check the format of a default case with timeout.
524 (default($timeout
:expr
) => $body
:tt
, $
($tail
:tt
)*)
528 crossbeam_channel_internal
!(
532 (default($timeout
) => $body
,)
535 // Allow trailing comma...
537 (default($timeout
:expr
,) => $body
:tt
, $
($tail
:tt
)*)
541 crossbeam_channel_internal
!(
545 (default($timeout
) => $body
,)
548 // Check for duplicate default cases...
550 (default $
($tail
:tt
)*)
554 crossbeam_channel_delegate
!(compile_error(
555 "there can be only one `default` case in a `select!` block"
558 // Print an error if the argument list is invalid.
560 (default($
($args
:tt
)*) => $body
:tt
, $
($tail
:tt
)*)
564 crossbeam_channel_delegate
!(compile_error(
565 crossbeam_channel_delegate
!(concat(
566 "invalid argument list in `default(",
567 crossbeam_channel_delegate
!(stringify($
($args
)*)),
572 // Print an error if there is an unexpected token after `default`.
574 (default $
($tail
:tt
)*)
578 crossbeam_channel_delegate
!(compile_error(
579 crossbeam_channel_delegate
!(concat(
580 "expected an argument list or `=>` after `default`, found `",
581 crossbeam_channel_delegate
!(stringify($t
)),
587 // The case was not consumed, therefore it must be invalid.
589 ($case
:ident $
($tail
:tt
)*)
593 crossbeam_channel_delegate
!(compile_error(
594 crossbeam_channel_delegate
!(concat(
595 "expected one of `recv`, `send`, or `default`, found `",
596 crossbeam_channel_delegate
!(stringify($case
)),
602 // Optimize `select!` into `try_recv()`.
604 (recv($r
:expr
) -> $res
:pat
=> $recv_body
:tt
,)
605 (default() => $default_body
:tt
,)
609 let _r
: &$
crate::Receiver
<_
> = _r
;
610 match _r
.try_recv() {
611 ::std
::result
::Result
::Err($
crate::TryRecvError
::Empty
) => {
615 let _res
= _res
.map_err(|_
| $
crate::RecvError
);
623 // Optimize `select!` into `recv()`.
625 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
,)
630 let _r
: &$
crate::Receiver
<_
> = _r
;
631 let _res
= _r
.recv();
637 // Optimize `select!` into `recv_timeout()`.
639 (recv($r
:expr
) -> $res
:pat
=> $recv_body
:tt
,)
640 (default($timeout
:expr
) => $default_body
:tt
,)
644 let _r
: &$
crate::Receiver
<_
> = _r
;
645 match _r
.recv_timeout($timeout
) {
646 ::std
::result
::Result
::Err($
crate::RecvTimeoutError
::Timeout
) => {
650 let _res
= _res
.map_err(|_
| $
crate::RecvError
);
659 // // Optimize the non-blocking case with two receive operations.
661 // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
662 // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
663 // (default() => $default_body:tt,)
667 // let _r1: &$crate::Receiver<_> = _r1;
671 // let _r2: &$crate::Receiver<_> = _r2;
673 // // TODO(stjepang): Implement this optimization.
679 // // Optimize the blocking case with two receive operations.
681 // (recv($r1:expr) -> $res1:pat => $body1:tt,)
682 // (recv($r2:expr) -> $res2:pat => $body2:tt,)
687 // let _r1: &$crate::Receiver<_> = _r1;
691 // let _r2: &$crate::Receiver<_> = _r2;
693 // // TODO(stjepang): Implement this optimization.
699 // // Optimize the case with two receive operations and a timeout.
701 // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
702 // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
703 // (default($timeout:expr) => $default_body:tt,)
707 // let _r1: &$crate::Receiver<_> = _r1;
711 // let _r2: &$crate::Receiver<_> = _r2;
713 // // TODO(stjepang): Implement this optimization.
720 // // Optimize `select!` into `try_send()`.
722 // (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,)
723 // (default() => $default_body:tt,)
727 // let _s: &$crate::Sender<_> = _s;
728 // // TODO(stjepang): Implement this optimization.
732 // // Optimize `select!` into `send()`.
734 // (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
739 // let _s: &$crate::Sender<_> = _s;
740 // // TODO(stjepang): Implement this optimization.
744 // // Optimize `select!` into `send_timeout()`.
746 // (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
747 // (default($timeout:expr) => $body:tt,)
751 // let _s: &$crate::Sender<_> = _s;
752 // // TODO(stjepang): Implement this optimization.
757 // Create a `Select` and add operations to it.
763 let mut _sel
= $
crate::Select
::new();
764 crossbeam_channel_internal
!(
807 // Run blocking selection.
815 let _oper
: $
crate::SelectedOperation
<'_
> = {
816 let _oper
= $sel
.select();
818 // Erase the lifetime so that `sel` can be dropped early even without NLL.
819 #[allow(unsafe_code)]
820 unsafe { ::std::mem::transmute(_oper) }
823 crossbeam_channel_internal
! {
830 // Run non-blocking selection.
834 (default() => $body
:tt
,)
838 let _oper
: ::std
::option
::Option
<$
crate::SelectedOperation
<'_
>> = {
839 let _oper
= $sel
.try_select();
841 // Erase the lifetime so that `sel` can be dropped early even without NLL.
842 #[allow(unsafe_code)]
843 unsafe { ::std::mem::transmute(_oper) }
848 ::std
::mem
::drop($sel
);
852 crossbeam_channel_internal
! {
861 // Run selection with a timeout.
865 (default($timeout
:expr
) => $body
:tt
,)
869 let _oper
: ::std
::option
::Option
<$
crate::SelectedOperation
<'_
>> = {
870 let _oper
= $sel
.select_timeout($timeout
);
872 // Erase the lifetime so that `sel` can be dropped early even without NLL.
873 #[allow(unsafe_code)]
874 unsafe { ::std::mem::transmute(_oper) }
878 ::std
::option
::Option
::None
=> {
879 ::std
::mem
::drop($sel
);
882 ::std
::option
::Option
::Some(_oper
) => {
883 crossbeam_channel_internal
! {
892 // Have we used up all labels?
900 crossbeam_channel_delegate
!(compile_error("too many operations in a `select!` block"))
902 // Add a receive operation to `sel`.
905 (recv($r
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
907 (($i
:tt $var
:ident
) $
($labels
:tt
)*)
912 #[allow(unsafe_code)]
913 let $var
: &$
crate::Receiver
<_
> = unsafe {
914 let _r
: &$
crate::Receiver
<_
> = _r
;
916 // Erase the lifetime so that `sel` can be dropped early even without NLL.
917 unsafe fn unbind
<'a
, T
>(x
: &T
) -> &'a T
{
918 ::std
::mem
::transmute(x
)
924 crossbeam_channel_internal
!(
930 ($
($cases
)* [$i
] recv($var
) -> $res
=> $body
,)
935 // Add a send operation to `sel`.
938 (send($s
:expr
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
940 (($i
:tt $var
:ident
) $
($labels
:tt
)*)
945 #[allow(unsafe_code)]
946 let $var
: &$
crate::Sender
<_
> = unsafe {
947 let _s
: &$
crate::Sender
<_
> = _s
;
949 // Erase the lifetime so that `sel` can be dropped early even without NLL.
950 unsafe fn unbind
<'a
, T
>(x
: &T
) -> &'a T
{
951 ::std
::mem
::transmute(x
)
957 crossbeam_channel_internal
!(
963 ($
($cases
)* [$i
] send($var
, $m
) -> $res
=> $body
,)
969 // Complete a receive operation.
973 ([$i
:tt
] recv($r
:ident
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
975 if $oper
.index() == $i
{
976 let _res
= $oper
.recv($r
);
977 ::std
::mem
::drop($sel
);
982 crossbeam_channel_internal
! {
990 // Complete a send operation.
994 ([$i
:tt
] send($s
:ident
, $m
:expr
) -> $res
:pat
=> $body
:tt
, $
($tail
:tt
)*)
996 if $oper
.index() == $i
{
997 let _res
= $oper
.send($s
, $m
);
998 ::std
::mem
::drop($sel
);
1003 crossbeam_channel_internal
! {
1011 // Panic if we don't identify the selected case, but this should never happen.
1017 crossbeam_channel_delegate
!(unreachable(
1018 "internal error in crossbeam-channel: invalid case"
1022 // Catches a bug within this macro (should not happen).
1023 (@$
($tokens
:tt
)*) => {
1024 crossbeam_channel_delegate
!(compile_error(
1025 crossbeam_channel_delegate
!(concat(
1026 "internal error in crossbeam-channel: ",
1027 crossbeam_channel_delegate
!(stringify(@$
($tokens
)*)),
1032 // The entry points.
1034 crossbeam_channel_delegate
!(compile_error("empty `select!` block"))
1036 ($
($case
:ident $
(($
($args
:tt
)*))* => $body
:expr $
(,)*)*) => {
1037 crossbeam_channel_internal
!(
1039 ($
($case $
(($
($args
)*))* => { $body }
,)*)
1043 ($
($tokens
:tt
)*) => {
1044 crossbeam_channel_internal
!(
1052 /// Selects from a set of channel operations.
1054 /// This macro allows you to define a set of channel operations, wait until any one of them becomes
1055 /// ready, and finally execute it. If multiple operations are ready at the same time, a random one
1056 /// among them is selected.
1058 /// It is also possible to define a `default` case that gets executed if none of the operations are
1059 /// ready, either right away or for a certain duration of time.
1061 /// An operation is considered to be ready if it doesn't have to block. Note that it is ready even
1062 /// when it will simply return an error because the channel is disconnected.
1064 /// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a
1065 /// dynamically created list of channel operations.
1067 /// [`Select`]: struct.Select.html
1071 /// Block until a send or a receive operation is selected:
1075 /// # extern crate crossbeam_channel;
1077 /// use std::thread;
1078 /// use crossbeam_channel::unbounded;
1080 /// let (s1, r1) = unbounded();
1081 /// let (s2, r2) = unbounded();
1082 /// s1.send(10).unwrap();
1084 /// // Since both operations are initially ready, a random one will be executed.
1086 /// recv(r1) -> msg => assert_eq!(msg, Ok(10)),
1087 /// send(s2, 20) -> res => {
1088 /// assert_eq!(res, Ok(()));
1089 /// assert_eq!(r2.recv(), Ok(20));
1095 /// Select from a set of operations without blocking:
1099 /// # extern crate crossbeam_channel;
1101 /// use std::thread;
1102 /// use std::time::Duration;
1103 /// use crossbeam_channel::unbounded;
1105 /// let (s1, r1) = unbounded();
1106 /// let (s2, r2) = unbounded();
1108 /// thread::spawn(move || {
1109 /// thread::sleep(Duration::from_secs(1));
1110 /// s1.send(10).unwrap();
1112 /// thread::spawn(move || {
1113 /// thread::sleep(Duration::from_millis(500));
1114 /// s2.send(20).unwrap();
1117 /// // None of the operations are initially ready.
1119 /// recv(r1) -> msg => panic!(),
1120 /// recv(r2) -> msg => panic!(),
1121 /// default => println!("not ready"),
1126 /// Select over a set of operations with a timeout:
1130 /// # extern crate crossbeam_channel;
1132 /// use std::thread;
1133 /// use std::time::Duration;
1134 /// use crossbeam_channel::unbounded;
1136 /// let (s1, r1) = unbounded();
1137 /// let (s2, r2) = unbounded();
1139 /// thread::spawn(move || {
1140 /// thread::sleep(Duration::from_secs(1));
1141 /// s1.send(10).unwrap();
1143 /// thread::spawn(move || {
1144 /// thread::sleep(Duration::from_millis(500));
1145 /// s2.send(20).unwrap();
1148 /// // None of the two operations will become ready within 100 milliseconds.
1150 /// recv(r1) -> msg => panic!(),
1151 /// recv(r2) -> msg => panic!(),
1152 /// default(Duration::from_millis(100)) => println!("timed out"),
1157 /// Optionally add a receive operation to `select!` using [`never`]:
1161 /// # extern crate crossbeam_channel;
1163 /// use std::thread;
1164 /// use std::time::Duration;
1165 /// use crossbeam_channel::{never, unbounded};
1167 /// let (s1, r1) = unbounded();
1168 /// let (s2, r2) = unbounded();
1170 /// thread::spawn(move || {
1171 /// thread::sleep(Duration::from_secs(1));
1172 /// s1.send(10).unwrap();
1174 /// thread::spawn(move || {
1175 /// thread::sleep(Duration::from_millis(500));
1176 /// s2.send(20).unwrap();
1179 /// // This receiver can be a `Some` or a `None`.
1180 /// let r2 = Some(&r2);
1182 /// // None of the two operations will become ready within 100 milliseconds.
1184 /// recv(r1) -> msg => panic!(),
1185 /// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
1190 /// To optionally add a timeout to `select!`, see the [example] for [`never`].
1192 /// [`never`]: fn.never.html
1193 /// [example]: fn.never.html#examples
1194 #[macro_export(local_inner_macros)]
1195 macro_rules
! select
{
1196 ($
($tokens
:tt
)*) => {
1197 crossbeam_channel_internal
!(