#diff #struct #pattern

diff-struct

A trait for diffing and applying diffs to types

10 releases

new 0.5.1 Dec 3, 2022
0.5.0 Oct 22, 2022
0.4.2 Jun 20, 2022
0.4.1 Dec 16, 2021
0.1.0 Aug 6, 2020

#134 in Rust patterns

Download history 227/week @ 2022-08-17 231/week @ 2022-08-24 215/week @ 2022-08-31 368/week @ 2022-09-07 264/week @ 2022-09-14 172/week @ 2022-09-21 241/week @ 2022-09-28 296/week @ 2022-10-05 330/week @ 2022-10-12 345/week @ 2022-10-19 335/week @ 2022-10-26 333/week @ 2022-11-02 267/week @ 2022-11-09 739/week @ 2022-11-16 1141/week @ 2022-11-23 1018/week @ 2022-11-30

3,199 downloads per month
Used in 10 crates (7 directly)

MIT license

39KB
1K SLoC

Diff

A Rust trait for diffing and applying diffs between data structures. Features a derive macro.

Abstractly speaking, a 'diff' between two structs A and B can be considered the change necessary to make to A to produce B. Succinctly, the pattern can be written as A -> B = D and A <- D = B

Diff is automatically derived on bools, numerals, Option's, HashMap's, and Vec's (provided the types they contain also implement Diff). The implementation of diffing Vec's is non-standard. It is faster and simpler than Myer's algorithm, but more error-prone on lists with many nearby duplicate elements.

Derive macro

The derive macro can be used on tuple or field structs to produce a new struct representing their difference. Note that this new struct is not considered to be the same type as the base struct, because certain data types cannot represent their own diff (bools, maps, lists, etc). Currently only 1 helper attribute is supported, attr which allows passing attributes (doc comments/derives) to the generated struct. The generated struct name is by default the name of the base struct plus "Diff". Example:

#[derive(Debug, Default, PartialEq, Diff)]
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);
}

In action

  • motion_lib: a modding tool for the proprietary motion_lib.bin filetype in SSBU. Utilizing this crate, the project features functions for producing file differences as serialized yaml. With this functionality, users can determine quickly what changes were made to the regular file across game updates, and apply those changes to their modded files to keep them up to date. Vise versa, they can apply their modded file's diffs to the new version of the file to achieve the same result.

In theory

An object implementing Diff will translate well into human-readable diffs of arbitrary data types, avoiding the problems and false positives of diffing or patching plain-text versions of the serialized structs.

Dependencies

~0.3–1MB
~22K SLoC