use std::io;
use std::os::windows::io::OwnedHandle;
use std::time::Duration;
use win_sync_sys::{Event, ResetMode};
use windows_ioring_sys::{CompletionWake, IoBuf, IoBufMut};
use windows_threadpool_sys::callback_env::CallbackEnviron;
use super::WindowsBackend;
use super::pool::{PoolEngine, Shared};
use durable_ioring::StampClock;
use super::CompletionEvent;
use durable_ioring::EpochId;
use durable_ioring::driver::EngineGuard;
use durable_ioring::driver::{Pumped, PumpedDelivery};
pub(crate) type SignalledSetup<E, B, C, K, R> =
Result<SignalledDelivery<E, B, C, K, R>, (io::Error, Box<PoolEngine<E, B, C, K, R>>)>;
pub(crate) struct SignalledDelivery<E, B, C, K, R>
where
E: EpochId + 'static,
B: IoBuf,
R: IoBufMut,
K: StampClock,
{
wake: CompletionWake,
pumped: PumpedDelivery<E, WindowsBackend<B, R>, C, K>,
signal: Event,
}
impl<E, B, C, K, R> SignalledDelivery<E, B, C, K, R>
where
E: EpochId + 'static,
B: IoBuf,
R: IoBufMut,
K: StampClock,
{
pub(crate) fn new(
mut engine: PoolEngine<E, B, C, K, R>,
env: Option<&mut CallbackEnviron<'_>>,
) -> SignalledSetup<E, B, C, K, R> {
let made = Event::new(ResetMode::Auto, false).and_then(|signal| {
let waker = signal.try_clone()?;
let notification = CompletionEvent::new(OwnedHandle::from(signal.try_clone()?));
Ok((signal, waker, notification))
});
let (signal, waker, notification) = match made {
Ok(made) => made,
Err(error) => return Err((error, Box::new(engine))),
};
let on_wake = move || {
let set = waker.set();
debug_assert!(set.is_ok(), "setting the completion signal failed: {set:?}");
};
let wake = match engine.backend.wake(on_wake, env) {
Ok(wake) => wake,
Err(error) => return Err((error, Box::new(engine))),
};
Ok(Self {
wake,
pumped: PumpedDelivery::with_notification(engine, notification),
signal,
})
}
pub(crate) fn signal(&self) -> io::Result<Event> {
self.signal.try_clone()
}
pub(crate) fn pump(&mut self, timeout: Option<Duration>) -> Pumped {
self.pumped.pump(timeout)
}
pub(crate) fn engine(&self) -> EngineGuard<'_, PoolEngine<E, B, C, K, R>> {
self.pumped.engine()
}
pub(crate) fn shared(&self) -> Shared<E, B, C, K, R> {
self.pumped.shared()
}
pub(crate) fn into_engine(self) -> PoolEngine<E, B, C, K, R> {
let Self { wake, pumped, .. } = self;
drop(wake);
pumped.into_engine()
}
}