use std::task::{Context, Poll, Waker};
use super::ready::{Direction, Ready};
pub(crate) struct ScheduledIo {
readiness: Ready,
reader: Option<Waker>,
writer: Option<Waker>,
}
impl Default for ScheduledIo {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl ScheduledIo {
pub(crate) const fn new() -> Self {
Self {
readiness: Ready::EMPTY,
reader: None,
writer: None,
}
}
#[allow(unused)]
#[inline]
pub(crate) fn set_writable(&mut self) {
self.readiness |= Ready::WRITABLE;
}
#[inline]
pub(crate) fn set_readiness(&mut self, f: impl Fn(Ready) -> Ready) {
self.readiness = f(self.readiness);
}
#[inline]
pub(crate) fn wake(&mut self, ready: Ready) {
if ready.is_readable() {
if let Some(waker) = self.reader.take() {
waker.wake();
}
}
if ready.is_writable() {
if let Some(waker) = self.writer.take() {
waker.wake();
}
}
}
#[inline]
pub(crate) fn clear_readiness(&mut self, ready: Ready) {
self.readiness = self.readiness - ready;
}
#[allow(clippy::needless_pass_by_ref_mut)]
#[inline]
pub(crate) fn poll_readiness(
&mut self,
cx: &mut Context<'_>,
direction: Direction,
) -> Poll<Ready> {
let ready = direction.mask() & self.readiness;
if !ready.is_empty() {
return Poll::Ready(ready);
}
self.set_waker(cx, direction);
Poll::Pending
}
#[inline]
pub(crate) fn set_waker(&mut self, cx: &mut Context<'_>, direction: Direction) {
let slot = match direction {
Direction::Read => &mut self.reader,
Direction::Write => &mut self.writer,
};
match slot {
Some(existing) => {
if !existing.will_wake(cx.waker()) {
existing.clone_from(cx.waker());
}
}
None => {
*slot = Some(cx.waker().clone());
}
}
}
}