futures_concurrency/utils/
tuple.rs

1/// Generate the `match` conditions inside the main polling body. This macro
2/// chooses a random starting point on each call to the given method, making
3/// it "fair".
4///
5/// The way this algorithm works is: we generate a random number between 0 and
6/// the length of the tuple we have. This number determines which element we
7/// start with. All other cases are mapped as `r + index`, and after we have the
8/// first one, we'll sequentially iterate over all others. The starting point of
9/// the stream is random, but the iteration order of all others is not.
10// NOTE(yosh): this macro monstrosity is needed so we can increment each `else
11// if` branch with + 1. When RFC 3086 becomes available to us, we can replace
12// this with `${index($F)}` to get the current iteration.
13//
14// # References
15// - https://twitter.com/maybewaffle/status/1588426440835727360
16// - https://twitter.com/Veykril/status/1588231414998335490
17// - https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
18macro_rules! gen_conditions {
19    // Base condition, setup the depth counter.
20    ($i:expr, $this:expr, $cx:expr, $method:ident, $(($F_index: expr; $F:ident, { $($arms:pat => $foo:expr,)* }))*) => {
21        $(
22            if $i == $F_index {
23                match unsafe { Pin::new_unchecked(&mut $this.$F) }.$method($cx) {
24                    $($arms => $foo,)*
25                }
26            }
27        )*
28    }
29}
30pub(crate) use gen_conditions;
31
32/// Calculate the number of tuples currently being operated on.
33macro_rules! tuple_len {
34    (@count_one $F:ident) => (1);
35    ($($F:ident,)*) => (0 $(+ crate::utils::tuple_len!(@count_one $F))*);
36}
37pub(crate) use tuple_len;