use super::*;
use executors::*;
pub trait Scheduler: Send + Sync {
fn schedule(&self, c: Arc<dyn CoreContainer>) -> ();
fn shutdown_async(&self) -> ();
fn shutdown(&self) -> Result<(), String>;
fn box_clone(&self) -> Box<dyn Scheduler>;
fn poison(&self) -> ();
fn spawn(&self, future: futures::future::BoxFuture<'static, ()>) -> ();
}
impl Clone for Box<dyn Scheduler> {
fn clone(&self) -> Self {
(*self).box_clone()
}
}
#[derive(Clone)]
pub struct ExecutorScheduler<E>
where
E: FuturesExecutor + Sync,
{
exec: E,
}
impl<E: FuturesExecutor + Sync + 'static> ExecutorScheduler<E> {
pub fn with(exec: E) -> ExecutorScheduler<E> {
ExecutorScheduler { exec }
}
pub fn from(exec: E) -> Box<dyn Scheduler> {
Box::new(ExecutorScheduler::with(exec))
}
}
impl<E: FuturesExecutor + Sync + 'static> Scheduler for ExecutorScheduler<E> {
fn schedule(&self, c: Arc<dyn CoreContainer>) -> () {
self.exec.execute(move || maybe_reschedule(c));
}
fn shutdown_async(&self) -> () {
self.exec.shutdown_async()
}
fn shutdown(&self) -> Result<(), String> {
self.exec.shutdown_borrowed()
}
fn box_clone(&self) -> Box<dyn Scheduler> {
Box::new(self.clone())
}
fn poison(&self) -> () {
self.exec.shutdown_async();
}
fn spawn(&self, future: futures::future::BoxFuture<'static, ()>) -> () {
let handle = self.exec.spawn(future);
handle.detach();
}
}
fn maybe_reschedule(c: Arc<dyn CoreContainer>) {
match c.execute() {
SchedulingDecision::Schedule => {
if cfg!(feature = "use_local_executor") {
let res = try_execute_locally(move || maybe_reschedule(c));
assert!(res.is_ok(), "Only run with Executors that can support local execute or remove the avoid_executor_lookups feature!");
} else {
let c2 = c.clone();
c.system().schedule(c2);
}
}
SchedulingDecision::Resume => maybe_reschedule(c),
_ => (),
}
}