Skip to main content

alloc/io/buffered/bufreader/
buffer.rs

1//! An encapsulation of `BufReader`'s buffer management logic.
2//!
3//! This module factors out the basic functionality of `BufReader` in order to protect two core
4//! invariants:
5//! * `filled` bytes of `buf` are always initialized
6//! * `pos` is always <= `filled`
7//! Since this module encapsulates the buffer management logic, we can ensure that the range
8//! `pos..filled` is always a valid index into the initialized region of the buffer. This means
9//! that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
10//! without encountering any runtime bounds checks.
11
12use core::cmp;
13use core::mem::MaybeUninit;
14
15use crate::boxed::Box;
16use crate::io::{self, BorrowedBuf, ErrorKind, Read};
17
18pub(super) struct Buffer {
19    // The buffer.
20    buf: Box<[MaybeUninit<u8>]>,
21    // The current seek offset into `buf`, must always be <= `filled`.
22    pos: usize,
23    // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
24    // initialized with bytes from a read.
25    filled: usize,
26    // Whether `buf` has been fully initialized. We track this so that we can accurately tell
27    // `read_buf` how many bytes of buf are initialized, to bypass as much of its defensive
28    // initialization as possible. Calls to `fill_buf` are not required to actually fill the buffer,
29    // and omitting this is a huge perf regression for `Read` impls that do not.
30    initialized: bool,
31}
32
33impl Buffer {
34    #[cfg(not(no_global_oom_handling))]
35    #[inline]
36    pub(super) fn with_capacity(capacity: usize) -> Self {
37        let buf = Box::new_uninit_slice(capacity);
38        Self { buf, pos: 0, filled: 0, initialized: false }
39    }
40
41    #[inline]
42    pub(super) fn try_with_capacity(capacity: usize) -> io::Result<Self> {
43        match Box::try_new_uninit_slice(capacity) {
44            Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: false }),
45            Err(_) => {
46                Err(io::const_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer"))
47            }
48        }
49    }
50
51    #[inline]
52    pub(super) fn buffer(&self) -> &[u8] {
53        // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and
54        // that region is initialized because those are all invariants of this type.
55        unsafe { self.buf.get_unchecked(self.pos..self.filled).assume_init_ref() }
56    }
57
58    #[inline]
59    pub(super) fn capacity(&self) -> usize {
60        self.buf.len()
61    }
62
63    #[inline]
64    pub(super) fn filled(&self) -> usize {
65        self.filled
66    }
67
68    #[inline]
69    pub(super) fn pos(&self) -> usize {
70        self.pos
71    }
72
73    // This is only used by a test which asserts that the initialization-tracking is correct.
74    pub(super) fn initialized(&self) -> bool {
75        self.initialized
76    }
77
78    #[inline]
79    pub(super) fn discard_buffer(&mut self) {
80        self.pos = 0;
81        self.filled = 0;
82    }
83
84    #[inline]
85    pub(super) fn consume(&mut self, amt: usize) {
86        self.pos = cmp::min(self.pos + amt, self.filled);
87    }
88
89    /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to
90    /// `visitor` and return true. If there are not enough bytes available, return false.
91    #[inline]
92    pub(super) fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
93    where
94        V: FnMut(&[u8]),
95    {
96        if let Some(claimed) = self.buffer().get(..amt) {
97            visitor(claimed);
98            // If the indexing into self.buffer() succeeds, amt must be a valid increment.
99            self.pos += amt;
100            true
101        } else {
102            false
103        }
104    }
105
106    #[inline]
107    pub(super) fn unconsume(&mut self, amt: usize) {
108        self.pos = self.pos.saturating_sub(amt);
109    }
110
111    /// Read more bytes into the buffer without discarding any of its contents
112    pub(super) fn read_more(&mut self, mut reader: impl Read) -> io::Result<usize> {
113        let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]);
114
115        if self.initialized {
116            // SAFETY: `self.initialized` is only set after `self.buf` was
117            // fully initialized, and once `self.buf` is fully initialized
118            // no part will become uninitialized.
119            unsafe { buf.set_init() };
120        }
121
122        reader.read_buf(buf.unfilled())?;
123        self.filled += buf.len();
124        self.initialized = buf.is_init();
125        Ok(buf.len())
126    }
127
128    /// Remove bytes that have already been read from the buffer.
129    pub(super) fn backshift(&mut self) {
130        self.buf.copy_within(self.pos..self.filled, 0);
131        self.filled -= self.pos;
132        self.pos = 0;
133    }
134
135    #[inline]
136    pub(super) fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
137        // If we've reached the end of our internal buffer then we need to fetch
138        // some more data from the reader.
139        // Branch using `>=` instead of the more correct `==`
140        // to tell the compiler that the pos..cap slice is always valid.
141        if self.pos >= self.filled {
142            debug_assert!(self.pos == self.filled);
143
144            let mut buf = BorrowedBuf::from(&mut *self.buf);
145
146            if self.initialized {
147                // SAFETY: `self.initialized` is only set after `self.buf` was
148                // fully initialized, and once `self.buf` is fully initialized
149                // no part will become uninitialized.
150                unsafe { buf.set_init() };
151            }
152
153            let result = reader.read_buf(buf.unfilled());
154
155            self.pos = 0;
156            self.filled = buf.len();
157            self.initialized = buf.is_init();
158
159            result?;
160        }
161        Ok(self.buffer())
162    }
163}