#[macro_export]
macro_rules! select {
(biased;) => {
::core::compile_error!("`select!` needs at least one branch")
};
(biased; $($branches:tt)+) => {
$crate::__select!(@branch [biased] [] [] $($branches)+)
};
() => {
::core::compile_error!("`select!` needs at least one branch")
};
($($branches:tt)+) => {
$crate::__select!(@branch [fair] [] [] $($branches)+)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select {
(@branch $mode:tt [$($done:tt)*] [$($all:tt)*] else => $else:expr $(,)?) => {
$crate::__select!(@emit $mode [$($done)*] [$($all)*] [$else])
};
(@branch $mode:tt [$($done:tt)*] [$($all:tt)*]) => {
$crate::__select!(
@emit $mode [$($done)*] [$($all)*]
[::core::panic!("all branches of `select!` are disabled and there is no `else` branch")]
)
};
(@branch $mode:tt [$($done:tt)*] [$($all:tt)*] $($rest:tt)+) => {
$crate::__select!(@pat $mode [$($done)*] [$($all)*] [] $($rest)+)
};
(@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] = $future:expr, if $cond:expr => $($rest:tt)+) => {
$crate::__select!(@handler $mode [$($done)*] [$($all)*] [$($pat)+] $future, $cond => $($rest)+)
};
(@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] = $future:expr => $($rest:tt)+) => {
$crate::__select!(@handler $mode [$($done)*] [$($all)*] [$($pat)+] $future, true => $($rest)+)
};
(@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)*] $next:tt $($rest:tt)*) => {
$crate::__select!(@pat $mode [$($done)*] [$($all)*] [$($pat)* $next] $($rest)*)
};
(@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:block, $($rest:tt)*) => {
$crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => $handler)] [$($all)* _] $($rest)*)
};
(@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:block $($rest:tt)*) => {
$crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => $handler)] [$($all)* _] $($rest)*)
};
(@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:expr, $($rest:tt)*) => {
$crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => { $handler })] [$($all)* _] $($rest)*)
};
(@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:expr) => {
$crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => { $handler })] [$($all)* _])
};
(@emit [$mode:ident]
[$( ([$($skip:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:tt) )+]
[$($all:tt)*]
[$else:expr]
) => {{
const _: () = ::core::assert!(
$crate::__count!($($all)*) <= 64,
"`select!` takes at most 64 branches"
);
let __output = {
let mut __disabled: u64 = 0;
$(
if !$cond {
__disabled |= 1u64 << $crate::__count!($($skip)*);
}
)+
let mut __futures = ($(
::core::pin::pin!(::core::future::IntoFuture::into_future($future)),
)+);
$crate::macros::support::poll_fn(|__cx: &mut ::core::task::Context<'_>| {
if !$crate::macros::support::proceed(__cx) {
return ::core::task::Poll::Pending;
}
let __branches: u32 = $crate::__count!($($all)*);
let __start: u32 = $crate::__select_start!($mode, __branches);
let mut __pending = false;
for __turn in 0..__branches {
let __branch = (__start + __turn) % __branches;
$(
if __branch == $crate::__count!($($skip)*) {
if __disabled & (1u64 << __branch) == 0 {
let ($($skip,)* __future, ..) = &mut __futures;
match ::core::future::Future::poll(::core::pin::Pin::as_mut(__future), __cx) {
::core::task::Poll::Ready(__value) => {
__disabled |= 1u64 << __branch;
let __matches = match &__value {
#[allow(unused_variables)]
$crate::__select_clean!($($pat)+) => true,
#[allow(unreachable_patterns)]
_ => false,
};
if __matches {
return ::core::task::Poll::Ready($crate::__select_wrap!(
[$($skip)*]
$crate::macros::support::Branch::Taken(__value)
));
}
}
::core::task::Poll::Pending => __pending = true,
}
}
continue;
}
)+
}
if __pending {
::core::task::Poll::Pending
} else {
::core::task::Poll::Ready($crate::__select_wrap!(
[$($all)*]
$crate::macros::support::AllDisabled
))
}
})
.await
};
match __output {
$(
$crate::__select_wrap!(
[$($skip)*]
$crate::macros::support::Branch::Taken($($pat)+)
) => $handler,
)+
$crate::__select_wrap!([$($all)*] $crate::macros::support::AllDisabled) => $else,
#[allow(unreachable_patterns)]
_ => ::core::unreachable!("a `select!` output its pattern rejected"),
}
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select_start {
(biased, $branches:expr) => {
0
};
(fair, $branches:expr) => {
$crate::macros::support::start($branches)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select_wrap {
([] $($inner:tt)+) => {
$($inner)+
};
([_ $($skip:tt)*] $($inner:tt)+) => {
$crate::macros::support::Branch::Next($crate::__select_wrap!([$($skip)*] $($inner)+))
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __select_clean {
(@ [$($out:tt)*] []) => {
$($out)*
};
(@ [$($inner:tt)*] [(paren [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
$crate::__select_clean!(@ [$($out)* ($($inner)*)] [$($stack)*] $($rest)*)
};
(@ [$($inner:tt)*] [(bracket [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
$crate::__select_clean!(@ [$($out)* [$($inner)*]] [$($stack)*] $($rest)*)
};
(@ [$($inner:tt)*] [(brace [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
$crate::__select_clean!(@ [$($out)* {$($inner)*}] [$($stack)*] $($rest)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] ref $($rest:tt)*) => {
$crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] mut $($rest:tt)*) => {
$crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] & $($rest:tt)*) => {
$crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] && $($rest:tt)*) => {
$crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] ($($group:tt)*) $($rest:tt)*) => {
$crate::__select_clean!(@ [] [(paren [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] [$($group:tt)*] $($rest:tt)*) => {
$crate::__select_clean!(@ [] [(bracket [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] {$($group:tt)*} $($rest:tt)*) => {
$crate::__select_clean!(@ [] [(brace [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
};
(@ [$($out:tt)*] [$($stack:tt)*] $next:tt $($rest:tt)*) => {
$crate::__select_clean!(@ [$($out)* $next] [$($stack)*] $($rest)*)
};
($($pat:tt)+) => {
$crate::__select_clean!(@ [] [] $($pat)+)
};
}