Expand description
§Difficient
Efficient, type-safe, (almost) zero-allocation structural diffing.
- Annotate your
struct
orenum
with#[derive(Diffable)]
- Diff your value with another value of the same type
- Apply the diff!
- Serialize the diff!
Visit
the diff, generating a custom stream of change events
The possibilities are endless!
§Example Usage
use difficient::{Diffable, DeepDiff, AtomicDiff, PatchOnlyDiff, Id, Replace};
// here is the type we would like to diff - note `#[derive(Diffable)]`
#[derive(Diffable, PartialEq, Debug, Clone)]
enum SimpleEnum {
First,
Second { x: &'static str, y: SimpleStruct }, // SimpleStruct defined below
}
// create an initial value
let mut source = SimpleEnum::First;
// diffing a value against itself results in no change
let diff1 = source.diff(&source);
assert!(diff1.is_unchanged());
// create a second value and diff
let mut target1 = SimpleEnum::Second {
x: "hello",
y: SimpleStruct { a: "aaa".into(), b: 123, c: vec![1.23] }
};
let diff2 = source.diff(&target1);
// the value is fully replaced by a different enum variant
let expect_diff = DeepDiff::Replaced(&target1);
assert_eq!(diff2, expect_diff);
// 'applying' a diff to source value results in the target value
source.apply(&diff2).unwrap();
assert_eq!(source, target1);
// create a third value and diff
let target2 = SimpleEnum::Second {
x: "goodbye",
y: SimpleStruct { a: "aaa".into(), b: 234, c: vec![1.23] }
};
let diff3 = target1.diff(&target2);
// here the variant is patched but not totally replaced
let expect_diff = DeepDiff::Patched(SimpleEnumDiff::Second {
x: AtomicDiff::Replaced(&"goodbye"),
y: PatchOnlyDiff::Patched(
SimpleStructDiff { a: AtomicDiff::Unchanged, b: AtomicDiff::Replaced(&234) }
)
});
assert_eq!(diff3, expect_diff);
target1.apply(&diff3).unwrap();
assert_eq!(target1, target2);
// It works for structs too!
#[derive(Diffable, PartialEq, Debug, Clone)]
struct SimpleStruct {
a: String,
b: i32,
#[diffable(skip)] // do not take `c` field into account when diffing
c: Vec<f64>,
}
let mut source = SimpleStruct {
a: "Hello".into(),
b: 123,
c: vec![3.3, 2.2, 1.1],
};
let target = SimpleStruct {
a: "Hello".into(),
b: 123,
c: vec![5.5, 4.4, 3.3],
};
let diff = source.diff(&target);
assert!(diff.is_unchanged()); // unchanged because `c` is ignored
§Visitor
With the visitor
feature activated, we can generate a series of discrete changes from the Diff
type.
See examples/visitor.rs
for a worked example.
§Efficient?
The diff function does not allocate, in most cases. This makes it extremely fast.
The exceptions are
- when dealing with boxed types
- when dealing collections (
Vec
,HashMap
orBTreeMap
)
Then it may have to allocate, which makes it merely very fast.
Structs§
Enums§
- Apply
Error - Atomic
Diff - A generic type which can represent two possible ‘diff’ states.
Appropriate for primitive types which cannot be ‘partially’ changed (e.g. bool, i32)
c.f.
DeepDiff
which can also represent a partially-changed state - Deep
Diff - A generic type which can represent three possible ‘diff’ states.
Appropriate for primitive types which can be ‘partially’ changed (e.g. structs)
c.f.
AtomicDiff
which cannot represent aPatched
state - KvDiff
- A generic type which represents the possible change-states of a Key-Value type
(e.g.
HashMap
,BTreeMap
) - Patch
Only Diff - A generic type which can represent two possible ‘diff’ states. Appropriate for types which cannot be fully replaced - this only really makes sense in the context of a derived ‘diff’ that has skipped fields
- VecChange
- VecDiff
Traits§
- Apply
- A trait that must implemented by any type that results from a ‘diff’ operation. It allows the (child) ‘diff’ type to be ‘applied’ to the parent type, mutating the parent in place to result in the value which is was originally diffed against.
- DiffKey
- A trait that must be implemented by any type
T
that is part of aVec<T>
being diffed. - Diffable
- The core trait of this library. Enables a value ‘A’ to be ‘diffed’ against another value ‘B’ of the same type, returning a ‘diff’ representing the difference between the two. The diff can then be applied to A to result in B.
- Replace
- A trait that must be implemented by any type that results from a ‘diff’ operation.