use std::{
io,
os::fd::{AsFd, BorrowedFd, OwnedFd},
};
use rustix::io::{Errno, read, write};
pub(super) struct Pipe {
read: OwnedFd,
write: OwnedFd,
}
impl Pipe {
pub(super) fn new() -> io::Result<Self> {
let (read, write) = pipe()?;
Ok(Self { read, write })
}
pub(super) fn notify(&self) -> io::Result<()> {
match write(&self.write, &[1]) {
Ok(_) | Err(Errno::AGAIN) => Ok(()),
Err(e) => Err(e.into()),
}
}
pub(super) fn drain(&self) {
let mut buf = [0u8; 64];
while read(&self.read, &mut buf).is_ok_and(|n| n == buf.len()) {}
}
pub(super) fn read_end(&self) -> BorrowedFd<'_> {
self.read.as_fd()
}
}
#[cfg(not(target_vendor = "apple"))]
fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
use rustix::pipe::{PipeFlags, pipe_with};
Ok(pipe_with(PipeFlags::CLOEXEC | PipeFlags::NONBLOCK)?)
}
#[cfg(target_vendor = "apple")]
fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
use rustix::{
io::{FdFlags, fcntl_setfd, ioctl_fionbio},
pipe::pipe,
};
let (read, write) = pipe()?;
for end in [&read, &write] {
fcntl_setfd(end, FdFlags::CLOEXEC)?;
ioctl_fionbio(end, true)?;
}
Ok((read, write))
}