use crate::io::Interest;
use crate::runtime::io::{ReadyEvent, Registration};
use crate::runtime::scheduler;
use mio::unix::SourceFd;
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
use std::{task::Context, task::Poll};
pub struct AsyncFd<T: AsRawFd> {
registration: Registration,
inner: Option<T>,
}
#[must_use = "You must explicitly choose whether to clear the readiness state by calling a method on ReadyGuard"]
pub struct AsyncFdReadyGuard<'a, T: AsRawFd> {
async_fd: &'a AsyncFd<T>,
event: Option<ReadyEvent>,
}
#[must_use = "You must explicitly choose whether to clear the readiness state by calling a method on ReadyGuard"]
pub struct AsyncFdReadyMutGuard<'a, T: AsRawFd> {
async_fd: &'a mut AsyncFd<T>,
event: Option<ReadyEvent>,
}
const ALL_INTEREST: Interest = Interest::READABLE.add(Interest::WRITABLE);
impl<T: AsRawFd> AsyncFd<T> {
#[inline]
#[track_caller]
pub fn new(inner: T) -> io::Result<Self>
where
T: AsRawFd,
{
Self::with_interest(inner, ALL_INTEREST)
}
#[inline]
#[track_caller]
pub fn with_interest(inner: T, interest: Interest) -> io::Result<Self>
where
T: AsRawFd,
{
Self::new_with_handle_and_interest(inner, scheduler::Handle::current(), interest)
}
#[track_caller]
pub(crate) fn new_with_handle_and_interest(
inner: T,
handle: scheduler::Handle,
interest: Interest,
) -> io::Result<Self> {
let fd = inner.as_raw_fd();
let registration =
Registration::new_with_interest_and_handle(&mut SourceFd(&fd), interest, handle)?;
Ok(AsyncFd {
registration,
inner: Some(inner),
})
}
#[inline]
pub fn get_ref(&self) -> &T {
self.inner.as_ref().unwrap()
}
#[inline]
pub fn get_mut(&mut self) -> &mut T {
self.inner.as_mut().unwrap()
}
fn take_inner(&mut self) -> Option<T> {
let fd = self.inner.as_ref().map(AsRawFd::as_raw_fd);
if let Some(fd) = fd {
let _ = self.registration.deregister(&mut SourceFd(&fd));
}
self.inner.take()
}
pub fn into_inner(mut self) -> T {
self.take_inner().unwrap()
}
pub fn poll_read_ready<'a>(
&'a self,
cx: &mut Context<'_>,
) -> Poll<io::Result<AsyncFdReadyGuard<'a, T>>> {
let event = ready!(self.registration.poll_read_ready(cx))?;
Ok(AsyncFdReadyGuard {
async_fd: self,
event: Some(event),
})
.into()
}
pub fn poll_read_ready_mut<'a>(
&'a mut self,
cx: &mut Context<'_>,
) -> Poll<io::Result<AsyncFdReadyMutGuard<'a, T>>> {
let event = ready!(self.registration.poll_read_ready(cx))?;
Ok(AsyncFdReadyMutGuard {
async_fd: self,
event: Some(event),
})
.into()
}
pub fn poll_write_ready<'a>(
&'a self,
cx: &mut Context<'_>,
) -> Poll<io::Result<AsyncFdReadyGuard<'a, T>>> {
let event = ready!(self.registration.poll_write_ready(cx))?;
Ok(AsyncFdReadyGuard {
async_fd: self,
event: Some(event),
})
.into()
}
pub fn poll_write_ready_mut<'a>(
&'a mut self,
cx: &mut Context<'_>,
) -> Poll<io::Result<AsyncFdReadyMutGuard<'a, T>>> {
let event = ready!(self.registration.poll_write_ready(cx))?;
Ok(AsyncFdReadyMutGuard {
async_fd: self,
event: Some(event),
})
.into()
}
async fn readiness(&self, interest: Interest) -> io::Result<AsyncFdReadyGuard<'_, T>> {
let event = self.registration.readiness(interest).await?;
Ok(AsyncFdReadyGuard {
async_fd: self,
event: Some(event),
})
}
async fn readiness_mut(
&mut self,
interest: Interest,
) -> io::Result<AsyncFdReadyMutGuard<'_, T>> {
let event = self.registration.readiness(interest).await?;
Ok(AsyncFdReadyMutGuard {
async_fd: self,
event: Some(event),
})
}
#[allow(clippy::needless_lifetimes)] pub async fn readable<'a>(&'a self) -> io::Result<AsyncFdReadyGuard<'a, T>> {
self.readiness(Interest::READABLE).await
}
#[allow(clippy::needless_lifetimes)] pub async fn readable_mut<'a>(&'a mut self) -> io::Result<AsyncFdReadyMutGuard<'a, T>> {
self.readiness_mut(Interest::READABLE).await
}
#[allow(clippy::needless_lifetimes)] pub async fn writable<'a>(&'a self) -> io::Result<AsyncFdReadyGuard<'a, T>> {
self.readiness(Interest::WRITABLE).await
}
#[allow(clippy::needless_lifetimes)] pub async fn writable_mut<'a>(&'a mut self) -> io::Result<AsyncFdReadyMutGuard<'a, T>> {
self.readiness_mut(Interest::WRITABLE).await
}
}
impl<T: AsRawFd> AsRawFd for AsyncFd<T> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_ref().unwrap().as_raw_fd()
}
}
impl<T: std::fmt::Debug + AsRawFd> std::fmt::Debug for AsyncFd<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AsyncFd")
.field("inner", &self.inner)
.finish()
}
}
impl<T: AsRawFd> Drop for AsyncFd<T> {
fn drop(&mut self) {
let _ = self.take_inner();
}
}
impl<'a, Inner: AsRawFd> AsyncFdReadyGuard<'a, Inner> {
pub fn clear_ready(&mut self) {
if let Some(event) = self.event.take() {
self.async_fd.registration.clear_readiness(event);
}
}
pub fn retain_ready(&mut self) {
}
#[cfg_attr(docsrs, doc(alias = "with_io"))]
pub fn try_io<R>(
&mut self,
f: impl FnOnce(&'a AsyncFd<Inner>) -> io::Result<R>,
) -> Result<io::Result<R>, TryIoError> {
let result = f(self.async_fd);
if let Err(e) = result.as_ref() {
if e.kind() == io::ErrorKind::WouldBlock {
self.clear_ready();
}
}
match result {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => Err(TryIoError(())),
result => Ok(result),
}
}
pub fn get_ref(&self) -> &'a AsyncFd<Inner> {
self.async_fd
}
pub fn get_inner(&self) -> &'a Inner {
self.get_ref().get_ref()
}
}
impl<'a, Inner: AsRawFd> AsyncFdReadyMutGuard<'a, Inner> {
pub fn clear_ready(&mut self) {
if let Some(event) = self.event.take() {
self.async_fd.registration.clear_readiness(event);
}
}
pub fn retain_ready(&mut self) {
}
pub fn try_io<R>(
&mut self,
f: impl FnOnce(&mut AsyncFd<Inner>) -> io::Result<R>,
) -> Result<io::Result<R>, TryIoError> {
let result = f(self.async_fd);
if let Err(e) = result.as_ref() {
if e.kind() == io::ErrorKind::WouldBlock {
self.clear_ready();
}
}
match result {
Err(err) if err.kind() == io::ErrorKind::WouldBlock => Err(TryIoError(())),
result => Ok(result),
}
}
pub fn get_ref(&self) -> &AsyncFd<Inner> {
self.async_fd
}
pub fn get_mut(&mut self) -> &mut AsyncFd<Inner> {
self.async_fd
}
pub fn get_inner(&self) -> &Inner {
self.get_ref().get_ref()
}
pub fn get_inner_mut(&mut self) -> &mut Inner {
self.get_mut().get_mut()
}
}
impl<'a, T: std::fmt::Debug + AsRawFd> std::fmt::Debug for AsyncFdReadyGuard<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReadyGuard")
.field("async_fd", &self.async_fd)
.finish()
}
}
impl<'a, T: std::fmt::Debug + AsRawFd> std::fmt::Debug for AsyncFdReadyMutGuard<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MutReadyGuard")
.field("async_fd", &self.async_fd)
.finish()
}
}
#[derive(Debug)]
pub struct TryIoError(());