Skip to main content

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}