| Crates.io | structdiff |
| lib.rs | structdiff |
| version | 0.7.3 |
| created_at | 2022-10-26 04:52:36.322401+00 |
| updated_at | 2025-02-22 21:24:34.542051+00 |
| description | zero-dependency crate for generating and applying partial diffs between struct instances |
| homepage | |
| repository | https://github.com/knickish/structdiff |
| max_upload_size | |
| id | 697555 |
| size | 194,534 |
A lightweight, zero-dependency struct diffing library which allows changed fields to be collected and applied. Derive Difference on a struct, then use the StructDiff trait to make and apply diffs. Supports optional serialization of the generated diff types with serde or nanoserde for ease of use.
use structdiff::{Difference, StructDiff};
#[derive(Debug, PartialEq, Clone, Difference)]
struct Example {
field1: f64,
#[difference(skip)]
field2: Vec<i32>,
#[difference(collection_strategy="unordered_array_like")]
field3: BTreeSet<usize>,
}
let first = Example {
field1: 0.0,
field2: vec![],
field3: vec![1, 2, 3].into_iter().collect(),
};
let second = Example {
field1: 3.14,
field2: vec![1],
field3: vec![2, 3, 4].into_iter().collect(),
};
let diffs = first.diff(&second);
// diffs is now a Vec of differences between the two instances,
// with length equal to number of changed/unskipped fields
assert_eq!(diffs.len(), 2);
let diffed = first.apply(diffs);
// diffed is now equal to second, except for skipped field
assert_eq!(diffed.field1, second.field1);
assert_eq!(&diffed.field3, &second.field3);
assert_ne!(diffed, second);
For more examples take a look at integration tests
#[difference(skip)] - Do not consider this field when creating a diff#[difference(recurse)] - Generate a StructDiff for this field when creating a diff#[difference(collection_strategy = {})]
"ordered_array_like" - Generates a minimal changeset for ordered, array-like collections of items which implement PartialEq. (uses levenshtein difference)"unordered_array_like" - Generates a minimal changeset for unordered, array-like collections of items which implement Hash + Eq."unordered_map_like" - Generates a minimal changeset for unordered, map-like collections for which the key implements Hash + Eq.#[difference(map_equality = {})] - Used with unordered_map_like
"key_only" - only replace a key-value pair for which the key has changed"key_and_value" - replace a key-value pair if either the key or value has changed#[difference(setter)] - Generate setters for this struct field#[difference(setter_name = {})] - Use this name instead of the default value when generating a setter for this field (used on field)#[difference(setters)] - Generate setters for all fields in the struct
field1 of the Example struct used above, a function with the signature set_field1_with_diff(&mut self, value: Option<usize>) -> Option<<Self as StructDiff>::Diff> will be generated. Useful when a single field will be changed in a struct with many fields, as it saves the comparison of all other fields.#[difference(expose)]/#[difference(expose = "MyDiffTypeName")] - expose the generated difference type (optionally, with the specified name)nanoserde, serde] - Serialization of Difference derived associated types. Allows diffs to easily be sent over network.debug_diffs - Derive Debug on the generated diff typegenerated_setters - Enable generation of setters for struct fields. These setters automatically return a diff if a field's value is changed by the assignment.rustc_hash - Use the (non-cryptographic) hash implementation from the rustc-hash crate instead of the default hasher. Much faster diff generation for collections at the cost of a dependency.This is being used actively for my own projects, although it's mostly working now. PRs will be accepted for either more tests or functionality.