/// Tests the readiness of a socket for the specified `flag` (e.g., `IN` or
/// `OUT`).
///
/// ## References
///
/// - <https://github.com/MengJiangProject/redproxy-rs/blob/4363b868bce8449441fb6364a679948d73270465/src/common/splice.rs>
/// - <https://github.com/tokio-rs/tokio/issues/7051>
/// - <https://github.com/tokio-rs/mio/issues/928>
/// - <https://strikefreedom.top/archives/linux-io-stack-and-zero-copy#splice>
/// - <https://strikefreedom.top/archives/linux-epoll-with-level-triggering-and-edge-triggering>
macro_rules! test_readiness {
    ($fd:expr, $flag:ident) => {{
        use rustix::event::{PollFd, PollFlags, Timespec, poll};

        let pollfds = &mut [PollFd::new($fd, PollFlags::$flag)];

        poll(pollfds, Some(&Timespec::default()))
            .map_err(Into::into)
            .and_then(|_| match pollfds[0].revents() {
                PollFlags::ERR | PollFlags::HUP | PollFlags::$flag => Ok(true),
                PollFlags::NVAL => Err(io::Error::other("invalid fd")),
                _ => Ok(false),
            })
    }};
}

pub(crate) use test_readiness;
