use std::{
io,
marker::PhantomData,
mem::replace,
path::PathBuf,
pin::Pin,
task::{Context, Poll},
};
use tempest_io::{Io, OpHandle};
use crate::context::{current_io, get_op_handle};
enum RemoveFileState {
NeedsSubmit {
path: PathBuf,
handle: Option<OpHandle>,
},
InFlight {
handle: OpHandle,
},
Done,
}
#[must_use = "futures do nothing unless awaited"]
pub struct RemoveFile<I: Io> {
state: RemoveFileState,
_marker: PhantomData<fn() -> I>,
}
pub fn remove_file<I: Io>(path: PathBuf) -> RemoveFile<I> {
RemoveFile {
state: RemoveFileState::NeedsSubmit { path, handle: None },
_marker: PhantomData,
}
}
impl<I: Io> Unpin for RemoveFile<I> {}
impl<I: Io> Future for RemoveFile<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, RemoveFileState::Done) {
RemoveFileState::NeedsSubmit { path, handle } => {
let handle = handle.unwrap_or_else(|| unsafe { get_op_handle(cx) });
let io = unsafe { current_io::<I>() };
match io.remove(&path, handle) {
Ok(()) => {
this.state = RemoveFileState::InFlight { handle };
Poll::Pending
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
this.state = RemoveFileState::NeedsSubmit {
path,
handle: Some(handle),
};
cx.waker().wake_by_ref();
Poll::Pending
}
Err(e) => Poll::Ready(Err(e)),
}
}
RemoveFileState::InFlight { handle } => {
let io = unsafe { current_io::<I>() };
match io.get_cqe(handle).transpose()? {
Some(_) => Poll::Ready(Ok(())),
None => {
this.state = RemoveFileState::InFlight { handle };
Poll::Pending
}
}
}
RemoveFileState::Done => panic!("polled after completion"),
}
}
}