Skip to content

Commit a5f39dd

Browse files
committed
- Make the diff enums drop useless allocations
- Change the API to hand throught serde_jsons Values - Add better README.md - Bump version - Add better docs
1 parent 6e8e451 commit a5f39dd

File tree

7 files changed

+152
-113
lines changed

7 files changed

+152
-113
lines changed

Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
[package]
22
name = "json_diff_ng"
3-
version = "0.6.0-RC2"
3+
version = "0.6.0-RC3"
44
authors = ["ksceriath", "ChrisRega"]
55
edition = "2021"
66
license = "Unlicense"
7-
description = "A small diff tool utility for comparing jsons. Forked from ksceriath and improved for usage as a library and with proper support for array diffs."
7+
description = "A JSON diff library and CLI."
88
readme = "README.md"
99
homepage = "https://github.com/ChrisRega/json-diff"
1010
repository = "https://github.com/ChrisRega/json-diff"
1111
keywords = ["cli", "diff", "json"]
1212
categories = ["command-line-utilities"]
1313

1414
[lib]
15-
name = "json_diff"
15+
name = "json_diff_ng"
1616
path = "src/lib.rs"
1717
crate-type = ["lib"]
1818

1919
[[bin]]
20-
name = "json_diff"
20+
name = "json_diff_ng"
2121
path = "src/main.rs"
2222

2323
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

README.md

+35-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
1-
# json-diff
1+
# json-diff-ng
22

3+
[![Crates.io](https://img.shields.io/crates/d/json_diff_ng?style=flat)](https://crates.io/crates/json_diff_ng)
4+
[![Documentation](https://docs.rs/json_diff_ng/badge.svg)](https://docs.rs/json_diff_ng)
5+
![CI](https://github.com/ChrisRega/json-diff/actions/workflows/rust.yml/badge.svg?branch=master "CI")
6+
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE)
7+
8+
## Contributors:
9+
10+
<a href="https://github.com/ChrisRega/json-diff/graphs/contributors">
11+
<img src="https://contrib.rocks/image?repo=ChrisRega/json-diff" alt="Contributors"/>
12+
</a>
13+
14+
## Library
15+
json_diff_ng can be used to get diffs of json-serializable structures in rust.
16+
17+
### Usage example
18+
```rust
19+
use json_diff::compare_strs;
20+
let data1 = r#"["a",{"c": ["d","f"] },"b"]"#;
21+
let data2 = r#"["b",{"c": ["e","d"] },"a"]"#;
22+
let diffs = compare_strs(data1, data2, true, &[]).unwrap();
23+
assert!(!diffs.is_empty());
24+
let diffs = diffs.unequal_values.get_diffs();
25+
assert_eq!(diffs.len(), 1);
26+
assert_eq!(
27+
diffs.first().unwrap().to_string(),
28+
r#".[0].c.[1].("f" != "e")"#
29+
);
30+
```
31+
32+
See [docs.rs](https://docs.rs/json_diff_ng) for more details.
33+
34+
35+
## CLI
336
json-diff is a command line utility to compare two jsons.
437

538
Input can be fed as inline strings or through files.
@@ -17,9 +50,5 @@ file : read input from json files
1750
direct : read input from command line
1851

1952
### Installation
53+
`$ cargo install json_diff_ng`
2054

21-
Currently, json-diff is available through crates.io (apart from building this repo directly). For crate installation,
22-
* Install cargo, through rustup
23-
`$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
24-
* Install json-diff
25-
`$ cargo install json_diff`

src/ds/key_node.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,27 @@ use serde_json::Value;
55
use crate::enums::{DiffEntry, PathElement};
66

77
#[derive(Debug, PartialEq)]
8-
pub enum TreeNode {
8+
pub enum DiffTreeNode {
99
Null,
1010
Value(Value, Value),
11-
Node(HashMap<String, TreeNode>),
12-
Array(Vec<(usize, TreeNode)>),
11+
Node(HashMap<String, DiffTreeNode>),
12+
Array(Vec<(usize, DiffTreeNode)>),
1313
}
1414

15-
impl TreeNode {
16-
pub fn get_diffs(&self) -> Vec<DiffEntry> {
15+
impl<'a> DiffTreeNode {
16+
pub fn get_diffs(&'a self) -> Vec<DiffEntry<'a>> {
1717
let mut buf = Vec::new();
1818
self.follow_path(&mut buf, &[]);
1919
buf
2020
}
2121

22-
pub fn follow_path(&self, diffs: &mut Vec<DiffEntry>, offset: &[PathElement]) {
22+
pub fn follow_path<'b>(
23+
&'a self,
24+
diffs: &mut Vec<DiffEntry<'a>>,
25+
offset: &'b [PathElement<'a>],
26+
) {
2327
match self {
24-
TreeNode::Null => {
28+
DiffTreeNode::Null => {
2529
let is_map_child = offset
2630
.last()
2731
.map(|o| matches!(o, PathElement::Object(_)))
@@ -33,18 +37,18 @@ impl TreeNode {
3337
});
3438
}
3539
}
36-
TreeNode::Value(l, r) => diffs.push(DiffEntry {
40+
DiffTreeNode::Value(l, r) => diffs.push(DiffEntry {
3741
path: offset.to_vec(),
38-
values: Some((l.to_string(), r.to_string())),
42+
values: Some((l, r)),
3943
}),
40-
TreeNode::Node(o) => {
44+
DiffTreeNode::Node(o) => {
4145
for (k, v) in o {
4246
let mut new_offset = offset.to_vec();
43-
new_offset.push(PathElement::Object(k.clone()));
47+
new_offset.push(PathElement::Object(k));
4448
v.follow_path(diffs, &new_offset);
4549
}
4650
}
47-
TreeNode::Array(v) => {
51+
DiffTreeNode::Array(v) => {
4852
for (l, k) in v {
4953
let mut new_offset = offset.to_vec();
5054
new_offset.push(PathElement::ArrayEntry(*l));

src/ds/mismatch.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
use crate::ds::key_node::TreeNode;
1+
use crate::ds::key_node::DiffTreeNode;
22
use crate::enums::{DiffEntry, DiffType};
33

44
/// Structure holding the differences after a compare operation.
55
/// For more readable access use the [`Mismatch::all_diffs`] method that yields a [`DiffEntry`] per diff.
66
#[derive(Debug, PartialEq)]
77
pub struct Mismatch {
8-
pub left_only: TreeNode,
9-
pub right_only: TreeNode,
10-
pub unequal_values: TreeNode,
8+
pub left_only: DiffTreeNode,
9+
pub right_only: DiffTreeNode,
10+
pub unequal_values: DiffTreeNode,
1111
}
1212

1313
impl Mismatch {
14-
pub fn new(l: TreeNode, r: TreeNode, u: TreeNode) -> Mismatch {
14+
pub fn new(l: DiffTreeNode, r: DiffTreeNode, u: DiffTreeNode) -> Mismatch {
1515
Mismatch {
1616
left_only: l,
1717
right_only: r,
@@ -21,16 +21,16 @@ impl Mismatch {
2121

2222
pub fn empty() -> Self {
2323
Mismatch {
24-
left_only: TreeNode::Null,
25-
unequal_values: TreeNode::Null,
26-
right_only: TreeNode::Null,
24+
left_only: DiffTreeNode::Null,
25+
unequal_values: DiffTreeNode::Null,
26+
right_only: DiffTreeNode::Null,
2727
}
2828
}
2929

3030
pub fn is_empty(&self) -> bool {
31-
self.left_only == TreeNode::Null
32-
&& self.unequal_values == TreeNode::Null
33-
&& self.right_only == TreeNode::Null
31+
self.left_only == DiffTreeNode::Null
32+
&& self.unequal_values == DiffTreeNode::Null
33+
&& self.right_only == DiffTreeNode::Null
3434
}
3535

3636
pub fn all_diffs(&self) -> Vec<(DiffType, DiffEntry)> {

src/enums.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -40,38 +40,38 @@ impl Display for DiffType {
4040
}
4141

4242
#[derive(Clone, Debug, PartialEq, Eq)]
43-
pub enum PathElement {
44-
Object(String),
43+
pub enum PathElement<'a> {
44+
Object(&'a str),
4545
ArrayEntry(usize),
4646
}
4747

48-
impl PathElement {
49-
pub fn resolve<'a>(&self, v: &'a serde_json::Value) -> Option<&'a serde_json::Value> {
48+
impl<'a> PathElement<'a> {
49+
pub fn resolve<'b>(&self, v: &'b serde_json::Value) -> Option<&'b serde_json::Value> {
5050
match self {
5151
PathElement::Object(o) => v.get(o),
5252
PathElement::ArrayEntry(i) => v.get(*i),
5353
}
5454
}
5555

56-
pub fn resolve_mut<'a>(
56+
pub fn resolve_mut<'b>(
5757
&self,
58-
v: &'a mut serde_json::Value,
59-
) -> Option<&'a mut serde_json::Value> {
58+
v: &'b mut serde_json::Value,
59+
) -> Option<&'b mut serde_json::Value> {
6060
match self {
6161
PathElement::Object(o) => v.get_mut(o),
6262
PathElement::ArrayEntry(i) => v.get_mut(*i),
6363
}
6464
}
6565
}
6666

67-
/// Represents a single difference in a JSON file
67+
/// A view on a single end-node of the [`DiffKeyNode`] tree.
6868
#[derive(Clone, Debug, Default, PartialEq, Eq)]
69-
pub struct DiffEntry {
70-
pub path: Vec<PathElement>,
71-
pub values: Option<(String, String)>,
69+
pub struct DiffEntry<'a> {
70+
pub path: Vec<PathElement<'a>>,
71+
pub values: Option<(&'a serde_json::Value, &'a serde_json::Value)>,
7272
}
7373

74-
impl Display for DiffEntry {
74+
impl Display for DiffEntry<'_> {
7575
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
7676
for element in &self.path {
7777
write!(f, ".{element}")?;
@@ -87,7 +87,7 @@ impl Display for DiffEntry {
8787
}
8888
}
8989

90-
impl Display for PathElement {
90+
impl Display for PathElement<'_> {
9191
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
9292
match self {
9393
PathElement::Object(o) => {

src/lib.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! # Library for comparing JSON data structures
22
//! ## Summary
33
//! Main entry points are [`compare_strs`] to compare string slices and [`compare_serde_values`] to compare already parse [`serde_json::Value`]
4-
//! ## Examples:
5-
//! ### Compare string slices:
4+
//! ## Example:
65
//! ```rust
76
//! use json_diff::compare_strs;
87
//! let data1 = r#"["a",{"c": ["d","f"] },"b"]"#;
@@ -17,14 +16,21 @@
1716
//! r#".[0].c.[1].("f" != "e")"#
1817
//! );
1918
//! ```
19+
//! ## How to handle the results
20+
//! Results are returned in a triple of [`DiffTreeNode`] called [`Mismatch`].
21+
//! The triple consists of values only on the left side, values only on the right side and values on both sides that differ.
22+
//! Since tree traversal is not usually what you want to do on client side, [`DiffTreeNode`] offers [`DiffTreeNode::get_diffs`] to retrieve
23+
//! a flat list of [`DiffEntry`] which is more easily usable. The path in the json is collapsed into a vector of [`PathElement`] which can be used to follow the diff.
24+
//! Similarly, all diffs after an operation can be collected using [`Mismatch::all_diffs`].
2025
//!
2126
//!
2227
2328
pub mod ds;
2429

2530
pub mod enums;
2631
pub mod process;
27-
pub use ds::key_node::TreeNode;
32+
pub use ds::key_node::DiffTreeNode;
33+
pub use ds::mismatch::Mismatch;
2834
pub use enums::DiffEntry;
2935
pub use enums::DiffType;
3036
pub use enums::Error;

0 commit comments

Comments
 (0)