use std::io;
use std::sync::{Arc, Mutex};
use windows_ioring_sys::{CompletionWake, IoBuf, IoBufMut};
use windows_threadpool_sys::callback_env::CallbackEnviron;
use super::WindowsBackend;
use durable_ioring::EpochId;
use durable_ioring::StampClock;
use durable_ioring::driver::{Engine, EngineGuard, Slot, lock, present};
#[cfg(test)]
mod tests;
pub(crate) type PoolEngine<E, B, C, K, R> = Engine<E, WindowsBackend<B, R>, C, K>;
pub(crate) type Shared<E, B, C, K, R> = Slot<E, WindowsBackend<B, R>, C, K>;
pub(crate) type PoolSetup<E, B, C, K, R> =
Result<PoolDelivery<E, B, C, K, R>, (io::Error, Box<PoolEngine<E, B, C, K, R>>)>;
pub(crate) struct PoolDelivery<E, B, C, K, R>
where
E: EpochId + 'static,
B: IoBuf,
R: IoBufMut,
K: StampClock,
{
wake: CompletionWake,
engine: Shared<E, B, C, K, R>,
}
impl<E, B, C, K, R> PoolDelivery<E, B, C, K, R>
where
E: EpochId + Send + Sync + 'static,
B: IoBuf + Send + 'static,
C: Send + 'static,
K: StampClock,
K::Instant: Send + Sync,
R: IoBufMut + Send + 'static,
{
pub(crate) fn new(
engine: PoolEngine<E, B, C, K, R>,
on_ready: impl Fn() + Send + Sync + 'static,
env: Option<&mut CallbackEnviron<'_>>,
) -> PoolSetup<E, B, C, K, R> {
let engine = Arc::new(Mutex::new(Some(engine)));
let drained = Arc::clone(&engine);
let on_wake = move || {
let deliver = lock(&drained).as_mut().is_some_and(Engine::drain);
if deliver {
on_ready();
}
};
let woken = present(lock(&engine)).backend.wake(on_wake, env);
match woken {
Ok(wake) => Ok(Self { wake, engine }),
Err(error) => {
let engine = lock(&engine).take().expect("put there above");
Err((error, Box::new(engine)))
}
}
}
}
impl<E, B, C, K, R> PoolDelivery<E, B, C, K, R>
where
E: EpochId + 'static,
B: IoBuf,
R: IoBufMut,
K: StampClock,
{
pub(crate) fn engine(&self) -> EngineGuard<'_, PoolEngine<E, B, C, K, R>> {
present(lock(&self.engine))
}
pub(crate) fn shared(&self) -> Shared<E, B, C, K, R> {
Arc::clone(&self.engine)
}
pub(crate) fn into_engine(self) -> PoolEngine<E, B, C, K, R> {
let Self { wake, engine } = self;
drop(wake);
lock(&engine)
.take()
.expect("only stopping delivery takes the engine")
}
}