use std::{
io,
marker::PhantomData,
mem::replace,
pin::Pin,
task::{Context, Poll},
};
use tempest_io::{Io, OpHandle};
use crate::context::{current_io, get_op_handle};
enum CloseFileState<I: Io> {
NeedsSubmit { fd: I::Fd, handle: Option<OpHandle> },
InFlight { handle: OpHandle },
Done,
}
#[must_use = "futures do nothing unless awaited"]
pub struct CloseFile<I: Io> {
state: CloseFileState<I>,
_marker: PhantomData<fn() -> I>,
}
pub fn close_file<I: Io>(fd: I::Fd) -> CloseFile<I> {
CloseFile {
state: CloseFileState::NeedsSubmit { fd, handle: None },
_marker: PhantomData,
}
}
impl<I: Io> Unpin for CloseFile<I> {}
impl<I: Io> Future for CloseFile<I> {
type Output = io::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
match replace(&mut this.state, CloseFileState::Done) {
CloseFileState::NeedsSubmit { fd, handle } => {
let handle = handle.unwrap_or_else(|| unsafe { get_op_handle(cx) });
let io = unsafe { current_io::<I>() };
match io.close(fd, handle) {
Ok(()) => {
this.state = CloseFileState::InFlight { handle };
Poll::Pending
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
this.state = CloseFileState::NeedsSubmit {
fd,
handle: Some(handle),
};
cx.waker().wake_by_ref();
Poll::Pending
}
Err(e) => Poll::Ready(Err(e)),
}
}
CloseFileState::InFlight { handle } => {
let io = unsafe { current_io::<I>() };
match io.get_cqe(handle).transpose()? {
Some(_) => Poll::Ready(Ok(())),
None => {
this.state = CloseFileState::InFlight { handle };
Poll::Pending
}
}
}
CloseFileState::Done => panic!("polled after completion"),
}
}
}