Rust in Everything
基于 serde 1.0.229

派生宏

两条主线上「类型」那一半的代码几乎都不是手写的:#[derive(Serialize, Deserialize)] 在编译期读结构体定义,写出 impl Serialize 和 impl Deserialize。这一部分读 serde_derive/src/(约 9k 行):先看宏怎么把输入变成内部 AST、怎么报错、输出外面包了什么,再看 #[serde(...)] 属性,然后逐个方向读生成的代码,最后讲泛型和生命周期。

  1. 派生宏的流水线:syn::DeriveInput 经 Container::from_ast 解析属性、check.rs 检查组合、Ctxt 把所有错误攒起来一起报,函数体用 Fragment 拼好后由 dummy.rs 包进 const _: () = { ... };remote 派生里 pretend.rs 生成一段永远不跑的代码压住 dead_code。
  2. 属性:容器、变体、字段三层属性,attr.rs 用 parse_nested_meta 逐项解析并查重,rename_all 的八种大小写规则、alias、rename(serialize = ..., deserialize = ...),以及属性写重、写错时的报错。
  3. 生成的 Serialize:struct 走 serialize_struct,字段数怎么算、skip_serializing_if 怎么把它变成运行期的值;newtype / tuple / unit 和 enum 四种表示各调哪个方法;serialize_with 的包装类型 __SerializeWith。
  4. 生成的 Deserialize:__Field 枚举和 __FieldVisitor 怎么认字段,visit_map 的循环、Option 字段缺省为 None 的来历、visit_seq、default 和 deny_unknown_fields,以及 deserialize_in_place。
  5. 泛型与 bound:bound.rs 给字段里出现的类型参数加 T: Serialize,#[serde(bound)] 覆盖默认推断,PhantomData 和被跳过的字段不加;生成的 'de 生命周期和 borrow 怎么加约束。
flowchart TB
  input["struct / enum 定义"] --> pipe[流水线]
  attrs["#[serde] 属性"] --> pipe
  pipe --> ser["impl Serialize"]
  pipe --> de["impl Deserialize"]
  bounds[泛型与 bound] --> ser
  bounds --> de

看生成代码用 cargo expand,约定见怎么读这一卷;一次完整的展开和调用顺序在一次往返。enum 的四种表示和缓冲在下一部分 04 enum 的表示与缓冲。

💬 关联讨论

发起讨论
加载中...