use std::fmt::Debug;
use std::hash::Hash;
use std::io::{self, ErrorKind};
use std::os::unix::io::AsRawFd;
use crate::poller::IoType;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Io {
Read,
Write,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum ResourceType {
Listener,
Transport,
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[display(inner)]
pub struct ResourceIdGenerator(u64);
impl Default for ResourceIdGenerator {
fn default() -> Self { ResourceIdGenerator(1) }
}
#[allow(dead_code)] impl ResourceIdGenerator {
pub fn next(&mut self) -> ResourceId {
let id = self.0;
self.0 += 1;
ResourceId(id)
}
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[display(inner)]
pub struct ResourceId(u64);
impl ResourceId {
pub const WAKER: ResourceId = ResourceId(0);
}
pub trait Resource: AsRawFd + WriteAtomic + Send {
type Event;
fn interests(&self) -> IoType;
fn handle_io(&mut self, io: Io) -> Option<Self::Event>;
}
#[derive(Debug, Display, Error, From)]
pub enum WriteError {
#[display("resource not ready to accept the data")]
NotReady,
#[display(inner)]
#[from]
Io(io::Error),
}
pub trait WriteAtomic: io::Write {
fn write_atomic(&mut self, buf: &[u8]) -> Result<(), WriteError> {
if !self.is_ready_to_write() {
Err(WriteError::NotReady)
} else {
self.write_or_buf(buf).map_err(|err| {
debug_assert!(
!matches!(
err.kind(),
ErrorKind::WouldBlock | ErrorKind::Interrupted | ErrorKind::WriteZero
),
"WriteAtomic::write_or_buf must handle EGAGAIN, EINTR, EWOULDBLOCK errors by \
buffering the data"
);
WriteError::from(err)
})
}
}
fn is_ready_to_write(&self) -> bool;
fn empty_write_buf(&mut self) -> io::Result<bool>;
#[doc(hidden)]
fn write_or_buf(&mut self, buf: &[u8]) -> io::Result<()>;
}