关于 serde-code-review
serde-code-review 是用于审查 Serde 代码的 Rust 代码审查技能。它覆盖派生、枚举表示、字段属性、edition 兼容性和序列化往返,并要求问题具备代码证据。
主要功能
- 01检查 Cargo 与序列化格式
- 02审查派生和字段属性
- 03检查枚举表示方式
- 04检查 Edition 2024 兼容性
- 05序列化往返正确性清单
适用场景
- 01审查跨序列化边界的 Serde 类型
- 02检查枚举和字段的线缆格式
- 03评估 edition 兼容性与往返测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill serde-code-review安装后在 Claude Code 中输入/serde-code-review确认已加载。
附带文件references/custom-serialization.mdreferences/derive-patterns.md
详细介绍
Serde 代码审查
审查工作流
- 检查 Cargo.toml — 记录 serde 功能(
derive、rc)、格式 crate(serde_json、toml、bincode等)以及 Rust edition(2024 edition 有影响 serde 代码的破坏性变更) - 检查 derive 用法 — 确认是否正确派生了
Serialize和Deserialize - 检查枚举表示形式 — 枚举标记会影响线格式兼容性和可读性
- 检查字段属性 — 重命名、默认值和跳过字段会影响 API 契约
- 检查与 2024 edition 的兼容性 — 保留关键字
gen、RPIT 生命周期捕获变更、never_type_fallback - 验证往返正确性 — 序列化后的数据必须能反序列化回相同的值
报告问题前的关卡
按顺序运行。只有通过适用的步骤后,才能编写问题报告。
-
磁盘上的 Serde 上下文 — 通过条件: 已阅读相关的
Cargo.toml(crate 或工作区根目录),并能说明 Rustedition、非默认的serde/serde_derive功能(derive、rc),以及所审查代码适用的格式 crate(serde_json、toml、bincode等)。然后,仅当该文件支持时,才应用特定 edition 的检查项(例如gen、RPIT /never_type_fallback)。 -
每个问题的证据 — 通过条件: 每个问题都引用当前代码树中的
[FILE:LINE],指向相关的struct/enum、Serialize/Deserialize实现或属性块(不得依赖记忆、仅查阅文档或引用其他分支)。 -
对照协议进行类别检查 — 通过条件: 对于相应的问题类型(derive 属性、枚举标记、
flatten、自定义实现、sqlx 与 serde 的一致性),已运行 review-verification-protocol 技能中的对应检查(例如,在报告“表示形式错误”前检查完整类型定义和 serde 属性;在报告仅适用于 2024 edition 的问题前,确认Cargo.toml中的 edition)。然后添加问题报告。 -
输出格式 — 通过条件: 报告行符合下方的“输出格式”(严重级别 + 描述)。
输出格式
按以下格式报告问题:
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
快速参考
| 问题类型 | 参考资料 |
|---|---|
| Derive 模式、属性宏、字段配置 | references/derive-patterns.md |
| 自定义 Serialize/Deserialize、特定格式的问题 | references/custom-serialization.md |
审查清单
Derive 用法
- 对跨越序列化边界的类型使用
#[derive(Serialize, Deserialize)] - 在 serde derive 旁使用
#[derive(Debug)](用于调试序列化问题) - 当 serde 为可选依赖时,使用受功能门控的 derive:
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - 对仅供 serde 使用的字段,优先使用
#[expect(unused)]而非#[allow(unused)](可自行清理的 lint 抑制,自 Rust 1.81 起稳定)
枚举表示形式
- 显式指定枚举标记(不要在预期使用其他格式时依赖 serde 默认的外部标记格式)
- 标记名称保持稳定,且不会与字段名称冲突
- 在整个 API 中一致使用
#[serde(rename_all = "...")]
字段配置
- 对可选字段使用
#[serde(skip_serializing_if = "Option::is_none")](生成简洁的 JSON 输出) - 对反序列化时应使用回退值的字段使用
#[serde(default)] - 当 Rust 字段名与线格式不同时使用
#[serde(rename = "...")] - 谨慎使用
#[serde(flatten)](可能导致键冲突) - 对需要向前兼容的类型,不使用
#[serde(deny_unknown_fields)] - 不要将字段或变体命名为
gen— 它是 2024 edition 的保留关键字(使用r#gen或重命名)
数据库集成(sqlx)
- 使用
#[derive(sqlx::Type)]的枚举,其表示形式应与 serde 一致 - 枚举变体的大小写应与 serde(
rename_all)和 sqlx(rename_all)保持一致
Edition 2024 兼容性
- 不存在名为
gen的字段或枚举变体(这是保留关键字——请使用带有#[serde(rename = "gen")]的r#gen,或选择其他名称) - 返回
impl Trait的自定义Serialize/Deserialize实现已考虑 RPIT 生命周期捕获变更(默认捕获所有作用域内的生命周期;使用+ use<'a>进行精确控制) - 反序列化错误路径已处理
never_type_fallback——!会回退为!,而不是(),这会影响Result<T, !>模式的匹配穷尽性
正确性
- 复杂类型具有往返测试(序列化 → 反序列化 → assert_eq)
- 具有往返测试的类型派生了
PartialEq - 不存在有损转换(例如,JSON 数字中的
f64→i64) - 金额/精度敏感值使用
Decimal,而非f64
严重性校准
严重
- 序列化器与反序列化器之间的枚举表示不匹配(导致数据丢失)
- 缺少
#[serde(rename)],导致 API 破坏性字段名称变更 #[serde(flatten)]导致键静默冲突- 有损数值转换(金额值的
f64精度损失)
主要
- 相关类型的
rename_all不一致(导致 API 易混淆) - 缺少
skip_serializing_if,导致输出中出现多余的 null/空值 - 在会被持续演进的 API 使用的类型上设置
deny_unknown_fields(破坏向前兼容性) - 复杂枚举表示缺少往返测试
- 字段或变体命名为
gen,但未使用r#gen转义(导致 Edition 2024 编译失败)
次要
- 在必填字段上不必要地使用
#[serde(default)] - 枚举使用字符串表示,而非效率更高的数字表示
- 能用 derive 和属性实现,却采用冗长的自定义实现
- 对仅用于 serde 的字段使用
#[allow(unused)],而非#[expect(unused)](优先使用可自行清理的 lint 抑制方式)
说明性
- 建议切换枚举表示方式,以获得更简洁的线格式
- 建议与 serde 一起添加
#[non_exhaustive],以实现向前兼容
有效模式(不要标记)
- 外部标记枚举——serde 的默认方式,适用于许多场景
#[serde(untagged)]枚举——由结构而非标签进行区分时有效- 动态数据使用
serde_json::Value——适用于真正没有架构的字段 - 对计算字段使用
#[serde(skip)]——适用于派生值/缓存值 - 自定义格式使用
#[serde(with = "...")]——日期、UUID 等的标准做法 - 使用带有
#[serde(rename = "gen")]的r#gen——针对线格式中gen字段的正确 Edition 2024 解决方法 - 在自定义序列化器返回类型上使用
+ use<'a>——精确控制 RPIT 生命周期捕获(Edition 2024)
提交发现前
完成上文的 门槛(报告发现前);门槛 3 纳入了 review-verification-protocol 技能,用于处理 serde 相关问题类型。