1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
/// ! `BufReader` 的缓冲区管理逻辑的封装。
///
/// 该模块将 `BufReader` 的基本功能分解出来,以保护两个 core 不,变体:
/// * `buf` 的 `filled` 字节总是被初始化
/// * `pos` 始终 <= `filled` 由于该模块封装了缓冲区管理逻辑,我们可以确保范围 `pos..filled` 始终是缓冲区初始化区域的有效索引。
/// 这意味着想要通过 `buffer` + `consume` 从 `BufReader` 读取的用户代码可以这样做而不会遇到任何运行时边界检查。
///
///
///
///
use crate::cmp;
use crate::io::{self, BorrowedBuf, Read};
use crate::mem::MaybeUninit;
pub struct Buffer {
// 缓冲区。
buf: Box<[MaybeUninit<u8>]>,
// 当前 seek 偏移到 `buf` 中,必须始终 <= `filled`。
pos: usize,
// 每个调用到 `fill_buf` 设置 `filled` 以指示在 `buf` 的开头有多少字节被读取的字节初始化。
//
filled: usize,
// 这是所有 `fill_buf` 调用返回的最大字节数。
// 我们跟踪这一点,以便我们可以准确地告诉 `read_buf` 初始化了多少字节的 buf,以尽可能多地绕过它的防御性初始化。
//
// 请注意,虽然这通常与 `filled` 相同,但并非必须如此。
// 对 `fill_buf` 的调用不需要实际填充缓冲区,对于不需要的 `Read` impls 来说,忽略这一点是一个巨大的性能回归。
initialized: usize,
}
impl Buffer {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let buf = Box::new_uninit_slice(capacity);
Self { buf, pos: 0, filled: 0, initialized: 0 }
}
#[inline]
pub fn buffer(&self) -> &[u8] {
// SAFETY: self.pos 和 self.cap 有效,并且 self.cap => self.pos,并且该区域被初始化,因为它们都是这种类型的不,变体。
//
unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) }
}
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn filled(&self) -> usize {
self.filled
}
#[inline]
pub fn pos(&self) -> usize {
self.pos
}
// 这仅由断言初始化跟踪正确的测试使用。
#[cfg(test)]
pub fn initialized(&self) -> usize {
self.initialized
}
#[inline]
pub fn discard_buffer(&mut self) {
self.pos = 0;
self.filled = 0;
}
#[inline]
pub fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.filled);
}
/// 如果缓冲区中有 `amt` 字节可用,则将包含这些字节的切片传递给 `visitor` 并返回 true。
/// 如果没有足够的可用字节,则返回 false。
#[inline]
pub fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
where
V: FnMut(&[u8]),
{
if let Some(claimed) = self.buffer().get(..amt) {
visitor(claimed);
// 如果对 self.buffer() 的索引成功,amt 必须是一个有效的增量。
self.pos += amt;
true
} else {
false
}
}
#[inline]
pub fn unconsume(&mut self, amt: usize) {
self.pos = self.pos.saturating_sub(amt);
}
#[inline]
pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
// 如果我们已经到达内部缓冲区的末尾,那么我们需要从 reader 获取更多数据。
// 使用 `>=` 而不是更正确的 `==` 进行分支,以告知编译器 pos..cap 切片始终有效。
//
//
if self.pos >= self.filled {
debug_assert!(self.pos == self.filled);
let mut buf = BorrowedBuf::from(&mut *self.buf);
// SAFETY: `self.filled` 字节将始终被初始化。
unsafe {
buf.set_init(self.initialized);
}
reader.read_buf(buf.unfilled())?;
self.pos = 0;
self.filled = buf.len();
self.initialized = buf.init_len();
}
Ok(self.buffer())
}
}