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