use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use dope_core::driver::{Backend, CompletionBackend, DriverLifecycle};
pub type ManifoldDriver<M> = <<M as Manifold>::Backend as Backend>::Driver;
pub trait Manifold {
type Backend: CompletionBackend;
fn has_pending(&self, _driver: &mut ManifoldDriver<Self>) -> bool {
false
}
fn drive(&mut self, driver: &mut ManifoldDriver<Self>);
fn park_timeout(&mut self) -> Option<std::time::Duration> {
None
}
}
pub struct Runtime<R: Manifold> {
pub(crate) reactor: R,
pub(crate) driver: ManifoldDriver<R>,
shutdown: Option<Arc<AtomicBool>>,
}
impl<R: Manifold> Runtime<R> {
pub fn new(reactor: R, driver: ManifoldDriver<R>) -> Self {
Self {
reactor,
driver,
shutdown: None,
}
}
pub fn with_shutdown(mut self, shutdown: Option<Arc<AtomicBool>>) -> Self {
self.shutdown = shutdown;
self
}
pub fn run_forever(mut self) -> std::io::Result<()> {
let Self {
reactor,
driver,
shutdown,
} = &mut self;
let driver_ptr: *mut ManifoldDriver<R> = &mut *driver;
R::Backend::set_current(driver_ptr);
loop {
if shutdown
.as_ref()
.is_some_and(|flag| flag.load(Ordering::Relaxed))
{
return Ok(());
}
reactor.drive(driver);
if reactor.has_pending(driver) {
let _ = driver.submit_only();
} else if let Some(timeout) = reactor.park_timeout() {
let _ = driver.park_for(timeout);
} else {
let _ = driver.park();
}
}
}
}