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}