diffo
Semantic diffing for Rust structs via serde.
Features
- ð Zero boilerplate - works with any
Serializetype - ðŊ Path-based changes -
user.roles[2].name - ðĻ Multiple formatters - pretty, JSON, JSON Patch (RFC 6902), Markdown
- ð Secret masking - hide sensitive fields
- ð§ Configurable - float tolerance, depth limits, collection caps
- ⥠Fast - optimized for production use
Quick Start
use diff;
use Serialize;
let old = Config ;
let new = Config ;
let d = diff.unwrap;
println!;
Output:
version
- String("1.0")
+ String("1.1")
Installation
Add to your Cargo.toml:
[]
= "0.1"
Examples
Basic Usage
use diff;
use Serialize;
let old = User ;
let new = User ;
let diff = diff.unwrap;
// Check specific changes
assert!;
assert!;
assert!;
Masking Secrets
use ;
let config = new
.mask
.mask;
let diff = diff_with.unwrap;
Float Tolerance
use DiffConfig;
let config = new
.float_tolerance
.default_float_tolerance;
let diff = diff_with.unwrap;
Output Formats
let diff = diff.unwrap;
// Pretty format (human-readable)
println!;
// JSON format
let json = diff.to_json?;
// JSON Patch (RFC 6902)
let patch = diff.to_json_patch?;
// Markdown table (great for PRs)
let markdown = diff.to_markdown?;
JSON Patch Output:
Markdown Output:
| Path | Change | Old Value | New Value |
|---|---|---|---|
| name | Modified | "Alice" | "Alice Smith" |
| Modified | "alice@old.com" | "alice@new.com" |
Use Cases
- Config changes - Track configuration drift
- Audit logs - Record what changed in entities
- API testing - Compare expected vs actual responses
- Migration tools - Validate data transformations
- Database migrations - Verify schema changes
- CI/CD - Detect unintended changes
Advanced Configuration
use DiffConfig;
let config = new
// Ignore specific paths
.ignore
.ignore
// Mask sensitive data
.mask
.mask
// Float comparison tolerance
.float_tolerance
.default_float_tolerance
// Limit depth (prevent stack overflow)
.max_depth
// Limit collection size
.collection_limit;
let diff = diff_with?;
Edge Cases Handled
- Floats: NaN == NaN, -0.0 == +0.0
- Large collections: Automatic elision with configurable limits
- Large byte arrays: Hex previews instead of full dumps
- Deep nesting: Configurable depth limits
- Type mismatches: Clear reporting when types differ
Performance
Diffo is designed for production use:
- O(n) complexity for most operations (n = number of fields)
- Index-based sequence diffing (not LCS, which is O(nÂē))
- Efficient path representation with BTreeMap
- Zero-copy where possible
Typical performance (on modest hardware):
- Small struct (5 fields): ~1-2 Ξs
- Medium struct (50 fields): ~10-20 Ξs
- Large struct (500 fields): ~100-200 Ξs
Comparison with Alternatives
| Feature | diffo | serde-diff | json-diff |
|---|---|---|---|
| Path notation | â | â | â |
| Secret masking | â | â | â |
| JSON Patch (RFC 6902) | â | â | â |
| Float tolerance | â | â | â |
| Works with any Serialize | â | â | JSON only |
| Multiple formatters | â | â | â |
| Collection limits | â | â | â |
Roadmap
v0.2
- LCS-based sequence diffing (patience algorithm)
- Configurable sequence diff strategies
- Custom comparator functions per path
v0.3
- Path interning for performance
- Streaming diff for very large structures
- Diff application (apply changes to produce new value)
v1.0
- Stable API guarantee
- Comprehensive benchmarks vs alternatives
- Performance optimization guide
Contributing
Contributions are welcome! Please open an issue or PR on GitHub.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Built with:
- serde - Serialization framework
- serde-value - Generic value representation