Rust in Everything
基于 bytes 1.12.1

Bytes

这一部分是本卷的重点,讲共享主线:一个只读的 Bytes 怎么做到 clone、切片、drop 都不拷贝数据。代码几乎都在 src/bytes.rs,1.7k 行,再加上 src/bytes_mut.rs 末尾给 freeze 用的一张表。

四章按「先看结构,再看每种存储,再看 clone 和切片」排列:

  1. 结构与 Vtable:Bytes 是 ptr、len、data、vtable 四个字,32 字节;Vtable 是五个函数指针,clone 和 is_unique 借用 data,into_vec、into_mut、drop 从 1.12.0 起按值拿 data(#826)。用手写表而不是 trait object,是因为 data 可以是空指针、带标记的指针或缓冲本身的地址,还要能被原子地换掉。
  2. 五种存储:静态切片、可提升(奇偶两张表)、Shared、from_owner 的 Owned<T>、BytesMut 冻结出来的共享块,各自的 clone / into_vec / into_mut / is_unique / drop;From<Vec<u8>> 在 len == cap 时走 Box<[u8]> 不分配,否则直接建 Shared;用一个程序认出每种构造最后落在哪张表上。
  3. clone 与提升:可提升存储第一次 clone 时用 CAS 把 data 换成 Shared,竞争失败的一方释放自己的那份;引用计数的内存序;is_unique 与 try_into_mut。
  4. 切片:slice、split_to、split_off 先 clone 一次再改 ptr 和 len;truncate 遇到可提升存储要先提升,因为那两张表不记容量;切出空段时不 clone,返回一个地址仍在原处的静态空 Bytes。
flowchart TB
  ctor["构造 Bytes"] --> pick["选一张 vtable"]
  pick --> clonenode["clone:按表分派"]
  clonenode --> promote["第一次 clone 提升"]
  pick --> slicenode["slice:改 ptr 和 len"]
  slicenode --> clonenode
  clonenode --> dropnode["drop:按表分派"]
  pick --> back["转回 Vec 或 BytesMut"]

谁在用这些 Bytes:hyper 把请求头和 body 分块从读缓冲里 split_to(n).freeze() 出来交给上层(解析与编码、body 的解码与编码),axum 的 Bytes 提取器把整个 body 收成一个 Bytes(body 提取器)。freeze 之前的构建那一侧在 03 BytesMut。

💬 关联讨论

发起讨论
加载中...