派生宏
两条主线上「类型」那一半的代码几乎都不是手写的:#[derive(Serialize, Deserialize)] 在编译期读结构体定义,写出 impl Serialize 和 impl Deserialize。这一部分读 serde_derive/src/(约 9k 行):先看宏怎么把输入变成内部 AST、怎么报错、输出外面包了什么,再看 #[serde(...)] 属性,然后逐个方向读生成的代码,最后讲泛型和生命周期。
- 派生宏的流水线:
syn::DeriveInput经Container::from_ast解析属性、check.rs检查组合、Ctxt把所有错误攒起来一起报,函数体用Fragment拼好后由dummy.rs包进const _: () = { ... };remote 派生里pretend.rs生成一段永远不跑的代码压住 dead_code。 - 属性:容器、变体、字段三层属性,
attr.rs用parse_nested_meta逐项解析并查重,rename_all的八种大小写规则、alias、rename(serialize = ..., deserialize = ...),以及属性写重、写错时的报错。 - 生成的 Serialize:struct 走
serialize_struct,字段数怎么算、skip_serializing_if怎么把它变成运行期的值;newtype / tuple / unit 和 enum 四种表示各调哪个方法;serialize_with的包装类型__SerializeWith。 - 生成的 Deserialize:
__Field枚举和__FieldVisitor怎么认字段,visit_map的循环、Option字段缺省为None的来历、visit_seq、default和deny_unknown_fields,以及deserialize_in_place。 - 泛型与 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 的表示与缓冲。
💬 关联讨论
发起讨论加载中...