mod ae_task; mod ae_yield; pub use {crate::async_engine::ae_yield::Yield, ae_task::SpawnedFuture}; use { crate::{ async_engine::ae_task::Runnable, utils::{array, numcell::NumCell, syncqueue::SyncQueue}, }, std::{ cell::{Cell, RefCell}, collections::VecDeque, future::Future, rc::Rc, task::Waker, }, }; #[derive(Copy, Clone, Eq, PartialEq)] pub enum Phase { EventHandling, Layout, PostLayout, Present, } const NUM_PHASES: usize = 4; pub struct AsyncEngine { num_queued: NumCell, queues: [SyncQueue; NUM_PHASES], iteration: NumCell, yields: SyncQueue, stash: RefCell>, yield_stash: RefCell>, stopped: Cell, } impl AsyncEngine { pub fn new() -> Rc { Rc::new(Self { num_queued: Default::default(), queues: array::from_fn(|_| Default::default()), iteration: Default::default(), yields: Default::default(), stash: Default::default(), yield_stash: Default::default(), stopped: Cell::new(false), }) } pub fn stop(&self) { self.stopped.set(true); } pub fn clear(&self) { self.stash.borrow_mut().clear(); self.yield_stash.borrow_mut().clear(); self.yields.take(); for queue in &self.queues { queue.take(); } } pub fn spawn + 'static>(self: &Rc, f: F) -> SpawnedFuture { self.spawn_(Phase::EventHandling, f) } pub fn spawn2 + 'static>( self: &Rc, phase: Phase, f: F, ) -> SpawnedFuture { self.spawn_(phase, f) } pub fn yield_now(self: &Rc) -> Yield { Yield { iteration: self.iteration(), queue: self.clone(), } } pub fn dispatch(&self) { let mut stash = self.stash.borrow_mut(); let mut yield_stash = self.yield_stash.borrow_mut(); while self.num_queued.get() > 0 { self.iteration.fetch_add(1); let mut phase = 0; while phase < NUM_PHASES as usize { self.queues[phase].swap(&mut *stash); if stash.is_empty() { phase += 1; continue; } self.num_queued.fetch_sub(stash.len()); for runnable in stash.drain(..) { runnable.run(); if self.stopped.get() { return; } } } self.yields.swap(&mut *yield_stash); for waker in yield_stash.drain(..) { waker.wake(); } } } fn push(&self, runnable: Runnable, phase: Phase) { self.queues[phase as usize].push(runnable); self.num_queued.fetch_add(1); } fn push_yield(&self, waker: Waker) { self.yields.push(waker); } fn iteration(&self) -> u64 { self.iteration.get() } }