use std::{
future::Future,
io,
task::{Context, Poll},
time::Duration,
};
use crate::context::{io_context, RawIoContext};
use super::{Cmd, Description, Driver, Handle, Interest, OpenFlags};
pub struct Sleep {
fd: Option<Handle>,
driver: Driver,
expired: Duration,
poller: Handle,
}
impl Sleep {
pub fn new_with(driver: Driver, poller: Handle, expired: Duration) -> io::Result<Self> {
Ok(Self {
fd: None,
driver,
expired,
poller,
})
}
}
impl Future for Sleep {
type Output = io::Result<()>;
fn poll(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.fd.is_none() {
let fd = match self
.driver
.fd_open(Description::Timeout, OpenFlags::Duration(self.expired))
{
Err(err) => return Poll::Ready(Err(err)),
Ok(fd) => fd,
};
self.fd = Some(fd);
match self.driver.fd_cntl(
self.poller,
Cmd::Register {
source: fd,
interests: Interest::Readable,
},
) {
Err(err) => return Poll::Ready(Err(err)),
_ => {}
}
log::trace!("create timeout {:?}", fd);
}
match self
.driver
.fd_cntl(self.fd.unwrap(), Cmd::Timeout(cx.waker().clone()))
{
Ok(resp) => match resp.try_into_timeout() {
Ok(status) => {
if status {
return Poll::Ready(Ok(()));
}
}
Err(err) => {
return Poll::Ready(Err(err));
}
},
Err(err) => return Poll::Ready(Err(err)),
}
return Poll::Pending;
}
}
impl Drop for Sleep {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
self.driver.fd_close(fd).unwrap();
}
}
}
pub async fn sleep(duration: Duration) -> io::Result<()> {
let context = io_context();
Sleep::new_with(context.driver().clone(), context.poller(), duration)?.await
}