use std::io;
#[cfg(unix)]
use std::os::unix::io::RawFd;
#[cfg(all(unix, test))]
fn get_output_fd() -> RawFd {
use std::sync::OnceLock;
static DEVNULL: OnceLock<RawFd> = OnceLock::new();
*DEVNULL.get_or_init(|| {
use std::ffi::CString;
let path = CString::new("/dev/null").unwrap();
unsafe { libc::open(path.as_ptr(), libc::O_WRONLY) }
})
}
#[cfg(all(unix, not(test)))]
#[inline]
fn get_output_fd() -> RawFd {
1 }
#[cfg(unix)]
pub fn write_stdout(buf: &[u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
let mut total_written = 0;
let mut remaining = buf;
let fd = get_output_fd();
while !remaining.is_empty() {
let written = unsafe {
libc::write(
fd,
remaining.as_ptr() as *const libc::c_void,
remaining.len(),
)
};
if written < 0 {
let err = io::Error::last_os_error();
if err.kind() == io::ErrorKind::Interrupted {
continue;
}
return Err(err);
}
let written = written as usize;
total_written += written;
remaining = &remaining[written..];
}
Ok(total_written)
}
#[cfg(windows)]
pub fn write_stdout(buf: &[u8]) -> io::Result<usize> {
use std::io::Write;
std::io::stdout().write(buf)
}
pub fn write_all_stdout(buf: &[u8]) -> io::Result<()> {
write_stdout(buf)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_write_stdout_empty() {
let result = write_stdout(&[]);
assert_eq!(result.unwrap(), 0);
}
#[test]
fn test_write_stdout_small() {
let msg = b"test";
let result = write_stdout(msg);
assert!(result.is_ok());
assert_eq!(result.unwrap(), msg.len());
}
#[test]
fn test_write_all_stdout() {
let msg = b"Hello from direct I/O\n";
let result = write_all_stdout(msg);
assert!(result.is_ok());
}
#[test]
#[cfg(unix)]
fn test_write_stdout_large() {
let large_buf = vec![b'A'; 10000];
let result = write_stdout(&large_buf);
assert!(result.is_ok());
assert_eq!(result.unwrap(), large_buf.len());
}
}