use std::io;
use std::os::fd::RawFd;
use crate::platform::fs::RawDescriptor;
impl From<RawFd> for RawDescriptor {
fn from(fd: RawFd) -> Self {
RawDescriptor::from_value(fd as usize)
}
}
pub fn write_all_to_descriptor(descriptor: RawDescriptor, mut bytes: &[u8]) -> io::Result<()> {
let fd = descriptor.value() as RawFd;
while !bytes.is_empty() {
let written = unsafe { libc::write(fd, bytes.as_ptr().cast(), bytes.len()) };
if written < 0 {
let error = io::Error::last_os_error();
if error.kind() == io::ErrorKind::Interrupted {
continue;
}
return Err(error);
}
if written == 0 {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"raw descriptor write returned zero",
));
}
bytes = &bytes[written as usize..];
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Read as _;
use std::os::fd::AsRawFd as _;
#[test]
fn every_byte_is_written() {
let file = tempfile::NamedTempFile::new().expect("temp file");
let payload = vec![b'x'; 300_000];
write_all_to_descriptor(RawDescriptor::from(file.as_file().as_raw_fd()), &payload)
.expect("write");
let mut readback = Vec::new();
std::fs::File::open(file.path())
.expect("reopen")
.read_to_end(&mut readback)
.expect("read");
assert_eq!(readback.len(), payload.len());
assert!(readback.iter().all(|b| *b == b'x'));
}
#[test]
fn an_empty_write_is_not_an_error() {
write_all_to_descriptor(RawDescriptor::from(-1), &[]).expect("empty write");
}
#[test]
fn a_closed_descriptor_reports_the_host_error() {
let error = write_all_to_descriptor(RawDescriptor::from(-1), b"x").expect_err("bad fd");
assert_eq!(error.raw_os_error(), Some(libc::EBADF));
}
}