14个版本 (8个破坏性更新)
0.10.0 | 2021年5月17日 |
---|---|
0.9.1 | 2020年1月1日 |
0.9.0 | 2019年12月31日 |
0.4.0 | 2019年11月26日 |
#202 在 数据结构
44,625 每月下载量
在 14 个crate中使用 (直接使用3个)
35KB
1K SLoC
Diffus
在任意数据结构的两个实例之间查找差异。
Diffus 动作展示
use diffus_derive::Diffus;
use diffus::{edit, Diffable};
#[derive(Diffus)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let left_point = Point { x: 1, y: 2 };
let right_point = Point { x: 1, y: 3 };
let diff = left_point.diff(&right_point);
match diff {
edit::Edit::Copy => println!("point: no difference"),
edit::Edit::Change(EditedPoint { x, y }) => {
match x {
edit::Edit::Copy => println!("x: no difference"),
edit::Edit::Change((left_x, right_x)) => println!("x: {} => {}", left_x, right_x),
}
match y {
edit::Edit::Copy => println!("y: no difference"),
edit::Edit::Change((left_y, right_y)) => println!("y: {} => {}", left_y, right_y),
}
}
}
}
Diffus 在映射中的应用
映射之间的差异是通过其键进行的。元素的标识来自其关联的键,在其他方面它以与使用Same
的集合相同的方式进行工作。
映射的可能编辑操作有 Copy
、Insert
、Remove
、Change
。
use diffus::{edit, Diffable};
fn main() {
let unity: std::collections::HashMap<_, _> =
[(1, 1), (2, 2), (3, 3)].iter().cloned().collect();
let not_unity: std::collections::HashMap<_, _> =
[(1, 1), (2, 3), (4, 4)].iter().cloned().collect();
if let edit::Edit::Change(diff) = unity.diff(¬_unity) {
assert!(diff[&1].is_copy());
assert_eq!(diff[&2].change().unwrap(), &(&2, &3));
assert!(diff[&3].is_remove());
assert_eq!(diff[&4].insert().unwrap(), &4);
} else {
unreachable!()
}
}
Diffus 在集合中的应用
通过最长公共子序列 (LCS) 算法以及支持对象值改变但保持其Same
“标识”的额外支持来进行集合之间的差异。
字符串被视为集合。
集合的可能编辑操作有 Copy
、Insert
、Remove
、Change
。
use diffus_derive::Diffus;
use diffus::{edit::{self, collection}, Same, Diffable};
#[derive(Diffus, Debug)]
struct Identified {
id: u32,
value: u32,
}
impl Same for Identified {
fn same(&self, other: &Self) -> bool {
self.id == other.id
}
}
fn main() {
let left = vec![
Identified { id: 1, value: 0 },
Identified { id: 2, value: 0 },
Identified { id: 3, value: 0 },
Identified { id: 4, value: 0 },
Identified { id: 5, value: 0 },
Identified { id: 6, value: 0 },
Identified { id: 7, value: 0 },
];
let right = vec![
Identified { id: 1, value: 0 },
Identified { id: 2, value: 1 },
Identified { id: 4, value: 0 },
Identified { id: 3, value: 0 },
Identified { id: 5, value: 0 },
Identified { id: 6, value: 0 },
];
let diff = left.diff(&right);
match diff {
edit::Edit::Copy => println!("no difference"),
edit::Edit::Change(diff) => {
diff.into_iter().map(|edit| {
match edit {
collection::Edit::Copy(elem) => println!("copy: {:?}", elem),
collection::Edit::Insert(elem) => println!("insert: {:?}", elem),
collection::Edit::Remove(elem) => println!("remove: {:?}", elem),
collection::Edit::Change(EditedIdentified { id, value}) => {
println!("changed:");
match id {
edit::Edit::Copy => println!(" copy: id"),
edit::Edit::Change((left_id, right_id)) => println!(" id: {} => {}", left_id, right_id),
}
match value {
edit::Edit::Copy => println!(" copy: value"),
edit::Edit::Change((left_value, right_value)) => println!(" value: {} => {}", left_value, right_value),
}
}
};
}).collect::<Vec<_>>();
},
};
}
Diffus 在枚举中的应用
两个枚举之间的差异按预期工作,它将变体更改与关联变体字段更改分开。
枚举的可能编辑操作有 Copy
、VariantChanged
、AssociatedChanged
。
use diffus_derive::Diffus;
use diffus::{edit, Diffable};
#[derive(Diffus, Debug, PartialEq)]
enum Test {
A,
B(String),
Bd(String, u32),
C { x: u32 },
Cd { x: u32, y: String },
}
fn main() {
let left = Test::Cd {
x: 42,
y: "Bilbo Baggins".to_owned(),
};
let right = Test::Cd {
x: 42,
y: "Frodo Baggins".to_owned(),
};
if let edit::Edit::Change(edit::enm::Edit::AssociatedChanged(
EditedTest::Cd { x, y },
)) = left.diff(&right)
{
assert!(x.is_copy());
assert!(y.is_change());
} else {
unreachable!()
}
let left = Test::Cd {
x: 42,
y: "Bilbo Baggins".to_owned(),
};
let right = Test::B("Frodo Baggins".to_owned());
if let edit::Edit::Change(edit::enm::Edit::VariantChanged(l, r)) =
left.diff(&right)
{
assert_eq!(&left, l);
assert_eq!(&right, r);
} else {
unreachable!()
}
}
使用diffus进行自定义差异
差异可以轻松地专门化以满足您的需求。
use diffus::{edit, Diffable};
struct Secret(String);
impl<'a> Diffable<'a> for Secret {
type Diff = ();
fn diff(&'a self, other: &'a Self) -> edit::Edit<Self::Diff> {
if self.0 == other.0 {
edit::Edit::Copy
} else {
edit::Edit::Change(())
}
}
}
fn main() {
assert_eq!(
Secret("Something".to_owned()).diff(&Secret("Else".to_owned()))
.change().unwrap(),
&()
);
}
依赖项
~0.4–0.8MB
~16K SLoC