12个版本
0.5.3 | 2023年7月22日 |
---|---|
0.5.1 | 2022年12月3日 |
0.5.0 | 2022年10月22日 |
0.4.2 | 2022年6月20日 |
0.3.1 | 2020年11月15日 |
#141 in 数据结构
8,193 每月下载量
用于 28 个crate(13个直接使用)
45KB
1.5K SLoC
差异
一个用于在数据结构之间比较和应用差异的Rust特质。具有 derive 宏。
从抽象的角度来看,结构体 A 和 B 之间的 '差异' 可以被认为是将 A 改成 B 所必需的更改。简而言之,这种模式可以写成 A -> B = D 和 A <- D = B
Diff 自动从几个常见的基类型中派生出来,包括:整数(i8、u32 等)、浮点数、非零整数、布尔值、字符、String、&str 和 PathBuf。
Diff 还从几个容器类型中派生出来,例如:Option、Box、Rc、Arc、HashMap、BTreeMap、HashSet、BTreeSet、元组(长度最多为 18)、数组,以及 Vec。
容器类型在比较时受到一些类型限制。内部类型 T 总是必须实现 Diff。根据容器类型,可能还有其他限制,例如 Debug、Clone、PartialEq。这些限制也可能适用于差异类型(T::Repr)。Vec 的差异实现是非标准的。它比 Myer 的算法更快、更简单,但在具有许多附近重复元素的列表上更易于出错。
derive 宏
derive 宏可以用于元组或字段结构体,以生成表示它们差异的新结构体。请注意,这个新结构体不被视为与基结构体相同的类型,因为某些数据类型无法表示其自身的差异(布尔值、映射、列表等)。目前仅支持 1 个辅助属性 attr
,它允许将属性(文档注释/derives)传递给生成的结构体。默认情况下,生成的结构体名称是基结构体名称加上 "Diff"。示例
#[derive(Debug, Default, PartialEq, Diff)]
// this will apply the specified derives on the generated 'ProjectMetaDiff' struct
#[diff(attr(
#[derive(Debug, PartialEq)]
))]
pub struct ProjectMeta {
contributors: Vec<String>,
combined_work_hours: usize,
}
#[test]
fn test_apply() {
let mut base = ProjectMeta::default();
let contribution_a = ProjectMeta {
contributors: vec!["Alice".into()],
combined_work_hours: 3,
};
let contribution_b = ProjectMeta {
contributors: vec!["Bob".into(), "Candice".into()],
combined_work_hours: 10,
};
let expected = ProjectMeta {
contributors: vec!["Bob".into(), "Candice".into(), "Alice".into()],
combined_work_hours: 13,
};
let diff_a = base.diff(&contribution_a);
let diff_b = base.diff(&contribution_b);
base.apply(&diff_a);
base.apply(&diff_b);
assert_eq!(base, expected);
}
实际应用
- motion_lib:SSBU中 proprietary motion_lib.bin 文件类型的修改工具。使用此库,项目提供了生成序列化 yaml 格式的文件差异功能。利用此功能,用户可以快速确定游戏更新后常规文件发生了哪些更改,并将这些更改应用到他们的修改文件中以保持其更新。反之,他们也可以将修改文件的差异应用到新版本的文件上以实现相同的结果。
理论上的
实现 Diff 的对象可以很好地转换为任意数据类型的可读差异,避免了比较或修补序列化结构体的纯文本版本时的问题和误报。
依赖项
~0.4–1MB
~24K SLoC