use alloc::boxed::Box;
use alloc::collections::VecDeque;
use alloc::rc::Rc;
use alloc::sync::Arc;
use alloc::task::Wake;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::future::Future;
use core::pin::Pin;
use core::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering::SeqCst};
use core::task::{Context, Poll, Waker};
use rt::sync::SpinLock;
pub use crate::Cancelled;
pub const BLOCKING_MAX: u32 = 8;
pub const PROGRESS_WAKE_MS: u64 = 30;
const BLOCKING_STACK: usize = 512 * 1024;
#[cfg(any(windows, target_os = "linux"))]
fn tid() -> u64 {
crate::plat_tid()
}
#[cfg(not(any(windows, target_os = "linux")))]
fn tid() -> u64 {
0
}
static VCLOCK: AtomicU64 = AtomicU64::new(u64::MAX);
pub fn now_us() -> u64 {
match VCLOCK.load(SeqCst) {
u64::MAX => crate::time_us(),
v => v,
}
}
pub fn clock_set(us: Option<u64>) {
VCLOCK.store(us.map_or(u64::MAX, |v| v.min(u64::MAX - 1)), SeqCst);
}
type Boxed = Pin<Box<dyn Future<Output = ()>>>;
struct Shared {
owner: u64,
park: Option<Arc<crate::Sem>>,
parked: bool,
local: SpinLock<Vec<(u32, u32)>>,
remote: SpinLock<Vec<(u32, u32)>>,
notified: AtomicBool,
}
impl Shared {
fn push(&self, e: (u32, u32)) {
let here = tid();
if here == self.owner && here != 0 {
self.local.lock().push(e);
} else if here == 0 {
self.local.lock().push(e);
self.signal();
} else {
self.remote.lock().push(e);
self.signal();
}
}
fn signal(&self) {
if !self.parked {
crate::wake();
} else if !self.notified.swap(true, SeqCst) {
if let Some(s) = &self.park {
s.post(1);
}
}
}
}
struct TaskWaker {
sh: Arc<Shared>,
slot: u32,
ver: u32,
queued: AtomicBool,
}
impl Wake for TaskWaker {
fn wake(self: Arc<Self>) {
self.wake_by_ref()
}
fn wake_by_ref(self: &Arc<Self>) {
if !self.queued.swap(true, SeqCst) {
self.sh.push((self.slot, self.ver));
}
}
}
struct Running {
fut: Boxed,
waker: Waker,
tw: Arc<TaskWaker>,
}
struct Slot {
ver: u32,
task: Option<Running>,
}
pub struct Executor {
sh: Arc<Shared>,
slots: Vec<Slot>,
free: Vec<u32>,
queue: Rc<RefCell<Vec<Boxed>>>,
live: usize,
}
impl Executor {
fn make(park: bool) -> Executor {
let sem = if park { crate::Sem::new(0).map(Arc::new) } else { None };
let sh = Shared {
owner: tid(),
parked: park,
park: sem,
local: SpinLock::new(Vec::new()),
remote: SpinLock::new(Vec::new()),
notified: AtomicBool::new(false),
};
Executor { sh: Arc::new(sh), slots: Vec::new(), free: Vec::new(), queue: Rc::new(RefCell::new(Vec::new())), live: 0 }
}
pub fn ui() -> Executor {
Executor::make(false)
}
pub fn new() -> Executor {
Executor::make(true)
}
pub fn spawner(&self) -> Spawner {
Spawner { q: self.queue.clone() }
}
pub fn spawn<F: Future + 'static>(&self, fut: F) -> Task<F::Output> {
self.spawner().spawn(fut)
}
fn insert(&mut self, fut: Boxed) {
let slot = match self.free.pop() {
Some(s) => s,
None => {
self.slots.push(Slot { ver: 0, task: None });
(self.slots.len() - 1) as u32
}
};
let ver = self.slots[slot as usize].ver;
let tw = Arc::new(TaskWaker { sh: self.sh.clone(), slot, ver, queued: AtomicBool::new(true) });
let waker = Waker::from(tw.clone());
self.slots[slot as usize].task = Some(Running { fut, waker, tw });
self.live += 1;
self.sh.local.lock().push((slot, ver));
}
pub fn accept_remote(&mut self) -> bool {
let mut r = core::mem::take(&mut *self.sh.remote.lock());
if r.is_empty() {
return false;
}
self.sh.local.lock().append(&mut r);
true
}
pub fn run(&mut self) -> usize {
let spawned = core::mem::take(&mut *self.queue.borrow_mut());
for f in spawned {
self.insert(f);
}
fire_timers(now_us());
run_inline(1);
let mut ready = core::mem::take(&mut *self.sh.local.lock());
if self.sh.parked {
ready.append(&mut core::mem::take(&mut *self.sh.remote.lock()));
}
let mut n = 0;
for (slot, ver) in ready {
let Some(s) = self.slots.get_mut(slot as usize) else { continue };
if s.ver != ver {
continue; }
let Some(r) = s.task.as_mut() else { continue };
r.tw.queued.store(false, SeqCst); n += 1;
let Running { fut, waker, .. } = r;
if fut.as_mut().poll(&mut Context::from_waker(waker)).is_ready() {
let done = s.task.take();
s.ver = s.ver.wrapping_add(1);
self.free.push(slot);
self.live -= 1;
drop(done); }
}
n
}
pub fn has_ready(&self) -> bool {
!self.queue.borrow().is_empty()
|| !self.sh.local.lock().is_empty()
|| (self.sh.parked && !self.sh.remote.lock().is_empty())
|| inline_pending()
}
pub fn busy(&self) -> bool {
self.has_ready() || !self.sh.remote.lock().is_empty() || blocking_pending() > 0
}
pub fn live(&self) -> usize {
self.live + self.queue.borrow().len()
}
pub fn block_on<F: Future>(&mut self, fut: F) -> F::Output {
let mut fut = core::pin::pin!(fut);
let main = Arc::new(MainWaker { sh: self.sh.clone(), woken: AtomicBool::new(true) });
let waker = Waker::from(main.clone());
loop {
self.sh.notified.store(false, SeqCst);
if main.woken.swap(false, SeqCst) {
if let Poll::Ready(v) = fut.as_mut().poll(&mut Context::from_waker(&waker)) {
return v;
}
}
self.run();
if main.woken.load(SeqCst) || self.has_ready() {
continue;
}
self.park();
}
}
fn park(&self) {
let ms = match next_timer() {
None => -1,
Some(at) => {
let now = now_us();
if at <= now {
return;
}
((at - now).saturating_add(999) / 1000).min(i32::MAX as u64) as i32
}
};
match &self.sh.park {
Some(s) => {
s.wait(ms);
}
None => crate::thread_yield(),
}
}
}
impl Default for Executor {
fn default() -> Self {
Executor::new()
}
}
struct MainWaker {
sh: Arc<Shared>,
woken: AtomicBool,
}
impl Wake for MainWaker {
fn wake(self: Arc<Self>) {
self.wake_by_ref()
}
fn wake_by_ref(self: &Arc<Self>) {
self.woken.store(true, SeqCst);
if tid() != self.sh.owner || tid() == 0 {
self.sh.signal();
}
}
}
pub fn block_on<F: Future>(fut: F) -> F::Output {
Executor::new().block_on(fut)
}
#[derive(Clone)]
pub struct Spawner {
q: Rc<RefCell<Vec<Boxed>>>,
}
impl Spawner {
pub fn spawn<F: Future + 'static>(&self, fut: F) -> Task<F::Output> {
let st = Arc::new(TaskState { flags: AtomicU32::new(0), out: SpinLock::new(None), waiter: SpinLock::new(None), me: SpinLock::new(None) });
let w = Wrap { fut: Some(Box::pin(fut)), st: st.clone() };
self.q.borrow_mut().push(Box::pin(w));
Task { st: Some(st) }
}
}
const T_DONE: u32 = 1;
const T_CANCEL: u32 = 2;
const T_DROPPED: u32 = 4;
struct TaskState<T> {
flags: AtomicU32,
out: SpinLock<Option<T>>,
waiter: SpinLock<Option<Waker>>,
me: SpinLock<Option<Waker>>,
}
impl<T> TaskState<T> {
fn finish(&self, v: Option<T>) {
let bits = if v.is_some() { T_DONE } else { T_DONE | T_DROPPED };
*self.out.lock() = v;
self.flags.fetch_or(bits, SeqCst);
*self.me.lock() = None;
let w = self.waiter.lock().take();
if let Some(w) = w {
w.wake();
}
}
fn cancel(&self) {
if self.flags.load(SeqCst) & (T_DONE | T_CANCEL) != 0 || self.flags.fetch_or(T_CANCEL, SeqCst) & (T_DONE | T_CANCEL) != 0 {
return;
}
let me = self.me.lock().clone();
if let Some(w) = me {
w.wake();
}
}
}
struct Wrap<F: Future> {
fut: Option<Pin<Box<F>>>,
st: Arc<TaskState<F::Output>>,
}
impl<F: Future> Future for Wrap<F> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = &mut *self;
if this.st.flags.load(SeqCst) & T_CANCEL != 0 {
this.fut = None;
this.st.finish(None);
return Poll::Ready(());
}
let Some(f) = this.fut.as_mut() else { return Poll::Ready(()) };
{
let mut me = this.st.me.lock();
if !me.as_ref().is_some_and(|w| w.will_wake(cx.waker())) {
*me = Some(cx.waker().clone());
}
}
match f.as_mut().poll(cx) {
Poll::Ready(v) => {
this.fut = None;
this.st.finish(Some(v));
Poll::Ready(())
}
Poll::Pending => Poll::Pending,
}
}
}
impl<F: Future> Drop for Wrap<F> {
fn drop(&mut self) {
if self.fut.take().is_some() {
self.st.finish(None); }
}
}
pub struct Task<T> {
st: Option<Arc<TaskState<T>>>,
}
impl<T> Task<T> {
pub fn is_done(&self) -> bool {
self.st.as_ref().is_none_or(|s| s.flags.load(SeqCst) & T_DONE != 0)
}
pub fn is_cancelled(&self) -> bool {
self.st.as_ref().is_some_and(|s| s.flags.load(SeqCst) & T_DROPPED != 0)
}
pub fn take(&self) -> Option<T> {
let s = self.st.as_ref()?;
if s.flags.load(SeqCst) & T_DONE == 0 {
return None;
}
s.out.lock().take()
}
pub fn cancel(&self) {
if let Some(s) = &self.st {
s.cancel();
}
}
pub fn detach(mut self) {
self.st = None;
}
}
impl<T> Drop for Task<T> {
fn drop(&mut self) {
if let Some(s) = &self.st {
s.cancel();
}
}
}
impl<T> Future for Task<T> {
type Output = Result<T, Cancelled>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let Some(s) = self.st.as_ref() else { return Poll::Ready(Err(Cancelled)) };
if s.flags.load(SeqCst) & T_DONE == 0 {
*s.waiter.lock() = Some(cx.waker().clone());
if s.flags.load(SeqCst) & T_DONE == 0 {
return Poll::Pending;
}
}
Poll::Ready(s.out.lock().take().ok_or(Cancelled))
}
}
struct Timer {
at: u64,
id: u64,
owner: u64,
waker: Waker,
}
static TIMERS: SpinLock<Vec<Timer>> = SpinLock::new(Vec::new());
static TIMER_ID: AtomicU64 = AtomicU64::new(1);
pub fn sleep(ms: u32) -> Sleep {
sleep_until(now_us().saturating_add(ms as u64 * 1000))
}
pub fn sleep_until(at_us: u64) -> Sleep {
Sleep { at: at_us, id: 0 }
}
pub struct Sleep {
at: u64,
id: u64,
}
impl Sleep {
pub fn deadline(&self) -> u64 {
self.at
}
}
impl Future for Sleep {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if now_us() >= self.at {
if self.id != 0 {
let id = core::mem::replace(&mut self.id, 0);
TIMERS.lock().retain(|t| t.id != id);
}
return Poll::Ready(());
}
let mut g = TIMERS.lock();
let found = if self.id == 0 { None } else { g.iter_mut().find(|t| t.id == self.id) };
match found {
Some(t) => {
if !t.waker.will_wake(cx.waker()) {
t.waker = cx.waker().clone();
}
t.owner = tid();
}
None => {
if self.id == 0 {
self.id = TIMER_ID.fetch_add(1, SeqCst);
}
g.push(Timer { at: self.at, id: self.id, owner: tid(), waker: cx.waker().clone() });
}
}
Poll::Pending
}
}
impl Drop for Sleep {
fn drop(&mut self) {
if self.id != 0 {
TIMERS.lock().retain(|t| t.id != self.id);
}
}
}
pub fn fire_timers(now: u64) -> usize {
let me = tid();
let mut due = Vec::new();
{
let mut g = TIMERS.lock();
let mut i = 0;
while i < g.len() {
if g[i].owner == me && g[i].at <= now {
let t = g.remove(i);
due.push((t.at, t.id, t.waker));
} else {
i += 1;
}
}
}
due.sort_by_key(|d| (d.0, d.1)); let n = due.len();
for (_, _, w) in due {
w.wake();
}
n
}
pub fn next_timer() -> Option<u64> {
let me = tid();
TIMERS.lock().iter().filter(|t| t.owner == me).map(|t| t.at).min()
}
pub fn yield_now() -> YieldNow {
YieldNow(false)
}
pub struct YieldNow(bool);
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
return Poll::Ready(());
}
self.0 = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
type BJob = Box<dyn FnOnce() + Send>;
struct BPool {
jobs: VecDeque<BJob>,
sem: Option<Arc<crate::Sem>>,
threads: u32,
idle: u32,
no_threads: bool,
}
static BPOOL: SpinLock<BPool> = SpinLock::new(BPool { jobs: VecDeque::new(), sem: None, threads: 0, idle: 0, no_threads: false });
static INFLIGHT: AtomicU32 = AtomicU32::new(0);
pub fn blocking_pending() -> u32 {
INFLIGHT.load(SeqCst)
}
fn submit(job: BJob) {
let mut g = BPOOL.lock();
g.jobs.push_back(job);
if g.no_threads {
return; }
if g.sem.is_none() {
g.sem = crate::Sem::new(0).map(Arc::new);
}
let Some(sem) = g.sem.clone() else {
g.no_threads = true;
return;
};
let start = g.jobs.len() as u32 > g.idle && g.threads < BLOCKING_MAX;
if start {
g.threads += 1;
}
drop(g);
if start {
let s = sem.clone();
if crate::thread_spawn(BLOCKING_STACK, Box::new(move || blocking_worker(s))).is_none() {
let mut g = BPOOL.lock();
g.threads -= 1;
if g.threads == 0 {
g.no_threads = true;
}
}
}
sem.post(1);
}
fn blocking_worker(sem: Arc<crate::Sem>) {
loop {
let job = {
let mut g = BPOOL.lock();
let j = g.jobs.pop_front();
if j.is_none() {
g.idle += 1;
}
j
};
match job {
Some(j) => j(),
None => {
sem.wait(-1);
BPOOL.lock().idle -= 1;
}
}
}
}
fn inline_pending() -> bool {
let g = BPOOL.lock();
g.no_threads && !g.jobs.is_empty()
}
fn run_inline(n: usize) {
for _ in 0..n {
let job = {
let mut g = BPOOL.lock();
if !g.no_threads {
return;
}
g.jobs.pop_front()
};
match job {
Some(j) => j(),
None => return,
}
}
}
struct Cell<T> {
val: SpinLock<Option<T>>,
waker: SpinLock<Option<Waker>>,
done: AtomicBool,
}
pub struct Blocking<T> {
cell: Arc<Cell<T>>,
tok: CancelToken,
taken: bool,
}
pub fn spawn_blocking<T: Send + 'static>(f: impl FnOnce() -> T + Send + 'static) -> Blocking<T> {
spawn_cancellable(move |_| f())
}
pub fn spawn_cancellable<T: Send + 'static>(f: impl FnOnce(&CancelToken) -> T + Send + 'static) -> Blocking<T> {
let cell = Arc::new(Cell { val: SpinLock::new(None), waker: SpinLock::new(None), done: AtomicBool::new(false) });
let tok = CancelToken::new();
let (c, t) = (cell.clone(), tok.clone());
let trusted = crate::policy::trusted_here();
let scopes = crate::policy::scopes_here(); INFLIGHT.fetch_add(1, SeqCst);
submit(Box::new(move || {
if !t.is_cancelled() {
let run = || if trusted { crate::policy::trusted_scope(|| f(&t)) } else { f(&t) };
let v = crate::policy::in_scopes(&scopes, run);
*c.val.lock() = Some(v);
} else {
drop(f); }
c.done.store(true, SeqCst);
let w = c.waker.lock().take();
if let Some(w) = w {
w.wake();
}
INFLIGHT.fetch_sub(1, SeqCst); }));
Blocking { cell, tok, taken: false }
}
impl<T> Blocking<T> {
pub fn is_done(&self) -> bool {
self.cell.done.load(SeqCst)
}
}
impl<T> Future for Blocking<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
if !self.cell.done.load(SeqCst) {
*self.cell.waker.lock() = Some(cx.waker().clone());
if !self.cell.done.load(SeqCst) {
return Poll::Pending;
}
}
let v = self.cell.val.lock().take();
match v {
Some(v) => {
self.taken = true;
Poll::Ready(v)
}
None => Poll::Pending, }
}
}
impl<T> Drop for Blocking<T> {
fn drop(&mut self) {
if !self.taken {
self.tok.cancel();
}
}
}
struct CancelInner {
flag: AtomicBool,
waiters: SpinLock<Vec<(u64, Waker)>>,
}
#[derive(Clone)]
pub struct CancelToken(Arc<CancelInner>);
static WAIT_ID: AtomicU64 = AtomicU64::new(1);
impl CancelToken {
pub fn new() -> CancelToken {
CancelToken(Arc::new(CancelInner { flag: AtomicBool::new(false), waiters: SpinLock::new(Vec::new()) }))
}
pub fn cancel(&self) {
if self.0.flag.swap(true, SeqCst) {
return;
}
let w = core::mem::take(&mut *self.0.waiters.lock());
for (_, w) in w {
w.wake();
}
}
pub fn is_cancelled(&self) -> bool {
self.0.flag.load(SeqCst)
}
pub fn check(&self) -> Result<(), Cancelled> {
if self.is_cancelled() { Err(Cancelled) } else { Ok(()) }
}
pub fn cancelled(&self) -> WaitCancelled {
WaitCancelled { tok: self.clone(), id: 0 }
}
pub fn run<F: Future>(&self, fut: F) -> Guarded<F> {
Guarded { fut: Some(Box::pin(fut)), wait: self.cancelled() }
}
}
impl Default for CancelToken {
fn default() -> Self {
CancelToken::new()
}
}
pub struct WaitCancelled {
tok: CancelToken,
id: u64,
}
impl Future for WaitCancelled {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.tok.is_cancelled() {
return Poll::Ready(());
}
if self.id == 0 {
self.id = WAIT_ID.fetch_add(1, SeqCst);
}
{
let mut g = self.tok.0.waiters.lock();
match g.iter_mut().find(|(i, _)| *i == self.id) {
Some((_, w)) => {
if !w.will_wake(cx.waker()) {
*w = cx.waker().clone();
}
}
None => g.push((self.id, cx.waker().clone())),
}
}
if self.tok.is_cancelled() { Poll::Ready(()) } else { Poll::Pending }
}
}
impl Drop for WaitCancelled {
fn drop(&mut self) {
if self.id != 0 {
let id = self.id;
self.tok.0.waiters.lock().retain(|(i, _)| *i != id);
}
}
}
pub struct Guarded<F: Future> {
fut: Option<Pin<Box<F>>>,
wait: WaitCancelled,
}
impl<F: Future> Unpin for Guarded<F> {}
impl<F: Future> Future for Guarded<F> {
type Output = Result<F::Output, Cancelled>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = &mut *self;
if this.wait.tok.is_cancelled() {
this.fut = None;
return Poll::Ready(Err(Cancelled));
}
let Some(f) = this.fut.as_mut() else { return Poll::Ready(Err(Cancelled)) };
if let Poll::Ready(v) = f.as_mut().poll(cx) {
this.fut = None;
return Poll::Ready(Ok(v));
}
if Pin::new(&mut this.wait).poll(cx).is_ready() {
this.fut = None;
return Poll::Ready(Err(Cancelled));
}
Poll::Pending
}
}
struct ProgInner {
done: AtomicU64,
total: AtomicU64,
seq: AtomicU64,
last_wake: AtomicU64,
waiters: SpinLock<Vec<Waker>>,
}
#[derive(Clone)]
pub struct Progress(Arc<ProgInner>);
impl Progress {
pub fn new() -> Progress {
Progress(Arc::new(ProgInner {
done: AtomicU64::new(0),
total: AtomicU64::new(0),
seq: AtomicU64::new(0),
last_wake: AtomicU64::new(0),
waiters: SpinLock::new(Vec::new()),
}))
}
pub fn set_total(&self, n: u64) {
self.0.total.store(n, SeqCst);
self.report();
}
pub fn set(&self, done: u64) {
self.0.done.store(done, SeqCst);
self.report();
}
pub fn add(&self, n: u64) {
self.0.done.fetch_add(n, SeqCst);
self.report();
}
pub fn done(&self) -> u64 {
self.0.done.load(SeqCst)
}
pub fn total(&self) -> u64 {
self.0.total.load(SeqCst)
}
pub fn permille(&self) -> u32 {
let (d, t) = (self.done(), self.total());
if t == 0 { 0 } else { (d.min(t) as u128 * 1000 / t as u128) as u32 }
}
pub fn reports(&self) -> u64 {
self.0.seq.load(SeqCst)
}
pub fn changed(&self) -> Changed {
Changed { p: self.clone(), seen: self.reports() }
}
fn report(&self) {
self.0.seq.fetch_add(1, SeqCst);
let w = core::mem::take(&mut *self.0.waiters.lock());
for w in w {
w.wake();
}
let now = crate::time_us();
let last = self.0.last_wake.load(SeqCst);
let end = self.total() != 0 && self.done() >= self.total();
if end || now.wrapping_sub(last) >= PROGRESS_WAKE_MS * 1000 {
self.0.last_wake.store(now, SeqCst);
crate::wake();
}
}
}
impl Default for Progress {
fn default() -> Self {
Progress::new()
}
}
pub struct Changed {
p: Progress,
seen: u64,
}
impl Future for Changed {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.p.reports() != self.seen {
return Poll::Ready(());
}
{
let mut g = self.p.0.waiters.lock();
if !g.iter().any(|w| w.will_wake(cx.waker())) {
g.push(cx.waker().clone());
}
}
if self.p.reports() != self.seen { Poll::Ready(()) } else { Poll::Pending }
}
}
enum MaybeDone<F: Future> {
Run(Pin<Box<F>>),
Done(Option<F::Output>),
}
impl<F: Future> MaybeDone<F> {
fn new(f: F) -> Self {
MaybeDone::Run(Box::pin(f))
}
fn poll(&mut self, cx: &mut Context<'_>) -> bool {
if let MaybeDone::Run(f) = self {
match f.as_mut().poll(cx) {
Poll::Ready(v) => *self = MaybeDone::Done(Some(v)),
Poll::Pending => return false,
}
}
true
}
fn take(&mut self) -> F::Output {
match self {
MaybeDone::Done(v) => v.take().expect("join: polled after completion"),
MaybeDone::Run(_) => unreachable!(),
}
}
}
pub struct Join<A: Future, B: Future>(MaybeDone<A>, MaybeDone<B>);
impl<A: Future, B: Future> Unpin for Join<A, B> {}
pub fn join<A: Future, B: Future>(a: A, b: B) -> Join<A, B> {
Join(MaybeDone::new(a), MaybeDone::new(b))
}
impl<A: Future, B: Future> Future for Join<A, B> {
type Output = (A::Output, B::Output);
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = &mut *self;
let a = this.0.poll(cx);
let b = this.1.poll(cx);
if a && b { Poll::Ready((this.0.take(), this.1.take())) } else { Poll::Pending }
}
}
pub struct Join3<A: Future, B: Future, C: Future>(MaybeDone<A>, MaybeDone<B>, MaybeDone<C>);
impl<A: Future, B: Future, C: Future> Unpin for Join3<A, B, C> {}
pub fn join3<A: Future, B: Future, C: Future>(a: A, b: B, c: C) -> Join3<A, B, C> {
Join3(MaybeDone::new(a), MaybeDone::new(b), MaybeDone::new(c))
}
impl<A: Future, B: Future, C: Future> Future for Join3<A, B, C> {
type Output = (A::Output, B::Output, C::Output);
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = &mut *self;
let a = this.0.poll(cx);
let b = this.1.poll(cx);
let c = this.2.poll(cx);
if a && b && c { Poll::Ready((this.0.take(), this.1.take(), this.2.take())) } else { Poll::Pending }
}
}
pub struct JoinAll<F: Future>(Vec<MaybeDone<F>>);
impl<F: Future> Unpin for JoinAll<F> {}
pub fn join_all<F: Future>(v: impl IntoIterator<Item = F>) -> JoinAll<F> {
JoinAll(v.into_iter().map(MaybeDone::new).collect())
}
impl<F: Future> Future for JoinAll<F> {
type Output = Vec<F::Output>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut all = true;
for f in self.0.iter_mut() {
all &= f.poll(cx);
}
if all { Poll::Ready(self.0.iter_mut().map(|f| f.take()).collect()) } else { Poll::Pending }
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Either<A, B> {
Left(A),
Right(B),
}
pub struct Select<A: Future, B: Future>(Pin<Box<A>>, Pin<Box<B>>);
pub fn select<A: Future, B: Future>(a: A, b: B) -> Select<A, B> {
Select(Box::pin(a), Box::pin(b))
}
impl<A: Future, B: Future> Future for Select<A, B> {
type Output = Either<A::Output, B::Output>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Poll::Ready(v) = self.0.as_mut().poll(cx) {
return Poll::Ready(Either::Left(v));
}
if let Poll::Ready(v) = self.1.as_mut().poll(cx) {
return Poll::Ready(Either::Right(v));
}
Poll::Pending
}
}