use std::{future::Future, pin::Pin};
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
use std::marker::PhantomData;
#[cfg(all(
any(feature = "async-io", feature = "tokio"),
any(target_os = "linux", target_vendor = "apple")
))]
use std::io;
#[cfg(all(
any(feature = "async-io", feature = "tokio"),
any(target_os = "linux", target_vendor = "apple")
))]
use std::os::fd::AsFd;
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
use std::os::fd::{BorrowedFd, OwnedFd};
pub struct AsyncFd {
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
inner: OwnedFd,
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
_private: (),
}
impl AsyncFd {
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub(crate) fn from_owned_fd(inner: OwnedFd) -> Self {
Self { inner }
}
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn into_owned_fd(self) -> OwnedFd {
self.inner
}
}
pub struct AsyncFdRef<'a> {
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
inner: BorrowedFd<'a>,
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
_marker: PhantomData<&'a ()>,
}
impl<'a> AsyncFdRef<'a> {
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn from_borrowed_fd(inner: BorrowedFd<'a>) -> Self {
Self { inner }
}
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn as_fd(&self) -> BorrowedFd<'_> {
self.inner
}
}
pub trait AsyncFdAdapter {
fn register(fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>>;
}
pub type AsyncFdReadableFuture<'a> =
Pin<Box<dyn Future<Output = std::io::Result<Box<dyn AsyncFdReadyGuard + 'a>>> + 'a>>;
pub trait AsyncFdRegistration: Send + Sync {
fn readable(&self) -> AsyncFdReadableFuture<'_>;
}
pub trait AsyncFdReadyGuard {
fn fd(&self) -> AsyncFdRef<'_>;
fn clear_ready(&mut self);
}
#[cfg(feature = "async-io")]
pub struct AsyncIo;
#[cfg(feature = "tokio")]
pub struct Tokio;
#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
impl AsyncFdAdapter for Tokio {
fn register(fd: AsyncFd) -> io::Result<Box<dyn AsyncFdRegistration>> {
Ok(Box::new(tokio::io::unix::AsyncFd::new(fd.into_owned_fd())?))
}
}
#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
impl AsyncFdRegistration for tokio::io::unix::AsyncFd<OwnedFd> {
fn readable(&self) -> AsyncFdReadableFuture<'_> {
Box::pin(async move {
let guard = self.readable().await?;
Ok(Box::new(guard) as Box<dyn AsyncFdReadyGuard>)
})
}
}
#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
impl AsyncFdReadyGuard for tokio::io::unix::AsyncFdReadyGuard<'_, OwnedFd> {
fn fd(&self) -> AsyncFdRef<'_> {
AsyncFdRef::from_borrowed_fd(self.get_inner().as_fd())
}
fn clear_ready(&mut self) {
tokio::io::unix::AsyncFdReadyGuard::clear_ready(self);
}
}
#[cfg(all(feature = "tokio", any(windows, target_os = "android")))]
impl AsyncFdAdapter for Tokio {
fn register(_fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>> {
unreachable!("Tokio AsyncFd registration is not used on this platform")
}
}
#[cfg(all(
feature = "async-io",
any(target_os = "linux", target_vendor = "apple")
))]
impl AsyncFdAdapter for AsyncIo {
fn register(fd: AsyncFd) -> io::Result<Box<dyn AsyncFdRegistration>> {
Ok(Box::new(AsyncIoRegistration(async_io::Async::new(
fd.into_owned_fd(),
)?)))
}
}
#[cfg(all(
feature = "async-io",
any(target_os = "linux", target_vendor = "apple")
))]
struct AsyncIoRegistration(async_io::Async<OwnedFd>);
#[cfg(all(
feature = "async-io",
any(target_os = "linux", target_vendor = "apple")
))]
struct AsyncIoReadyGuard<'a>(&'a async_io::Async<OwnedFd>);
#[cfg(all(
feature = "async-io",
any(target_os = "linux", target_vendor = "apple")
))]
impl AsyncFdRegistration for AsyncIoRegistration {
fn readable(&self) -> AsyncFdReadableFuture<'_> {
Box::pin(async move {
self.0.readable().await?;
Ok(Box::new(AsyncIoReadyGuard(&self.0)) as Box<dyn AsyncFdReadyGuard>)
})
}
}
#[cfg(all(
feature = "async-io",
any(target_os = "linux", target_vendor = "apple")
))]
impl AsyncFdReadyGuard for AsyncIoReadyGuard<'_> {
fn fd(&self) -> AsyncFdRef<'_> {
AsyncFdRef::from_borrowed_fd(self.0.get_ref().as_fd())
}
fn clear_ready(&mut self) {}
}
#[cfg(all(feature = "async-io", any(windows, target_os = "android")))]
impl AsyncFdAdapter for AsyncIo {
fn register(_fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>> {
unreachable!("async-io AsyncFd registration is not used on this platform")
}
}