use std::future::Future;
use std::io;
use std::marker::PhantomData;
use std::pin::Pin as StdPin;
use std::sync::Arc;
use std::task::{Context, Poll};
use crate::future::waker::WakerRegistry;
use crate::operation::BufferType;
use crate::operation::{Operation, Submitted};
use crate::ring::Ring;
pub struct OperationFuture<'ring, 'buf> {
operation: Option<Operation<'ring, 'buf, Submitted>>,
ring: &'ring mut Ring<'ring>,
waker_registry: Arc<WakerRegistry>,
_phantom: PhantomData<(&'ring (), &'buf ())>,
}
impl<'ring, 'buf> OperationFuture<'ring, 'buf> {
pub(crate) fn new(
operation: Operation<'ring, 'buf, Submitted>,
ring: &'ring mut Ring<'ring>,
waker_registry: Arc<WakerRegistry>,
) -> Self {
Self {
operation: Some(operation),
ring,
waker_registry,
_phantom: PhantomData,
}
}
}
impl<'ring, 'buf> Future for OperationFuture<'ring, 'buf> {
type Output = io::Result<(i32, Option<StdPin<&'buf mut [u8]>>)>;
fn poll(mut self: StdPin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let operation = match self.operation.as_ref() {
Some(op) => op,
None => {
panic!("OperationFuture polled after completion");
}
};
let operation_id = operation.id();
match self.ring.try_complete_by_id(operation_id) {
Ok(Some(result)) => {
let operation = self.operation.take().unwrap();
let completed = operation.complete_with_result(result);
let (io_result, buffer) = completed.into_result();
self.waker_registry.remove_waker(operation_id);
let buffer_option = match buffer {
BufferType::Pinned(buf) => Some(buf),
_ => None,
};
Poll::Ready(io_result.map(|bytes| (bytes, buffer_option)))
}
Ok(None) => {
self.waker_registry
.register_waker(operation_id, cx.waker().clone());
Poll::Pending
}
Err(e) => {
self.waker_registry.remove_waker(operation_id);
Poll::Ready(Err(io::Error::other(format!(
"Error checking operation completion: {e}"
))))
}
}
}
}
impl<'ring, 'buf> Drop for OperationFuture<'ring, 'buf> {
fn drop(&mut self) {
if let Some(operation) = &self.operation {
self.waker_registry.remove_waker(operation.id());
}
}
}