use core::future::poll_fn;
use core::task::{Context, Poll};
use std::io;
use std::sync::Arc;
use super::{Interest, Ready, Source};
#[derive(Clone, Copy)]
pub(crate) struct Marks {
pub(crate) ready: Ready,
pub(crate) read: Option<u32>,
pub(crate) write: Option<u32>,
}
pub(crate) fn poll_marks(
source: &Arc<Source>,
cx: &mut Context<'_>,
read: bool,
write: bool,
) -> Poll<io::Result<Marks>> {
let mut marks = Marks {
ready: Ready::EMPTY,
read: None,
write: None,
};
if read && let Poll::Ready(tick) = source.poll_fd_read_ready(cx) {
marks.read = Some(tick?);
marks.ready = marks.ready | Ready::READABLE;
}
if write && let Poll::Ready(tick) = source.poll_fd_write_ready(cx) {
marks.write = Some(tick?);
marks.ready = marks.ready | Ready::WRITABLE;
}
if marks.ready.is_empty() {
Poll::Pending
} else {
Poll::Ready(Ok(marks))
}
}
pub(crate) fn clear(source: &Arc<Source>, marks: Marks) {
if let Some(tick) = marks.read {
source.fd_clear_read(tick);
}
if let Some(tick) = marks.write {
source.fd_clear_write(tick);
}
}
pub(crate) fn sides(interest: Interest) -> (bool, bool) {
(interest.is_readable(), interest.is_writable())
}
pub(crate) fn try_io<R>(
source: &Arc<Source>,
(read, write): (bool, bool),
f: impl FnOnce() -> io::Result<R>,
) -> io::Result<R> {
let mut cx = Context::from_waker(std::task::Waker::noop());
let marks = match poll_marks(source, &mut cx, read, write) {
Poll::Ready(marks) => marks?,
Poll::Pending => return Err(io::ErrorKind::WouldBlock.into()),
};
let result = f();
if matches!(&result, Err(e) if e.kind() == io::ErrorKind::WouldBlock) {
clear(source, marks);
}
result
}
pub(crate) async fn async_io<R>(
source: &Arc<Source>,
(read, write): (bool, bool),
mut f: impl FnMut() -> io::Result<R>,
) -> io::Result<R> {
loop {
let marks = poll_fn(|cx| poll_marks(source, cx, read, write)).await?;
match f() {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => clear(source, marks),
result => return result,
}
}
}