tokio/io/util/buf_reader.rs
1use crate::io::util::DEFAULT_BUF_SIZE;
2use crate::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
3
4use pin_project_lite::pin_project;
5use std::io::{self, IoSlice, SeekFrom};
6use std::pin::Pin;
7use std::task::{ready, Context, Poll};
8use std::{cmp, fmt, mem};
9
10pin_project! {
11 /// The `BufReader` struct adds buffering to any reader.
12 ///
13 /// It can be excessively inefficient to work directly with a [`AsyncRead`]
14 /// instance. A `BufReader` performs large, infrequent reads on the underlying
15 /// [`AsyncRead`] and maintains an in-memory buffer of the results.
16 ///
17 /// `BufReader` can improve the speed of programs that make *small* and
18 /// *repeated* read calls to the same file or network socket. It does not
19 /// help when reading very large amounts at once, or reading just one or a few
20 /// times. It also provides no advantage when reading from a source that is
21 /// already in memory, like a `Vec<u8>`.
22 ///
23 /// When the `BufReader` is dropped, the contents of its buffer will be
24 /// discarded. Creating multiple instances of a `BufReader` on the same
25 /// stream can cause data loss.
26 #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
27 pub struct BufReader<R> {
28 #[pin]
29 pub(super) inner: R,
30 pub(super) buf: Box<[u8]>,
31 pub(super) pos: usize,
32 pub(super) cap: usize,
33 pub(super) seek_state: SeekState,
34 }
35}
36
37impl<R: AsyncRead> BufReader<R> {
38 /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
39 /// but may change in the future.
40 pub fn new(inner: R) -> Self {
41 Self::with_capacity(DEFAULT_BUF_SIZE, inner)
42 }
43
44 /// Creates a new `BufReader` with the specified buffer capacity.
45 ///
46 /// # Panics
47 ///
48 /// Panics if `capacity` is zero.
49 #[track_caller]
50 pub fn with_capacity(capacity: usize, inner: R) -> Self {
51 assert!(capacity > 0, "capacity must be greater than zero");
52 let buffer = vec![0; capacity];
53 Self {
54 inner,
55 buf: buffer.into_boxed_slice(),
56 pos: 0,
57 cap: 0,
58 seek_state: SeekState::Init,
59 }
60 }
61
62 /// Gets a reference to the underlying reader.
63 ///
64 /// It is inadvisable to directly read from the underlying reader.
65 pub fn get_ref(&self) -> &R {
66 &self.inner
67 }
68
69 /// Gets a mutable reference to the underlying reader.
70 ///
71 /// It is inadvisable to directly read from the underlying reader.
72 pub fn get_mut(&mut self) -> &mut R {
73 &mut self.inner
74 }
75
76 /// Gets a pinned mutable reference to the underlying reader.
77 ///
78 /// It is inadvisable to directly read from the underlying reader.
79 pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> {
80 self.project().inner
81 }
82
83 /// Consumes this `BufReader`, returning the underlying reader.
84 ///
85 /// Note that any leftover data in the internal buffer is lost.
86 pub fn into_inner(self) -> R {
87 self.inner
88 }
89
90 /// Returns a reference to the internally buffered data.
91 ///
92 /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
93 pub fn buffer(&self) -> &[u8] {
94 &self.buf[self.pos..self.cap]
95 }
96
97 /// Invalidates all data in the internal buffer.
98 #[inline]
99 fn discard_buffer(self: Pin<&mut Self>) {
100 let me = self.project();
101 *me.pos = 0;
102 *me.cap = 0;
103 }
104}
105
106impl<R: AsyncRead> AsyncRead for BufReader<R> {
107 fn poll_read(
108 mut self: Pin<&mut Self>,
109 cx: &mut Context<'_>,
110 buf: &mut ReadBuf<'_>,
111 ) -> Poll<io::Result<()>> {
112 // If we don't have any buffered data and we're doing a massive read
113 // (larger than our internal buffer), bypass our internal buffer
114 // entirely.
115 if self.pos == self.cap && buf.remaining() >= self.buf.len() {
116 let res = ready!(self.as_mut().get_pin_mut().poll_read(cx, buf));
117 self.discard_buffer();
118 return Poll::Ready(res);
119 }
120 let rem = ready!(self.as_mut().poll_fill_buf(cx))?;
121 let amt = std::cmp::min(rem.len(), buf.remaining());
122 buf.put_slice(&rem[..amt]);
123 self.consume(amt);
124 Poll::Ready(Ok(()))
125 }
126}
127
128impl<R: AsyncRead> AsyncBufRead for BufReader<R> {
129 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
130 let me = self.project();
131
132 // If we've reached the end of our internal buffer then we need to fetch
133 // some more data from the underlying reader.
134 // Branch using `>=` instead of the more correct `==`
135 // to tell the compiler that the pos..cap slice is always valid.
136 if *me.pos >= *me.cap {
137 debug_assert!(*me.pos == *me.cap);
138 let mut buf = ReadBuf::new(me.buf);
139 ready!(me.inner.poll_read(cx, &mut buf))?;
140 *me.cap = buf.filled().len();
141 *me.pos = 0;
142 }
143 Poll::Ready(Ok(&me.buf[*me.pos..*me.cap]))
144 }
145
146 fn consume(self: Pin<&mut Self>, amt: usize) {
147 let me = self.project();
148 *me.pos = cmp::min(*me.pos + amt, *me.cap);
149 }
150}
151
152#[derive(Debug, Clone, Copy)]
153pub(super) enum SeekState {
154 /// `start_seek` has not been called.
155 Init,
156 /// `start_seek` has been called, but `poll_complete` has not yet been called.
157 Start(SeekFrom),
158 /// Waiting for completion of the first `poll_complete` in the `n.checked_sub(remainder).is_none()` branch.
159 PendingOverflowed(i64),
160 /// Waiting for completion of `poll_complete`.
161 Pending,
162}
163
164/// Seeks to an offset, in bytes, in the underlying reader.
165///
166/// The position used for seeking with `SeekFrom::Current(_)` is the
167/// position the underlying reader would be at if the `BufReader` had no
168/// internal buffer.
169///
170/// Seeking always discards the internal buffer, even if the seek position
171/// would otherwise fall within it. This guarantees that calling
172/// `.into_inner()` immediately after a seek yields the underlying reader
173/// at the same position.
174///
175/// See [`AsyncSeek`] for more details.
176///
177/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
178/// where `n` minus the internal buffer length overflows an `i64`, two
179/// seeks will be performed instead of one. If the second seek returns
180/// `Err`, the underlying reader will be left at the same position it would
181/// have if you called `seek` with `SeekFrom::Current(0)`.
182impl<R: AsyncRead + AsyncSeek> AsyncSeek for BufReader<R> {
183 fn start_seek(self: Pin<&mut Self>, pos: SeekFrom) -> io::Result<()> {
184 // We needs to call seek operation multiple times.
185 // And we should always call both start_seek and poll_complete,
186 // as start_seek alone cannot guarantee that the operation will be completed.
187 // poll_complete receives a Context and returns a Poll, so it cannot be called
188 // inside start_seek.
189 *self.project().seek_state = SeekState::Start(pos);
190 Ok(())
191 }
192
193 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
194 let res = match mem::replace(self.as_mut().project().seek_state, SeekState::Init) {
195 SeekState::Init => {
196 return self.project().inner.poll_complete(cx);
197 }
198 SeekState::Start(SeekFrom::Current(n)) => {
199 let remainder = (self.cap - self.pos) as i64;
200 // it should be safe to assume that remainder fits within an i64 as the alternative
201 // means we managed to allocate 8 exbibytes and that's absurd.
202 // But it's not out of the realm of possibility for some weird underlying reader to
203 // support seeking by i64::MIN so we need to handle underflow when subtracting
204 // remainder.
205 if let Some(offset) = n.checked_sub(remainder) {
206 self.as_mut()
207 .get_pin_mut()
208 .start_seek(SeekFrom::Current(offset))?;
209 } else {
210 // seek backwards by our remainder, and then by the offset
211 self.as_mut()
212 .get_pin_mut()
213 .start_seek(SeekFrom::Current(-remainder))?;
214 if self.as_mut().get_pin_mut().poll_complete(cx)?.is_pending() {
215 *self.as_mut().project().seek_state = SeekState::PendingOverflowed(n);
216 return Poll::Pending;
217 }
218
219 // https://github.com/rust-lang/rust/pull/61157#issuecomment-495932676
220 self.as_mut().discard_buffer();
221
222 self.as_mut()
223 .get_pin_mut()
224 .start_seek(SeekFrom::Current(n))?;
225 }
226 self.as_mut().get_pin_mut().poll_complete(cx)?
227 }
228 SeekState::PendingOverflowed(n) => {
229 if self.as_mut().get_pin_mut().poll_complete(cx)?.is_pending() {
230 *self.as_mut().project().seek_state = SeekState::PendingOverflowed(n);
231 return Poll::Pending;
232 }
233
234 // https://github.com/rust-lang/rust/pull/61157#issuecomment-495932676
235 self.as_mut().discard_buffer();
236
237 self.as_mut()
238 .get_pin_mut()
239 .start_seek(SeekFrom::Current(n))?;
240 self.as_mut().get_pin_mut().poll_complete(cx)?
241 }
242 SeekState::Start(pos) => {
243 // Seeking with Start/End doesn't care about our buffer length.
244 self.as_mut().get_pin_mut().start_seek(pos)?;
245 self.as_mut().get_pin_mut().poll_complete(cx)?
246 }
247 SeekState::Pending => self.as_mut().get_pin_mut().poll_complete(cx)?,
248 };
249
250 match res {
251 Poll::Ready(res) => {
252 self.discard_buffer();
253 Poll::Ready(Ok(res))
254 }
255 Poll::Pending => {
256 *self.as_mut().project().seek_state = SeekState::Pending;
257 Poll::Pending
258 }
259 }
260 }
261}
262
263impl<R: AsyncRead + AsyncWrite> AsyncWrite for BufReader<R> {
264 fn poll_write(
265 self: Pin<&mut Self>,
266 cx: &mut Context<'_>,
267 buf: &[u8],
268 ) -> Poll<io::Result<usize>> {
269 self.get_pin_mut().poll_write(cx, buf)
270 }
271
272 fn poll_write_vectored(
273 self: Pin<&mut Self>,
274 cx: &mut Context<'_>,
275 bufs: &[IoSlice<'_>],
276 ) -> Poll<io::Result<usize>> {
277 self.get_pin_mut().poll_write_vectored(cx, bufs)
278 }
279
280 fn is_write_vectored(&self) -> bool {
281 self.get_ref().is_write_vectored()
282 }
283
284 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
285 self.get_pin_mut().poll_flush(cx)
286 }
287
288 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
289 self.get_pin_mut().poll_shutdown(cx)
290 }
291}
292
293impl<R: fmt::Debug> fmt::Debug for BufReader<R> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 f.debug_struct("BufReader")
296 .field("reader", &self.inner)
297 .field(
298 "buffer",
299 &format_args!("{}/{}", self.cap - self.pos, self.buf.len()),
300 )
301 .finish()
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308
309 #[test]
310 fn assert_unpin() {
311 crate::is_unpin::<BufReader<()>>();
312 }
313}