Skip to main content

borrowed_buf/
io.rs

1//! Integration with [`std::io`]. Requires the `std` feature.
2//!
3//! These are stable stand-ins for the nightly-only `Read::read_buf` and `Read::read_buf_exact`,
4//! with the same behavior as their default implementations.
5
6use crate::BorrowedCursor;
7use std::io::{self, ErrorKind, IoSlice, Read, Write};
8
9/// Reads from `reader` into `cursor` with a single [`Read::read`] call.
10///
11/// Mirrors the default implementation of the nightly `Read::read_buf`. The unfilled part of the
12/// underlying [`BorrowedBuf`](crate::BorrowedBuf) is zeroed first, but only once over its lifetime,
13/// so reading in a loop stays cheap.
14///
15/// # Panics
16///
17/// Panics if `reader` reports more bytes than the slice it was given.
18///
19/// ```
20/// use borrowed_buf::{BorrowedBuf, io};
21/// use core::mem::MaybeUninit;
22///
23/// let mut reader: &[u8] = b"hello world";
24/// let mut storage = [MaybeUninit::uninit(); 64];
25/// let mut buf = BorrowedBuf::from(&mut storage[..]);
26///
27/// // Read until EOF, zeroing the buffer only once.
28/// loop {
29///     let before = buf.len();
30///     io::read_buf(&mut reader, buf.unfilled())?;
31///     if buf.len() == before {
32///         break;
33///     }
34/// }
35/// assert_eq!(buf.filled(), b"hello world");
36/// # Ok::<(), std::io::Error>(())
37/// ```
38#[inline]
39pub fn read_buf<R: Read + ?Sized>(
40    reader: &mut R,
41    mut cursor: BorrowedCursor<'_, u8>,
42) -> io::Result<()> {
43    let n = reader.read(cursor.ensure_init())?;
44    cursor.advance_checked(n);
45    Ok(())
46}
47
48/// Reads from `reader` until `cursor` is full.
49///
50/// Mirrors the default implementation of the nightly `Read::read_buf_exact`. Retries on
51/// [`ErrorKind::Interrupted`]. Returns [`ErrorKind::UnexpectedEof`] if the reader ends first;
52/// whatever was read up to that point stays in the buffer.
53///
54/// ```
55/// use borrowed_buf::{BorrowedBuf, io};
56/// use core::mem::MaybeUninit;
57///
58/// let mut reader: &[u8] = b"\x00\x05rest";
59/// let mut storage = [MaybeUninit::uninit(); 2];
60/// let mut header = BorrowedBuf::from(&mut storage[..]);
61/// io::read_buf_exact(&mut reader, header.unfilled())?;
62/// assert_eq!(u16::from_be_bytes([header.filled()[0], header.filled()[1]]), 5);
63/// # Ok::<(), std::io::Error>(())
64/// ```
65pub fn read_buf_exact<R: Read + ?Sized>(
66    reader: &mut R,
67    mut cursor: BorrowedCursor<'_, u8>,
68) -> io::Result<()> {
69    while cursor.capacity() > 0 {
70        let before = cursor.written();
71        match read_buf(reader, cursor.reborrow()) {
72            Ok(()) if cursor.written() == before => {
73                return Err(io::Error::new(
74                    ErrorKind::UnexpectedEof,
75                    "failed to fill whole buffer",
76                ));
77            }
78            Ok(()) => {}
79            Err(e) if e.kind() == ErrorKind::Interrupted => {}
80            Err(e) => return Err(e),
81        }
82    }
83    Ok(())
84}
85
86impl Write for BorrowedCursor<'_, u8> {
87    #[inline]
88    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
89        let n = buf.len().min(self.capacity());
90        self.append(&buf[..n]);
91        Ok(n)
92    }
93
94    #[inline]
95    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
96        let mut written = 0;
97        for buf in bufs {
98            let n = self.write(buf)?;
99            written += n;
100            if n < buf.len() {
101                break;
102            }
103        }
104        Ok(written)
105    }
106
107    #[inline]
108    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
109        if self.write(buf)? < buf.len() {
110            Err(io::Error::new(
111                ErrorKind::WriteZero,
112                "failed to write whole buffer",
113            ))
114        } else {
115            Ok(())
116        }
117    }
118
119    #[inline]
120    fn flush(&mut self) -> io::Result<()> {
121        Ok(())
122    }
123}