Initial import of crossbeam-channel-0.5.0.

Bug: 155309706
Change-Id: I8a4696d18bfd2efa9ae51fa0072a40aa45c219a9
diff --git a/src/select_macro.rs b/src/select_macro.rs
new file mode 100644
index 0000000..f8b247e
--- /dev/null
+++ b/src/select_macro.rs
@@ -0,0 +1,1166 @@
+//! The `select!` macro.
+
+/// A helper macro for `select!` to hide the long list of macro patterns from the documentation.
+///
+/// The macro consists of two stages:
+/// 1. Parsing
+/// 2. Code generation
+///
+/// The parsing stage consists of these subparts:
+/// 1. `@list`: Turns a list of tokens into a list of cases.
+/// 2. `@list_errorN`: Diagnoses the syntax error.
+/// 3. `@case`: Parses a single case and verifies its argument list.
+///
+/// The codegen stage consists of these subparts:
+/// 1. `@init`: Attempts to optimize `select!` away and initializes the list of handles.
+/// 1. `@count`: Counts the listed cases.
+/// 3. `@add`: Adds send/receive operations to the list of handles and starts selection.
+/// 4. `@complete`: Completes the selected send/receive operation.
+///
+/// If the parsing stage encounters a syntax error or the codegen stage ends up with too many
+/// cases to process, the macro fails with a compile-time error.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! crossbeam_channel_internal {
+    // The list is empty. Now check the arguments of each processed case.
+    (@list
+        ()
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($head)*)
+            ()
+            ()
+        )
+    };
+    // If necessary, insert an empty argument list after `default`.
+    (@list
+        (default => $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            (default() => $($tail)*)
+            ($($head)*)
+        )
+    };
+    // But print an error if `default` is followed by a `->`.
+    (@list
+        (default -> $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!(
+            "expected `=>` after `default` case, found `->`"
+        )
+    };
+    // Print an error if there's an `->` after the argument list in the default case.
+    (@list
+        (default $args:tt -> $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!(
+            "expected `=>` after `default` case, found `->`"
+        )
+    };
+    // Print an error if there is a missing result in a recv case.
+    (@list
+        (recv($($args:tt)*) => $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!(
+            "expected `->` after `recv` case, found `=>`"
+        )
+    };
+    // Print an error if there is a missing result in a send case.
+    (@list
+        (send($($args:tt)*) => $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!(
+            "expected `->` after `send` operation, found `=>`"
+        )
+    };
+    // Make sure the arrow and the result are not repeated.
+    (@list
+        ($case:ident $args:tt -> $res:tt -> $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!("expected `=>`, found `->`")
+    };
+    // Print an error if there is a semicolon after the block.
+    (@list
+        ($case:ident $args:tt $(-> $res:pat)* => $body:block; $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        compile_error!(
+            "did you mean to put a comma instead of the semicolon after `}`?"
+        )
+    };
+    // The first case is separated by a comma.
+    (@list
+        ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr, $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ($($tail)*)
+            ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
+        )
+    };
+    // Don't require a comma after the case if it has a proper block.
+    (@list
+        ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:block $($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ($($tail)*)
+            ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
+        )
+    };
+    // Only one case remains.
+    (@list
+        ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ()
+            ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
+        )
+    };
+    // Accept a trailing comma at the end of the list.
+    (@list
+        ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ()
+            ($($head)* $case ($($args)*) $(-> $res)* => { $body },)
+        )
+    };
+    // Diagnose and print an error.
+    (@list
+        ($($tail:tt)*)
+        ($($head:tt)*)
+    ) => {
+        $crate::crossbeam_channel_internal!(@list_error1 $($tail)*)
+    };
+    // Stage 1: check the case type.
+    (@list_error1 recv $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error2 recv $($tail)*)
+    };
+    (@list_error1 send $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error2 send $($tail)*)
+    };
+    (@list_error1 default $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error2 default $($tail)*)
+    };
+    (@list_error1 $t:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected one of `recv`, `send`, or `default`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+    (@list_error1 $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error2 $($tail)*);
+    };
+    // Stage 2: check the argument list.
+    (@list_error2 $case:ident) => {
+        compile_error!(
+            concat!(
+                "missing argument list after `",
+                stringify!($case),
+                "`",
+            )
+        )
+    };
+    (@list_error2 $case:ident => $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "missing argument list after `",
+                stringify!($case),
+                "`",
+            )
+        )
+    };
+    (@list_error2 $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error3 $($tail)*)
+    };
+    // Stage 3: check the `=>` and what comes after it.
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)*) => {
+        compile_error!(
+            concat!(
+                "missing `=>` after `",
+                stringify!($case),
+                "` case",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* =>) => {
+        compile_error!(
+            "expected expression after `=>`"
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:expr; $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma instead of the semicolon after `",
+                stringify!($body),
+                "`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => recv($($a:tt)*) $($tail:tt)*) => {
+        compile_error!(
+            "expected an expression after `=>`"
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => send($($a:tt)*) $($tail:tt)*) => {
+        compile_error!(
+            "expected an expression after `=>`"
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => default($($a:tt)*) $($tail:tt)*) => {
+        compile_error!(
+            "expected an expression after `=>`"
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident($($a:tt)*) $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma after `",
+                stringify!($f),
+                "(",
+                stringify!($($a)*),
+                ")`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!($($a:tt)*) $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma after `",
+                stringify!($f),
+                "!(",
+                stringify!($($a)*),
+                ")`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident![$($a:tt)*] $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma after `",
+                stringify!($f),
+                "![",
+                stringify!($($a)*),
+                "]`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!{$($a:tt)*} $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma after `",
+                stringify!($f),
+                "!{",
+                stringify!($($a)*),
+                "}`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "did you mean to put a comma after `",
+                stringify!($body),
+                "`?",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) -> => $($tail:tt)*) => {
+        compile_error!("missing pattern after `->`")
+    };
+    (@list_error3 $case:ident($($args:tt)*) $t:tt $(-> $r:pat)* => $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected `->`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+    (@list_error3 $case:ident($($args:tt)*) -> $t:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected a pattern, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+    (@list_error3 recv($($args:tt)*) $t:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected `->`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+    (@list_error3 send($($args:tt)*) $t:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected `->`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+    (@list_error3 recv $args:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected an argument list after `recv`, found `",
+                stringify!($args),
+                "`",
+            )
+        )
+    };
+    (@list_error3 send $args:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected an argument list after `send`, found `",
+                stringify!($args),
+                "`",
+            )
+        )
+    };
+    (@list_error3 default $args:tt $($tail:tt)*) => {
+        compile_error!(
+            concat!(
+                "expected an argument list or `=>` after `default`, found `",
+                stringify!($args),
+                "`",
+            )
+        )
+    };
+    (@list_error3 $($tail:tt)*) => {
+        $crate::crossbeam_channel_internal!(@list_error4 $($tail)*)
+    };
+    // Stage 4: fail with a generic error message.
+    (@list_error4 $($tail:tt)*) => {
+        compile_error!("invalid syntax")
+    };
+
+    // Success! All cases were parsed.
+    (@case
+        ()
+        $cases:tt
+        $default:tt
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @init
+            $cases
+            $default
+        )
+    };
+
+    // Check the format of a recv case.
+    (@case
+        (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            ($($cases)* recv($r) -> $res => $body,)
+            $default
+        )
+    };
+    // Allow trailing comma...
+    (@case
+        (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            ($($cases)* recv($r) -> $res => $body,)
+            $default
+        )
+    };
+    // Print an error if the argument list is invalid.
+    (@case
+        (recv($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "invalid argument list in `recv(",
+                stringify!($($args)*),
+                ")`",
+            )
+        )
+    };
+    // Print an error if there is no argument list.
+    (@case
+        (recv $t:tt $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "expected an argument list after `recv`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+
+    // Check the format of a send case.
+    (@case
+        (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            ($($cases)* send($s, $m) -> $res => $body,)
+            $default
+        )
+    };
+    // Allow trailing comma...
+    (@case
+        (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            ($($cases)* send($s, $m) -> $res => $body,)
+            $default
+        )
+    };
+    // Print an error if the argument list is invalid.
+    (@case
+        (send($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "invalid argument list in `send(",
+                stringify!($($args)*),
+                ")`",
+            )
+        )
+    };
+    // Print an error if there is no argument list.
+    (@case
+        (send $t:tt $($tail:tt)*)
+        ($($cases:tt)*)
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "expected an argument list after `send`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+
+    // Check the format of a default case.
+    (@case
+        (default() => $body:tt, $($tail:tt)*)
+        $cases:tt
+        ()
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            $cases
+            (default() => $body,)
+        )
+    };
+    // Check the format of a default case with timeout.
+    (@case
+        (default($timeout:expr) => $body:tt, $($tail:tt)*)
+        $cases:tt
+        ()
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            $cases
+            (default($timeout) => $body,)
+        )
+    };
+    // Allow trailing comma...
+    (@case
+        (default($timeout:expr,) => $body:tt, $($tail:tt)*)
+        $cases:tt
+        ()
+    ) => {
+        $crate::crossbeam_channel_internal!(
+            @case
+            ($($tail)*)
+            $cases
+            (default($timeout) => $body,)
+        )
+    };
+    // Check for duplicate default cases...
+    (@case
+        (default $($tail:tt)*)
+        $cases:tt
+        ($($def:tt)+)
+    ) => {
+        compile_error!(
+            "there can be only one `default` case in a `select!` block"
+        )
+    };
+    // Print an error if the argument list is invalid.
+    (@case
+        (default($($args:tt)*) => $body:tt, $($tail:tt)*)
+        $cases:tt
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "invalid argument list in `default(",
+                stringify!($($args)*),
+                ")`",
+            )
+        )
+    };
+    // Print an error if there is an unexpected token after `default`.
+    (@case
+        (default $t:tt $($tail:tt)*)
+        $cases:tt
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "expected an argument list or `=>` after `default`, found `",
+                stringify!($t),
+                "`",
+            )
+        )
+    };
+
+    // The case was not consumed, therefore it must be invalid.
+    (@case
+        ($case:ident $($tail:tt)*)
+        $cases:tt
+        $default:tt
+    ) => {
+        compile_error!(
+            concat!(
+                "expected one of `recv`, `send`, or `default`, found `",
+                stringify!($case),
+                "`",
+            )
+        )
+    };
+
+    // Optimize `select!` into `try_recv()`.
+    (@init
+        (recv($r:expr) -> $res:pat => $recv_body:tt,)
+        (default() => $default_body:tt,)
+    ) => {{
+        match $r {
+            ref _r => {
+                let _r: &$crate::Receiver<_> = _r;
+                match _r.try_recv() {
+                    ::std::result::Result::Err($crate::TryRecvError::Empty) => {
+                        $default_body
+                    }
+                    _res => {
+                        let _res = _res.map_err(|_| $crate::RecvError);
+                        let $res = _res;
+                        $recv_body
+                    }
+                }
+            }
+        }
+    }};
+    // Optimize `select!` into `recv()`.
+    (@init
+        (recv($r:expr) -> $res:pat => $body:tt,)
+        ()
+    ) => {{
+        match $r {
+            ref _r => {
+                let _r: &$crate::Receiver<_> = _r;
+                let _res = _r.recv();
+                let $res = _res;
+                $body
+            }
+        }
+    }};
+    // Optimize `select!` into `recv_timeout()`.
+    (@init
+        (recv($r:expr) -> $res:pat => $recv_body:tt,)
+        (default($timeout:expr) => $default_body:tt,)
+    ) => {{
+        match $r {
+            ref _r => {
+                let _r: &$crate::Receiver<_> = _r;
+                match _r.recv_timeout($timeout) {
+                    ::std::result::Result::Err($crate::RecvTimeoutError::Timeout) => {
+                        $default_body
+                    }
+                    _res => {
+                        let _res = _res.map_err(|_| $crate::RecvError);
+                        let $res = _res;
+                        $recv_body
+                    }
+                }
+            }
+        }
+    }};
+
+    // // Optimize the non-blocking case with two receive operations.
+    // (@init
+    //     (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
+    //     (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
+    //     (default() => $default_body:tt,)
+    // ) => {{
+    //     match $r1 {
+    //         ref _r1 => {
+    //             let _r1: &$crate::Receiver<_> = _r1;
+    //
+    //             match $r2 {
+    //                 ref _r2 => {
+    //                     let _r2: &$crate::Receiver<_> = _r2;
+    //
+    //                     // TODO(stjepang): Implement this optimization.
+    //                 }
+    //             }
+    //         }
+    //     }
+    // }};
+    // // Optimize the blocking case with two receive operations.
+    // (@init
+    //     (recv($r1:expr) -> $res1:pat => $body1:tt,)
+    //     (recv($r2:expr) -> $res2:pat => $body2:tt,)
+    //     ()
+    // ) => {{
+    //     match $r1 {
+    //         ref _r1 => {
+    //             let _r1: &$crate::Receiver<_> = _r1;
+    //
+    //             match $r2 {
+    //                 ref _r2 => {
+    //                     let _r2: &$crate::Receiver<_> = _r2;
+    //
+    //                     // TODO(stjepang): Implement this optimization.
+    //                 }
+    //             }
+    //         }
+    //     }
+    // }};
+    // // Optimize the case with two receive operations and a timeout.
+    // (@init
+    //     (recv($r1:expr) -> $res1:pat => $recv_body1:tt,)
+    //     (recv($r2:expr) -> $res2:pat => $recv_body2:tt,)
+    //     (default($timeout:expr) => $default_body:tt,)
+    // ) => {{
+    //     match $r1 {
+    //         ref _r1 => {
+    //             let _r1: &$crate::Receiver<_> = _r1;
+    //
+    //             match $r2 {
+    //                 ref _r2 => {
+    //                     let _r2: &$crate::Receiver<_> = _r2;
+    //
+    //                     // TODO(stjepang): Implement this optimization.
+    //                 }
+    //             }
+    //         }
+    //     }
+    // }};
+
+    // // Optimize `select!` into `try_send()`.
+    // (@init
+    //     (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,)
+    //     (default() => $default_body:tt,)
+    // ) => {{
+    //     match $s {
+    //         ref _s => {
+    //             let _s: &$crate::Sender<_> = _s;
+    //             // TODO(stjepang): Implement this optimization.
+    //         }
+    //     }
+    // }};
+    // // Optimize `select!` into `send()`.
+    // (@init
+    //     (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
+    //     ()
+    // ) => {{
+    //     match $s {
+    //         ref _s => {
+    //             let _s: &$crate::Sender<_> = _s;
+    //             // TODO(stjepang): Implement this optimization.
+    //         }
+    //     }
+    // }};
+    // // Optimize `select!` into `send_timeout()`.
+    // (@init
+    //     (send($s:expr, $m:expr) -> $res:pat => $body:tt,)
+    //     (default($timeout:expr) => $body:tt,)
+    // ) => {{
+    //     match $s {
+    //         ref _s => {
+    //             let _s: &$crate::Sender<_> = _s;
+    //             // TODO(stjepang): Implement this optimization.
+    //         }
+    //     }
+    // }};
+
+    // Create the list of handles and add operations to it.
+    (@init
+        ($($cases:tt)*)
+        $default:tt
+    ) => {{
+        const _LEN: usize = $crate::crossbeam_channel_internal!(@count ($($cases)*));
+        let _handle: &$crate::internal::SelectHandle = &$crate::never::<()>();
+
+        #[allow(unused_mut)]
+        let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN];
+
+        $crate::crossbeam_channel_internal!(
+            @add
+            _sel
+            ($($cases)*)
+            $default
+            (
+                (0usize _oper0)
+                (1usize _oper1)
+                (2usize _oper2)
+                (3usize _oper3)
+                (4usize _oper4)
+                (5usize _oper5)
+                (6usize _oper6)
+                (7usize _oper7)
+                (8usize _oper8)
+                (9usize _oper9)
+                (10usize _oper10)
+                (11usize _oper11)
+                (12usize _oper12)
+                (13usize _oper13)
+                (14usize _oper14)
+                (15usize _oper15)
+                (16usize _oper16)
+                (17usize _oper17)
+                (18usize _oper18)
+                (19usize _oper19)
+                (20usize _oper20)
+                (21usize _oper21)
+                (22usize _oper22)
+                (23usize _oper23)
+                (24usize _oper24)
+                (25usize _oper25)
+                (26usize _oper26)
+                (27usize _oper27)
+                (28usize _oper28)
+                (29usize _oper29)
+                (30usize _oper30)
+                (31usize _oper31)
+            )
+            ()
+        )
+    }};
+
+    // Count the listed cases.
+    (@count ()) => {
+        0
+    };
+    (@count ($oper:ident $args:tt -> $res:pat => $body:tt, $($cases:tt)*)) => {
+        1 + $crate::crossbeam_channel_internal!(@count ($($cases)*))
+    };
+
+    // Run blocking selection.
+    (@add
+        $sel:ident
+        ()
+        ()
+        $labels:tt
+        $cases:tt
+    ) => {{
+        let _oper: $crate::SelectedOperation<'_> = {
+            let _oper = $crate::internal::select(&mut $sel);
+
+            // Erase the lifetime so that `sel` can be dropped early even without NLL.
+            unsafe { ::std::mem::transmute(_oper) }
+        };
+
+        $crate::crossbeam_channel_internal! {
+            @complete
+            $sel
+            _oper
+            $cases
+        }
+    }};
+    // Run non-blocking selection.
+    (@add
+        $sel:ident
+        ()
+        (default() => $body:tt,)
+        $labels:tt
+        $cases:tt
+    ) => {{
+        let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
+            let _oper = $crate::internal::try_select(&mut $sel);
+
+            // Erase the lifetime so that `sel` can be dropped early even without NLL.
+            unsafe { ::std::mem::transmute(_oper) }
+        };
+
+        match _oper {
+            None => {
+                { $sel };
+                $body
+            }
+            Some(_oper) => {
+                $crate::crossbeam_channel_internal! {
+                    @complete
+                    $sel
+                    _oper
+                    $cases
+                }
+            }
+        }
+    }};
+    // Run selection with a timeout.
+    (@add
+        $sel:ident
+        ()
+        (default($timeout:expr) => $body:tt,)
+        $labels:tt
+        $cases:tt
+    ) => {{
+        let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = {
+            let _oper = $crate::internal::select_timeout(&mut $sel, $timeout);
+
+            // Erase the lifetime so that `sel` can be dropped early even without NLL.
+            unsafe { ::std::mem::transmute(_oper) }
+        };
+
+        match _oper {
+            ::std::option::Option::None => {
+                { $sel };
+                $body
+            }
+            ::std::option::Option::Some(_oper) => {
+                $crate::crossbeam_channel_internal! {
+                    @complete
+                    $sel
+                    _oper
+                    $cases
+                }
+            }
+        }
+    }};
+    // Have we used up all labels?
+    (@add
+        $sel:ident
+        $input:tt
+        $default:tt
+        ()
+        $cases:tt
+    ) => {
+        compile_error!("too many operations in a `select!` block")
+    };
+    // Add a receive operation to `sel`.
+    (@add
+        $sel:ident
+        (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*)
+        $default:tt
+        (($i:tt $var:ident) $($labels:tt)*)
+        ($($cases:tt)*)
+    ) => {{
+        match $r {
+            ref _r => {
+                let $var: &$crate::Receiver<_> = unsafe {
+                    let _r: &$crate::Receiver<_> = _r;
+
+                    // Erase the lifetime so that `sel` can be dropped early even without NLL.
+                    unsafe fn unbind<'a, T>(x: &T) -> &'a T {
+                        ::std::mem::transmute(x)
+                    }
+                    unbind(_r)
+                };
+                $sel[$i] = ($var, $i, $var as *const $crate::Receiver<_> as *const u8);
+
+                $crate::crossbeam_channel_internal!(
+                    @add
+                    $sel
+                    ($($tail)*)
+                    $default
+                    ($($labels)*)
+                    ($($cases)* [$i] recv($var) -> $res => $body,)
+                )
+            }
+        }
+    }};
+    // Add a send operation to `sel`.
+    (@add
+        $sel:ident
+        (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
+        $default:tt
+        (($i:tt $var:ident) $($labels:tt)*)
+        ($($cases:tt)*)
+    ) => {{
+        match $s {
+            ref _s => {
+                let $var: &$crate::Sender<_> = unsafe {
+                    let _s: &$crate::Sender<_> = _s;
+
+                    // Erase the lifetime so that `sel` can be dropped early even without NLL.
+                    unsafe fn unbind<'a, T>(x: &T) -> &'a T {
+                        ::std::mem::transmute(x)
+                    }
+                    unbind(_s)
+                };
+                $sel[$i] = ($var, $i, $var as *const $crate::Sender<_> as *const u8);
+
+                $crate::crossbeam_channel_internal!(
+                    @add
+                    $sel
+                    ($($tail)*)
+                    $default
+                    ($($labels)*)
+                    ($($cases)* [$i] send($var, $m) -> $res => $body,)
+                )
+            }
+        }
+    }};
+
+    // Complete a receive operation.
+    (@complete
+        $sel:ident
+        $oper:ident
+        ([$i:tt] recv($r:ident) -> $res:pat => $body:tt, $($tail:tt)*)
+    ) => {{
+        if $oper.index() == $i {
+            let _res = $oper.recv($r);
+            { $sel };
+
+            let $res = _res;
+            $body
+        } else {
+            $crate::crossbeam_channel_internal! {
+                @complete
+                $sel
+                $oper
+                ($($tail)*)
+            }
+        }
+    }};
+    // Complete a send operation.
+    (@complete
+        $sel:ident
+        $oper:ident
+        ([$i:tt] send($s:ident, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*)
+    ) => {{
+        if $oper.index() == $i {
+            let _res = $oper.send($s, $m);
+            { $sel };
+
+            let $res = _res;
+            $body
+        } else {
+            $crate::crossbeam_channel_internal! {
+                @complete
+                $sel
+                $oper
+                ($($tail)*)
+            }
+        }
+    }};
+    // Panic if we don't identify the selected case, but this should never happen.
+    (@complete
+        $sel:ident
+        $oper:ident
+        ()
+    ) => {{
+        unreachable!(
+            "internal error in crossbeam-channel: invalid case"
+        )
+    }};
+
+    // Catches a bug within this macro (should not happen).
+    (@$($tokens:tt)*) => {
+        compile_error!(
+            concat!(
+                "internal error in crossbeam-channel: ",
+                stringify!(@$($tokens)*),
+            )
+        )
+    };
+
+    // The entry points.
+    () => {
+        compile_error!("empty `select!` block")
+    };
+    ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ($($case $(($($args)*))* => { $body },)*)
+            ()
+        )
+    };
+    ($($tokens:tt)*) => {
+        $crate::crossbeam_channel_internal!(
+            @list
+            ($($tokens)*)
+            ()
+        )
+    };
+}
+
+/// Selects from a set of channel operations.
+///
+/// This macro allows you to define a set of channel operations, wait until any one of them becomes
+/// ready, and finally execute it. If multiple operations are ready at the same time, a random one
+/// among them is selected.
+///
+/// It is also possible to define a `default` case that gets executed if none of the operations are
+/// ready, either right away or for a certain duration of time.
+///
+/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even
+/// when it will simply return an error because the channel is disconnected.
+///
+/// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a
+/// dynamically created list of channel operations.
+///
+/// [`Select`]: super::Select
+///
+/// # Examples
+///
+/// Block until a send or a receive operation is selected:
+///
+/// ```
+/// use crossbeam_channel::{select, unbounded};
+///
+/// let (s1, r1) = unbounded();
+/// let (s2, r2) = unbounded();
+/// s1.send(10).unwrap();
+///
+/// // Since both operations are initially ready, a random one will be executed.
+/// select! {
+///     recv(r1) -> msg => assert_eq!(msg, Ok(10)),
+///     send(s2, 20) -> res => {
+///         assert_eq!(res, Ok(()));
+///         assert_eq!(r2.recv(), Ok(20));
+///     }
+/// }
+/// ```
+///
+/// Select from a set of operations without blocking:
+///
+/// ```
+/// use std::thread;
+/// use std::time::Duration;
+/// use crossbeam_channel::{select, unbounded};
+///
+/// let (s1, r1) = unbounded();
+/// let (s2, r2) = unbounded();
+///
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_secs(1));
+///     s1.send(10).unwrap();
+/// });
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_millis(500));
+///     s2.send(20).unwrap();
+/// });
+///
+/// // None of the operations are initially ready.
+/// select! {
+///     recv(r1) -> msg => panic!(),
+///     recv(r2) -> msg => panic!(),
+///     default => println!("not ready"),
+/// }
+/// ```
+///
+/// Select over a set of operations with a timeout:
+///
+/// ```
+/// use std::thread;
+/// use std::time::Duration;
+/// use crossbeam_channel::{select, unbounded};
+///
+/// let (s1, r1) = unbounded();
+/// let (s2, r2) = unbounded();
+///
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_secs(1));
+///     s1.send(10).unwrap();
+/// });
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_millis(500));
+///     s2.send(20).unwrap();
+/// });
+///
+/// // None of the two operations will become ready within 100 milliseconds.
+/// select! {
+///     recv(r1) -> msg => panic!(),
+///     recv(r2) -> msg => panic!(),
+///     default(Duration::from_millis(100)) => println!("timed out"),
+/// }
+/// ```
+///
+/// Optionally add a receive operation to `select!` using [`never`]:
+///
+/// ```
+/// use std::thread;
+/// use std::time::Duration;
+/// use crossbeam_channel::{select, never, unbounded};
+///
+/// let (s1, r1) = unbounded();
+/// let (s2, r2) = unbounded();
+///
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_secs(1));
+///     s1.send(10).unwrap();
+/// });
+/// thread::spawn(move || {
+///     thread::sleep(Duration::from_millis(500));
+///     s2.send(20).unwrap();
+/// });
+///
+/// // This receiver can be a `Some` or a `None`.
+/// let r2 = Some(&r2);
+///
+/// // None of the two operations will become ready within 100 milliseconds.
+/// select! {
+///     recv(r1) -> msg => panic!(),
+///     recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)),
+/// }
+/// ```
+///
+/// To optionally add a timeout to `select!`, see the [example] for [`never`].
+///
+/// [`never`]: super::never
+/// [example]: super::never#examples
+#[macro_export]
+macro_rules! select {
+    ($($tokens:tt)*) => {
+        $crate::crossbeam_channel_internal!(
+            $($tokens)*
+        )
+    };
+}