formatting_nostd/borrowed_fd_writer.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
use rustix::fd::BorrowedFd;
/// A `core::fmt::Writer` that writes to a file descriptor via direct syscalls.
///
/// Its `core::fmt::Write` implementation retries if interrupted by a signal,
/// and returns errors if the file is closed or the write returns other errors
/// (including `EWOULDBLOCK`). In such cases, partial writes can occur.
///
/// To format a message with Rust's formatting:
/// ```
/// # // Can't create pipes under miri.
/// # #[cfg(not(miri))]
/// # {
/// # use formatting_nostd::BorrowedFdWriter;
/// use rustix::fd::AsFd;
/// use core::fmt::Write;
/// let (_reader_fd, writer_fd) = rustix::pipe::pipe().unwrap();
/// let mut writer = BorrowedFdWriter::new(writer_fd.as_fd());
/// let x = 42;
/// write!(&mut writer, "{x}").unwrap();
/// # }
/// ```
pub struct BorrowedFdWriter<'fd> {
fd: BorrowedFd<'fd>,
}
impl<'fd> BorrowedFdWriter<'fd> {
pub fn new(fd: BorrowedFd<'fd>) -> Self {
Self { fd }
}
}
impl core::fmt::Write for BorrowedFdWriter<'_> {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
let mut bytes_slice = s.as_bytes();
while !bytes_slice.is_empty() {
let Ok(written) = rustix::io::retry_on_intr(|| rustix::io::write(self.fd, bytes_slice))
else {
return Err(core::fmt::Error);
};
if written == 0 {
// Not making forward progress; e.g. file may be closed.
return Err(core::fmt::Error);
}
bytes_slice = &bytes_slice[written..];
}
Ok(())
}
}
// We can't test without going through FFI, which miri doesn't support.
#[cfg(all(test, not(miri)))]
mod test {
use core::fmt::Write;
use rustix::fd::AsFd;
use super::*;
#[test]
fn test_write() {
let (reader, writer) = rustix::pipe::pipe().unwrap();
BorrowedFdWriter::new(writer.as_fd())
.write_str("123")
.unwrap();
let mut buf = [0xff; 4];
assert_eq!(rustix::io::read(reader.as_fd(), &mut buf), Ok(3));
assert_eq!(buf, [b'1', b'2', b'3', 0xff]);
}
}