#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BiasedRace2<A, B> {
First(A),
Second(B),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BiasedRace3<A, B, C> {
First(A),
Second(B),
Third(C),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BiasedRace4<A, B, C, D> {
First(A),
Second(B),
Third(C),
Fourth(D),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FairRace2<A, B> {
First(A),
Second(B),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FairRace4<A, B, C, D> {
First(A),
Second(B),
Third(C),
Fourth(D),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FairRace3<A, B, C> {
First(A),
Second(B),
Third(C),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FairRace5<A, B, C, D, E> {
First(A),
Second(B),
Third(C),
Fourth(D),
Fifth(E),
}
use std::sync::atomic::{AtomicU64, Ordering};
static FAIR_RACE_SEED: AtomicU64 = AtomicU64::new(0x9E37_79B9_7F4A_7C15);
#[doc(hidden)]
pub fn fair_start(branches: usize) -> usize {
let mut state = FAIR_RACE_SEED.fetch_add(0x9E37_79B9_7F4A_7C15, Ordering::Relaxed);
state ^= state >> 30;
state = state.wrapping_mul(0xBF58_476D_1CE4_E5B9);
state ^= state >> 27;
state = state.wrapping_mul(0x94D0_49BB_1331_11EB);
(state ^ (state >> 31)) as usize % branches
}
#[macro_export]
macro_rules! fair_race {
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?), ($third:expr $(; $third_guard:expr)?), ($fourth:expr $(; $fourth_guard:expr)?), ($fifth:expr $(; $fifth_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?; let second_enabled = true $(&& $second_guard)?; let third_enabled = true $(&& $third_guard)?; let fourth_enabled = true $(&& $fourth_guard)?; let fifth_enabled = true $(&& $fifth_guard)?;
let mut first = $first; let mut second = $second; let mut third = $third; let mut fourth = $fourth; let mut fifth = $fifth;
let start = $crate::async_engine::__fair_race_start(5);
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled && !third_enabled && !fourth_enabled && !fifth_enabled { panic!("fair race has no enabled branches"); }
for branch in [start, (start+1)%5, (start+2)%5, (start+3)%5, (start+4)%5] {
match branch {
0 if first_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace5::First(v)); },
1 if second_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace5::Second(v)); },
2 if third_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(third.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace5::Third(v)); },
3 if fourth_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(fourth.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace5::Fourth(v)); },
4 if fifth_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(fifth.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace5::Fifth(v)); },
_ => {}
}
}
std::task::Poll::Pending
}).await
}
}};
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?), ($third:expr $(; $third_guard:expr)?), ($fourth:expr $(; $fourth_guard:expr)?) $(,)?) => {{
async {
let enabled = [
true $(&& $first_guard)?, true $(&& $second_guard)?,
true $(&& $third_guard)?, true $(&& $fourth_guard)?,
];
let mut first = $first;
let mut second = $second;
let mut third = $third;
let mut fourth = $fourth;
let start = $crate::async_engine::__fair_race_start(4);
std::future::poll_fn(move |cx| {
assert!(enabled.iter().any(|value| *value), "fair race has no enabled branches");
for offset in 0..4 {
let branch = (start + offset) % 4;
if !enabled[branch] { continue; }
match branch {
0 => if let std::task::Poll::Ready(value) = std::future::Future::poll(first.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace4::First(value));
},
1 => if let std::task::Poll::Ready(value) = std::future::Future::poll(second.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace4::Second(value));
},
2 => if let std::task::Poll::Ready(value) = std::future::Future::poll(third.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace4::Third(value));
},
_ => if let std::task::Poll::Ready(value) = std::future::Future::poll(fourth.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace4::Fourth(value));
},
}
}
std::task::Poll::Pending
}).await
}
}};
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?), ($third:expr $(; $third_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?;
let second_enabled = true $(&& $second_guard)?;
let third_enabled = true $(&& $third_guard)?;
let mut first = $first; let mut second = $second; let mut third = $third;
let start = $crate::async_engine::__fair_race_start(3);
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled && !third_enabled { panic!("fair race has no enabled branches"); }
for branch in [start, (start + 1) % 3, (start + 2) % 3] {
match branch {
0 if first_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace3::First(v)); },
1 if second_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace3::Second(v)); },
2 if third_enabled => if let std::task::Poll::Ready(v) = std::future::Future::poll(third.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::FairRace3::Third(v)); },
_ => {}
}
}
std::task::Poll::Pending
}).await
}
}};
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?;
let second_enabled = true $(&& $second_guard)?;
let mut first = $first;
let mut second = $second;
let first_turn = $crate::async_engine::__fair_race_start(2) == 0;
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled { panic!("fair race has no enabled branches"); }
if first_turn {
if first_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace2::First(v));
} }
if second_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace2::Second(v));
} }
} else {
if second_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace2::Second(v));
} }
if first_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::FairRace2::First(v));
} }
}
std::task::Poll::Pending
}).await
}
}};
}
#[macro_export]
macro_rules! biased_race {
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?;
let second_enabled = true $(&& $second_guard)?;
let mut first = $first;
let mut second = $second;
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled { panic!("biased race has no enabled branches"); }
if first_enabled {
if let std::task::Poll::Ready(value) = std::future::Future::poll(first.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::BiasedRace2::First(value));
}
}
if second_enabled {
if let std::task::Poll::Ready(value) = std::future::Future::poll(second.as_mut(), cx) {
return std::task::Poll::Ready($crate::async_engine::BiasedRace2::Second(value));
}
}
std::task::Poll::Pending
}).await
}
}};
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?), ($third:expr $(; $third_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?; let second_enabled = true $(&& $second_guard)?; let third_enabled = true $(&& $third_guard)?;
let mut first = $first; let mut second = $second; let mut third = $third;
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled && !third_enabled { panic!("biased race has no enabled branches"); }
if first_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace3::First(v)); } }
if second_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace3::Second(v)); } }
if third_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(third.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace3::Third(v)); } }
std::task::Poll::Pending
}).await
}
}};
(($first:expr $(; $first_guard:expr)?), ($second:expr $(; $second_guard:expr)?), ($third:expr $(; $third_guard:expr)?), ($fourth:expr $(; $fourth_guard:expr)?) $(,)?) => {{
async {
let first_enabled = true $(&& $first_guard)?; let second_enabled = true $(&& $second_guard)?; let third_enabled = true $(&& $third_guard)?; let fourth_enabled = true $(&& $fourth_guard)?;
let mut first = $first; let mut second = $second; let mut third = $third; let mut fourth = $fourth;
std::future::poll_fn(move |cx| {
if !first_enabled && !second_enabled && !third_enabled && !fourth_enabled { panic!("biased race has no enabled branches"); }
if first_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(first.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace4::First(v)); } }
if second_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(second.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace4::Second(v)); } }
if third_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(third.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace4::Third(v)); } }
if fourth_enabled { if let std::task::Poll::Ready(v) = std::future::Future::poll(fourth.as_mut(), cx) { return std::task::Poll::Ready($crate::async_engine::BiasedRace4::Fourth(v)); } }
std::task::Poll::Pending
}).await
}
}};
}