polldance/src/io.rs
2023-08-25 12:11:07 -05:00

86 lines
2.1 KiB
Rust

use crate::Readiness;
use rustix::{event::PollFd, fd::AsFd};
use std::num::NonZeroUsize;
pub use std::io::{Error, Result};
pub enum InProgress<T> {
Ready(T),
InProgress,
}
pub enum Nonblocking<T> {
Ready(T),
WouldBlock,
}
pub enum ReadBytes {
Read(NonZeroUsize),
EOF,
}
impl<T> Nonblocking<T> {
pub fn map<U>(self, callback: impl FnOnce(T) -> U) -> Nonblocking<U> {
match self {
Self::Ready(t) => Nonblocking::Ready((callback)(t)),
Self::WouldBlock => Nonblocking::WouldBlock,
}
}
}
impl<T> InProgress<T> {
pub fn map<U>(self, callback: impl FnOnce(T) -> U) -> InProgress<U> {
match self {
Self::Ready(t) => InProgress::Ready((callback)(t)),
Self::InProgress => InProgress::InProgress,
}
}
}
impl From<usize> for ReadBytes {
fn from(n: usize) -> Self {
n.try_into().map(Self::Read).unwrap_or(Self::EOF)
}
}
impl From<ReadBytes> for usize {
fn from(n: ReadBytes) -> Self {
match n {
ReadBytes::EOF => 0,
ReadBytes::Read(n) => n.into(),
}
}
}
pub fn try_ready<A: AsFd>(fd: &A, interest: Readiness) -> Result<Nonblocking<Readiness>> {
let mut fds = [PollFd::new(fd, interest.into())];
rustix::event::poll(&mut fds, 0)?;
let revents: Readiness = fds[0].revents().into();
let out = revents & interest;
if out.is_empty() {
return Ok(Nonblocking::WouldBlock);
}
Ok(Nonblocking::Ready(out))
}
pub(crate) fn in_progress<T>(res: rustix::io::Result<T>) -> Result<InProgress<T>> {
match res {
Ok(t) => Ok(InProgress::Ready(t)),
Err(e) if e == rustix::io::Errno::INPROGRESS => Ok(InProgress::InProgress),
Err(e) => Err(e.into()),
}
}
pub(crate) fn nonblocking<T>(res: rustix::io::Result<T>) -> Result<Nonblocking<T>> {
match res {
Ok(t) => Ok(Nonblocking::Ready(t)),
Err(e) if e == rustix::io::Errno::WOULDBLOCK || e == rustix::io::Errno::AGAIN => {
Ok(Nonblocking::WouldBlock)
}
Err(e) => Err(e.into()),
}
}