1#[macro_export]
81macro_rules! select {
82 (biased;) => {
83 ::core::compile_error!("`select!` needs at least one branch")
84 };
85 (biased; $($branches:tt)+) => {
86 $crate::__select!(@branch [biased] [] [] $($branches)+)
87 };
88 () => {
89 ::core::compile_error!("`select!` needs at least one branch")
90 };
91 ($($branches:tt)+) => {
92 $crate::__select!(@branch [fair] [] [] $($branches)+)
93 };
94}
95
96#[doc(hidden)]
100#[macro_export]
101macro_rules! __select {
102 (@branch $mode:tt [$($done:tt)*] [$($all:tt)*] else => $else:expr $(,)?) => {
104 $crate::__select!(@emit $mode [$($done)*] [$($all)*] [$else])
105 };
106 (@branch $mode:tt [$($done:tt)*] [$($all:tt)*]) => {
108 $crate::__select!(
109 @emit $mode [$($done)*] [$($all)*]
110 [::core::panic!("all branches of `select!` are disabled and there is no `else` branch")]
111 )
112 };
113 (@branch $mode:tt [$($done:tt)*] [$($all:tt)*] $($rest:tt)+) => {
115 $crate::__select!(@pat $mode [$($done)*] [$($all)*] [] $($rest)+)
116 };
117
118 (@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] = $future:expr, if $cond:expr => $($rest:tt)+) => {
119 $crate::__select!(@handler $mode [$($done)*] [$($all)*] [$($pat)+] $future, $cond => $($rest)+)
120 };
121 (@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] = $future:expr => $($rest:tt)+) => {
122 $crate::__select!(@handler $mode [$($done)*] [$($all)*] [$($pat)+] $future, true => $($rest)+)
123 };
124 (@pat $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)*] $next:tt $($rest:tt)*) => {
125 $crate::__select!(@pat $mode [$($done)*] [$($all)*] [$($pat)* $next] $($rest)*)
126 };
127
128 (@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:block, $($rest:tt)*) => {
129 $crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => $handler)] [$($all)* _] $($rest)*)
130 };
131 (@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:block $($rest:tt)*) => {
132 $crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => $handler)] [$($all)* _] $($rest)*)
133 };
134 (@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:expr, $($rest:tt)*) => {
135 $crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => { $handler })] [$($all)* _] $($rest)*)
136 };
137 (@handler $mode:tt [$($done:tt)*] [$($all:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:expr) => {
138 $crate::__select!(@branch $mode [$($done)* ([$($all)*] [$($pat)+] $future, $cond => { $handler })] [$($all)* _])
139 };
140
141 (@emit [$mode:ident]
142 [$( ([$($skip:tt)*] [$($pat:tt)+] $future:expr, $cond:expr => $handler:tt) )+]
143 [$($all:tt)*]
144 [$else:expr]
145 ) => {{
146 const _: () = ::core::assert!(
147 $crate::__count!($($all)*) <= 64,
148 "`select!` takes at most 64 branches"
149 );
150 let __output = {
153 let mut __disabled: u64 = 0;
154 $(
155 if !$cond {
156 __disabled |= 1u64 << $crate::__count!($($skip)*);
157 }
158 )+
159 let mut __futures = ($(
160 ::core::pin::pin!(::core::future::IntoFuture::into_future($future)),
161 )+);
162 $crate::macros::support::poll_fn(|__cx: &mut ::core::task::Context<'_>| {
163 if !$crate::macros::support::proceed(__cx) {
164 return ::core::task::Poll::Pending;
165 }
166 let __branches: u32 = $crate::__count!($($all)*);
167 let __start: u32 = $crate::__select_start!($mode, __branches);
168 let mut __pending = false;
169 for __turn in 0..__branches {
170 let __branch = (__start + __turn) % __branches;
171 $(
172 if __branch == $crate::__count!($($skip)*) {
173 if __disabled & (1u64 << __branch) == 0 {
174 let ($($skip,)* __future, ..) = &mut __futures;
175 match ::core::future::Future::poll(::core::pin::Pin::as_mut(__future), __cx) {
176 ::core::task::Poll::Ready(__value) => {
177 __disabled |= 1u64 << __branch;
178 let __matches = match &__value {
179 #[allow(unused_variables)]
180 $crate::__select_clean!($($pat)+) => true,
181 #[allow(unreachable_patterns)]
182 _ => false,
183 };
184 if __matches {
185 return ::core::task::Poll::Ready($crate::__select_wrap!(
186 [$($skip)*]
187 $crate::macros::support::Branch::Taken(__value)
188 ));
189 }
190 }
191 ::core::task::Poll::Pending => __pending = true,
192 }
193 }
194 continue;
195 }
196 )+
197 }
198 if __pending {
199 ::core::task::Poll::Pending
200 } else {
201 ::core::task::Poll::Ready($crate::__select_wrap!(
202 [$($all)*]
203 $crate::macros::support::AllDisabled
204 ))
205 }
206 })
207 .await
208 };
209 match __output {
210 $(
211 $crate::__select_wrap!(
212 [$($skip)*]
213 $crate::macros::support::Branch::Taken($($pat)+)
214 ) => $handler,
215 )+
216 $crate::__select_wrap!([$($all)*] $crate::macros::support::AllDisabled) => $else,
217 #[allow(unreachable_patterns)]
219 _ => ::core::unreachable!("a `select!` output its pattern rejected"),
220 }
221 }};
222}
223
224#[doc(hidden)]
226#[macro_export]
227macro_rules! __select_start {
228 (biased, $branches:expr) => {
229 0
230 };
231 (fair, $branches:expr) => {
232 $crate::macros::support::start($branches)
233 };
234}
235
236#[doc(hidden)]
238#[macro_export]
239macro_rules! __select_wrap {
240 ([] $($inner:tt)+) => {
241 $($inner)+
242 };
243 ([_ $($skip:tt)*] $($inner:tt)+) => {
244 $crate::macros::support::Branch::Next($crate::__select_wrap!([$($skip)*] $($inner)+))
245 };
246}
247
248#[doc(hidden)]
254#[macro_export]
255macro_rules! __select_clean {
256 (@ [$($out:tt)*] []) => {
257 $($out)*
258 };
259 (@ [$($inner:tt)*] [(paren [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
260 $crate::__select_clean!(@ [$($out)* ($($inner)*)] [$($stack)*] $($rest)*)
261 };
262 (@ [$($inner:tt)*] [(bracket [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
263 $crate::__select_clean!(@ [$($out)* [$($inner)*]] [$($stack)*] $($rest)*)
264 };
265 (@ [$($inner:tt)*] [(brace [$($out:tt)*] [$($rest:tt)*]) $($stack:tt)*]) => {
266 $crate::__select_clean!(@ [$($out)* {$($inner)*}] [$($stack)*] $($rest)*)
267 };
268 (@ [$($out:tt)*] [$($stack:tt)*] ref $($rest:tt)*) => {
269 $crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
270 };
271 (@ [$($out:tt)*] [$($stack:tt)*] mut $($rest:tt)*) => {
272 $crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
273 };
274 (@ [$($out:tt)*] [$($stack:tt)*] & $($rest:tt)*) => {
275 $crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
276 };
277 (@ [$($out:tt)*] [$($stack:tt)*] && $($rest:tt)*) => {
278 $crate::__select_clean!(@ [$($out)*] [$($stack)*] $($rest)*)
279 };
280 (@ [$($out:tt)*] [$($stack:tt)*] ($($group:tt)*) $($rest:tt)*) => {
281 $crate::__select_clean!(@ [] [(paren [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
282 };
283 (@ [$($out:tt)*] [$($stack:tt)*] [$($group:tt)*] $($rest:tt)*) => {
284 $crate::__select_clean!(@ [] [(bracket [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
285 };
286 (@ [$($out:tt)*] [$($stack:tt)*] {$($group:tt)*} $($rest:tt)*) => {
287 $crate::__select_clean!(@ [] [(brace [$($out)*] [$($rest)*]) $($stack)*] $($group)*)
288 };
289 (@ [$($out:tt)*] [$($stack:tt)*] $next:tt $($rest:tt)*) => {
290 $crate::__select_clean!(@ [$($out)* $next] [$($stack)*] $($rest)*)
291 };
292 ($($pat:tt)+) => {
293 $crate::__select_clean!(@ [] [] $($pat)+)
294 };
295}