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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
#![unstable(feature = "read_buf", issue = "78485")]
#[cfg(test)]
mod tests;
use crate::fmt::{self, Debug, Formatter};
use crate::io::{Result, Write};
use crate::mem::{self, MaybeUninit};
use crate::{cmp, ptr};
/// 增量填充和初始化的借用字节缓冲区。
///
/// 这种类型是一种 "double cursor"。
/// 它跟踪缓冲区中的三个区域:缓冲区开头的区域已被逻辑填充数据,已在某个时刻初始化但尚未逻辑填充的区域,以及完全未初始化的末尾区域。
///
/// 填充区域保证是初始化区域的子集。
///
/// 总之,缓冲区的内容可以可视化为:
///
/// ```not_rust
/// [ capacity ]
/// [ filled | unfilled ]
/// [ initialized | uninitialized ]
/// ```
///
/// `BorrowedBuf` 是通过一个独特的引用 (`&mut`) 围绕一些现有数据 (或数据容量) 创建的。`BorrowedBuf` 可以配置 (例如,使用 `clear` 或 `set_init`),但不能直接写入。
/// 要写入缓冲区,请使用 `unfilled` 创建一个 `BorrowedCursor`。
/// 游标对缓冲区的未填充部分具有只写访问权限 (您可以将其视为只写迭代器)。
///
/// 生命周期 `'data` 是,底层,数据的生命周期的界限。
///
pub struct BorrowedBuf<'data> {
/// 缓冲区的,底层,数据。
buf: &'data mut [MaybeUninit<u8>],
/// 已知要填充的 `self.buf` 的长度。
filled: usize,
/// 已知要初始化的 `self.buf` 的长度。
init: usize,
}
impl Debug for BorrowedBuf<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedBuf")
.field("init", &self.init)
.field("filled", &self.filled)
.field("capacity", &self.capacity())
.finish()
}
}
/// 从完全初始化的切片创建一个新的 `BorrowedBuf`。
impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
#[inline]
fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
let len = slice.len();
BorrowedBuf {
// SAFETY: 初始化数据永远不会变为未初始化是 BorrowedBuf 的不,变体
buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
filled: 0,
init: len,
}
}
}
/// 从未初始化的缓冲区创建一个新的 `BorrowedBuf`。
///
/// 如果已知缓冲区的一部分已经初始化,则使用 `set_init`。
impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
#[inline]
fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
BorrowedBuf { buf, filled: 0, init: 0 }
}
}
impl<'data> BorrowedBuf<'data> {
/// 返回缓冲区的总容量。
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
/// 返回缓冲区填充部分的长度。
#[inline]
pub fn len(&self) -> usize {
self.filled
}
/// 返回缓冲区初始化部分的长度。
#[inline]
pub fn init_len(&self) -> usize {
self.init
}
/// 返回对缓冲区填充部分的共享引用。
#[inline]
pub fn filled(&self) -> &[u8] {
// SAFETY: 我们只对缓冲区的填充部分进行切片,这总是有效的
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
}
/// 返回缓冲区未填充部分上的游标。
#[inline]
pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
BorrowedCursor {
start: self.filled,
// SAFETY: 我们从不分配给 `BorrowedCursor::buf`,因此以协变方式处理其生命周期是安全的。
//
buf: unsafe {
mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self)
},
}
}
/// 清除缓冲区,将填充区域重置为空。
///
/// 初始化的字节数不变,缓冲区的内容也不变。
#[inline]
pub fn clear(&mut self) -> &mut Self {
self.filled = 0;
self
}
/// 断言缓冲区的前 `n` 个字节已初始化。
///
/// `BorrowedBuf` 假定字节永远不会被取消初始化,因此当调用该方法时使用的字节数少于已知要初始化的字节数时,该方法什么也不做。
///
///
/// # Safety
///
/// 调用者必须确保缓冲区的前 `n` 个未填充字节已经初始化。
#[inline]
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
self.init = cmp::max(self.init, n);
self
}
}
/// [`BorrowedBuf`](BorrowedBuf) 未填充部分的可写视图。
///
/// 提供对底层 `BorrowedBuf` 的已初始化和未初始化部分的访问。
/// 可以使用 [`append`](BorrowedCursor::append) 将数据直接写入游标,也可以通过获取部分或全部游标的切片并写入切片来间接写入数据。
///
/// 在间接情况下,调用者必须在写入后调用 [`advance`](BorrowedCursor::advance) 来通知游标已经写入了多少字节。
///
/// 一旦数据被写入游标,它就成为底层 `BorrowedBuf` 的填充部分的一部分,并且不能再被游标访问或重写。
/// 即,游标跟踪底层 `BorrowedBuf` 的未填充部分。
///
/// 生命周期 `'a` 是底层缓冲区的生命周期的界限 (这意味着它是该缓冲区中数据的传递界限)。
///
///
///
#[derive(Debug)]
pub struct BorrowedCursor<'a> {
/// 底层缓冲区。
// 安全不,变体: 当我们创建一个 `BorrowedCursor` 时,我们将 buf 的类型视为 `BorrowedBuf` 的生命周期中的协,变体。
// 只有当我们从不通过分配来替换 `buf` 时,这才是安全的,所以不要那样做!
//
buf: &'a mut BorrowedBuf<'a>,
/// 创建游标时,底层,缓冲区的填充部分的长度。
///
start: usize,
}
impl<'a> BorrowedCursor<'a> {
/// 通过使用较小的生命周期克隆它来重新借用此游标。
///
/// 由于游标保持对其底层缓冲区的唯一访问,因此当新游标存在时,借用的游标不可访问。
///
#[inline]
pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> {
BorrowedCursor {
// SAFETY: 我们从不分配给 `BorrowedCursor::buf`,因此以协变方式处理其生命周期是安全的。
//
buf: unsafe {
mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>(
self.buf,
)
},
start: self.start,
}
}
/// 返回游标中的可用空间。
#[inline]
pub fn capacity(&self) -> usize {
self.buf.capacity() - self.buf.filled
}
/// 返回自从 `BorrowedBuf` 创建以来写入此游标的字节数。
///
/// 请注意,如果此游标是另一个游标的重新借用克隆,则返回的计数是通过任一游标写入的计数,而不是自游标重新借用以来的计数。
///
#[inline]
pub fn written(&self) -> usize {
self.buf.filled - self.start
}
/// 将共享引用返回到游标的初始化部分。
#[inline]
pub fn init_ref(&self) -> &[u8] {
// SAFETY: 我们只对缓冲区的初始化部分进行切片,这始终是有效的
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
}
/// 返回游标的初始化部分的,可变引用。
#[inline]
pub fn init_mut(&mut self) -> &mut [u8] {
// SAFETY: 我们只对缓冲区的初始化部分进行切片,这始终是有效的
unsafe {
MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
}
}
/// 将一个,可变引用,返回到游标的未初始化部分。
///
/// 取消初始化这些字节中的任何一个都是安全的。
#[inline]
pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf.buf[self.buf.init..]
}
/// 返回对整个游标的引用。
///
/// # Safety
///
/// 调用者不得取消初始化游标初始化部分中的任何字节。
#[inline]
pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.buf.buf[self.buf.filled..]
}
/// 通过断言 `n` 字节已被填充来前进游标。
///
/// 推进后,`n` 字节不再可以通过游标访问,只能通过底层缓冲区访问。
/// 即,缓冲区的填充部分增加了 `n` 个元素,而其未填充部分 (以及该游标的容量) 缩小了 `n` 个元素。
///
///
/// # Safety
///
/// 调用者必须确保游标的前 `n` 字节已正确初始化。
///
#[inline]
pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
self.buf.filled += n;
self.buf.init = cmp::max(self.buf.init, self.buf.filled);
self
}
/// 初始化游标中的所有字节。
#[inline]
pub fn ensure_init(&mut self) -> &mut Self {
let uninit = self.uninit_mut();
// SAFETY: 0 是 MaybeUninit<u8> 的有效值,并且长度与分配匹配,因为它来自切片引用。
//
unsafe {
ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
}
self.buf.init = self.buf.capacity();
self
}
/// 断言游标的前 `n` 个未填充字节已初始化。
///
/// `BorrowedBuf` 假定字节永远不会被取消初始化,因此当调用该方法时使用的字节数少于已知要初始化的字节数时,该方法什么也不做。
///
///
/// # Safety
///
/// 调用者必须确保缓冲区的前 `n` 个字节已经被初始化。
#[inline]
pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
self.buf.init = cmp::max(self.buf.init, self.buf.filled + n);
self
}
/// 将数据,追加,到游标,在其缓冲区中推进位置。
///
/// # Panics
///
/// 如果 `self.capacity()` 小于 `buf.len()`,则发生 panic。
#[inline]
pub fn append(&mut self, buf: &[u8]) {
assert!(self.capacity() >= buf.len());
// SAFETY: 我们不会取消初始化切片的任何元素
unsafe {
MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf);
}
// SAFETY: 我们只是将 buf 的全部内容添加到了填充部分。
unsafe {
self.set_init(buf.len());
}
self.buf.filled += buf.len();
}
}
impl<'a> Write for BorrowedCursor<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.append(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}