compio-compat 0.1.0-rc.1

Compatibility layer for compio to work with various async runtimes.
Documentation
#[cfg(target_os = "linux")]
use std::os::fd::OwnedFd;
use std::{
    io,
    ops::Deref,
    os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd},
};

use compio_runtime::Runtime;
use mod_use::mod_use;

#[cfg(feature = "tokio")]
mod_use![tokio];

#[cfg(feature = "futures")]
mod_use![futures];

struct UnixAdapter {
    runtime: Runtime,
    #[cfg(target_os = "linux")]
    efd: Option<OwnedFd>,
}

#[cfg(target_os = "linux")]
impl UnixAdapter {
    fn new(runtime: Runtime) -> io::Result<Self> {
        if runtime.driver_type().is_iouring() {
            use rustix::{
                event::{EventfdFlags, eventfd},
                io_uring::{IoringRegisterOp, io_uring_register},
            };

            let efd = eventfd(0, EventfdFlags::CLOEXEC | EventfdFlags::NONBLOCK)?;
            let efd_raw = efd.as_raw_fd();
            unsafe {
                io_uring_register(
                    BorrowedFd::borrow_raw(runtime.as_raw_fd()),
                    IoringRegisterOp::RegisterEventfd,
                    (&raw const efd_raw).cast(),
                    1,
                )?;
            }
            Ok(Self {
                runtime,
                efd: Some(efd),
            })
        } else {
            Ok(Self { runtime, efd: None })
        }
    }

    fn clear(&self) -> io::Result<()> {
        if let Some(efd) = &self.efd {
            let mut buf = [0u8; 8];
            match rustix::io::read(efd, &mut buf) {
                Ok(_) => {}
                Err(e)
                    if matches!(
                        e.kind(),
                        io::ErrorKind::WouldBlock | io::ErrorKind::Interrupted
                    ) => {}
                Err(e) => return Err(io::Error::from(e)),
            }
        }
        Ok(())
    }
}

#[cfg(not(target_os = "linux"))]
impl UnixAdapter {
    fn new(runtime: Runtime) -> io::Result<Self> {
        Ok(Self { runtime })
    }

    fn clear(&self) -> io::Result<()> {
        Ok(())
    }
}

impl AsRawFd for UnixAdapter {
    fn as_raw_fd(&self) -> RawFd {
        #[cfg(target_os = "linux")]
        {
            self.efd
                .as_ref()
                .map(|f| f.as_raw_fd())
                .unwrap_or_else(|| self.runtime.as_raw_fd())
        }
        #[cfg(not(target_os = "linux"))]
        {
            self.runtime.as_raw_fd()
        }
    }
}

impl AsFd for UnixAdapter {
    fn as_fd(&self) -> BorrowedFd<'_> {
        unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
    }
}

impl Deref for UnixAdapter {
    type Target = Runtime;

    fn deref(&self) -> &Self::Target {
        &self.runtime
    }
}