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