use std::io;
use std::sync::{Arc, Mutex, MutexGuard};
use windows_sys::Win32::Storage::FileSystem::IORING_OP_CODE;
use windows_threadpool_sys::callback_env::CallbackEnviron;
use crate::batch::Batch;
use crate::capability::RingVersion;
use crate::completion_wake::CompletionWake;
use crate::ring::{Completion, IoRing, Op, RingInfo};
type OnCompletion<T, X> = dyn Fn(Completion, Option<(Option<T>, X)>) + Send + Sync;
fn drain<T, X>(ring: &Mutex<IoRing<T, X>>, on_completion: &OnCompletion<T, X>) {
loop {
let popped = {
let mut ring = ring
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
ring.try_pop()
};
match popped {
Ok(Some((completion, held))) => on_completion(completion, held),
Ok(None) => break,
Err(error) => {
debug_assert!(
false,
"IoRing::try_pop failed during event-driven drain: {error}"
);
break;
}
}
}
}
pub struct EventDelivery<T = (), X = ()> {
#[expect(
dead_code,
reason = "held for its Drop, which stops the wait and drains it before the ring is released"
)]
wake: CompletionWake,
ring: Arc<Mutex<IoRing<T, X>>>,
}
impl<T: Send + 'static, X: Send + 'static> EventDelivery<T, X> {
pub fn new<F>(
ring: IoRing<T, X>,
on_completion: F,
env: Option<&mut CallbackEnviron<'_>>,
) -> io::Result<Self>
where
F: Fn(Completion, Option<(Option<T>, X)>) + Send + Sync + 'static,
{
let on_completion: Arc<OnCompletion<T, X>> = Arc::new(on_completion);
let ring = Arc::new(Mutex::new(ring));
let ring_for_wake = Arc::clone(&ring);
let wake = CompletionWake::new(
&mut *ring
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner),
move || drain(&ring_for_wake, on_completion.as_ref()),
env,
)?;
Ok(Self { wake, ring })
}
#[must_use]
pub fn scope(&self) -> RingScope<'_, T, X> {
RingScope {
ring: self
.ring
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner),
}
}
}
pub struct RingScope<'delivery, T = (), X = ()> {
ring: MutexGuard<'delivery, IoRing<T, X>>,
}
impl<T, X> RingScope<'_, T, X> {
pub fn batch(&mut self) -> Batch<'_, T, X> {
Batch::new(&mut self.ring)
}
#[must_use]
pub fn outstanding(&self) -> usize {
self.ring.outstanding()
}
#[must_use]
pub fn version(&self) -> RingVersion {
self.ring.version()
}
pub fn info(&self) -> io::Result<RingInfo> {
self.ring.info()
}
#[must_use]
pub fn supports(&self, op: Op) -> bool {
self.ring.supports(op)
}
#[must_use]
pub fn supports_raw(&self, op_code: IORING_OP_CODE) -> bool {
self.ring.supports_raw(op_code)
}
#[must_use]
pub fn registered_file_count(&self) -> u32 {
self.ring.registered_file_count()
}
#[must_use]
pub fn registered_buffer_count(&self) -> u32 {
self.ring.registered_buffer_count()
}
}
#[cfg(test)]
mod tests;