Skip to content

Commit c0cedba

Browse files
committed
Extract functionality into modules
1 parent 92c2449 commit c0cedba

File tree

6 files changed

+177
-164
lines changed

6 files changed

+177
-164
lines changed

src/constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ impl fmt::Display for Message {
3333

3434
write!(f, "{}", message)
3535
}
36-
}
36+
}

src/ds/key_node.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use colored::*;
2+
use serde_json::Value;
3+
use std::collections::HashMap;
4+
5+
#[derive(Debug, PartialEq)] // TODO check: do we need PartiaEq ?
6+
pub enum KeyNode {
7+
Nil,
8+
Value(Value, Value),
9+
Node(HashMap<String, KeyNode>),
10+
}
11+
12+
impl KeyNode {
13+
pub fn absolute_keys(&self, keys: &mut Vec<String>, key_from_root: Option<String>) {
14+
let val_key = |key: Option<String>| {
15+
key.map(|mut s| {
16+
s.push_str(" ->");
17+
s
18+
})
19+
.unwrap_or(String::new())
20+
};
21+
let nil_key = |key: Option<String>| key.unwrap_or(String::new());
22+
match self {
23+
KeyNode::Nil => keys.push(nil_key(key_from_root)),
24+
KeyNode::Value(a, b) => keys.push(format!(
25+
"{} [ {} :: {} ]",
26+
val_key(key_from_root),
27+
a.to_string().blue().bold(),
28+
b.to_string().cyan().bold()
29+
)),
30+
KeyNode::Node(map) => {
31+
for (key, value) in map {
32+
value.absolute_keys(
33+
keys,
34+
Some(format!("{} {}", val_key(key_from_root.clone()), key)),
35+
)
36+
}
37+
}
38+
}
39+
}
40+
}

src/ds/mismatch.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use crate::ds::key_node::KeyNode;
2+
3+
#[derive(Debug, PartialEq)]
4+
pub struct Mismatch {
5+
pub left_only_keys: KeyNode,
6+
pub right_only_keys: KeyNode,
7+
pub keys_in_both: KeyNode,
8+
}
9+
10+
impl Mismatch {
11+
pub fn new(l: KeyNode, r: KeyNode, u: KeyNode) -> Mismatch {
12+
Mismatch {
13+
left_only_keys: l,
14+
right_only_keys: r,
15+
keys_in_both: u,
16+
}
17+
}
18+
}

src/ds/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod key_node;
2+
pub mod mismatch;

src/main.rs

Lines changed: 12 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
mod constants;
2+
mod ds;
3+
mod process;
4+
15
use colored::*;
6+
use constants::Message;
7+
use ds::key_node::KeyNode;
8+
use ds::mismatch::Mismatch;
29
use serde_json;
3-
use serde_json::Map;
4-
use serde_json::Value;
5-
use std::collections::HashMap;
6-
use std::collections::HashSet;
710
use std::fmt;
811
use std::fs;
9-
use std::process;
12+
use std::process as proc;
1013
use std::str::FromStr;
1114
use structopt::StructOpt;
12-
use constants::Message;
13-
14-
mod constants;
1515

1616
const HELP: &str = r#"
1717
Example:
@@ -59,7 +59,7 @@ struct Cli {
5959

6060
fn error_exit(message: constants::Message) -> ! {
6161
eprintln!("{}", message);
62-
process::exit(1);
62+
proc::exit(1);
6363
}
6464

6565
fn main() {
@@ -130,64 +130,10 @@ fn display_output(result: Mismatch) {
130130
}
131131
}
132132

133-
#[derive(Debug, PartialEq)] // TODO check: do we need PartiaEq ?
134-
enum KeyNode {
135-
Nil,
136-
Value(Value, Value),
137-
Node(HashMap<String, KeyNode>),
138-
}
139-
140-
impl KeyNode {
141-
fn absolute_keys(&self, keys: &mut Vec<String>, key_from_root: Option<String>) {
142-
let val_key = |key: Option<String>| {
143-
key.map(|mut s| {
144-
s.push_str(" ->");
145-
s
146-
})
147-
.unwrap_or(String::new())
148-
};
149-
let nil_key = |key: Option<String>| key.unwrap_or(String::new());
150-
match self {
151-
KeyNode::Nil => keys.push(nil_key(key_from_root)),
152-
KeyNode::Value(a, b) => keys.push(format!(
153-
"{} [ {} :: {} ]",
154-
val_key(key_from_root),
155-
a.to_string().blue().bold(),
156-
b.to_string().cyan().bold()
157-
)),
158-
KeyNode::Node(map) => {
159-
for (key, value) in map {
160-
value.absolute_keys(
161-
keys,
162-
Some(format!("{} {}", val_key(key_from_root.clone()), key)),
163-
)
164-
}
165-
}
166-
}
167-
}
168-
}
169-
170-
#[derive(Debug, PartialEq)]
171-
struct Mismatch {
172-
left_only_keys: KeyNode,
173-
right_only_keys: KeyNode,
174-
keys_in_both: KeyNode,
175-
}
176-
177-
impl Mismatch {
178-
fn new(l: KeyNode, r: KeyNode, u: KeyNode) -> Mismatch {
179-
Mismatch {
180-
left_only_keys: l,
181-
right_only_keys: r,
182-
keys_in_both: u,
183-
}
184-
}
185-
}
186-
187133
fn compare_jsons(a: &str, b: &str) -> Mismatch {
188134
if let Ok(value1) = serde_json::from_str(a) {
189135
if let Ok(value2) = serde_json::from_str(b) {
190-
match_json(&value1, &value2)
136+
process::match_json(&value1, &value2)
191137
} else {
192138
error_exit(Message::JSON2);
193139
}
@@ -196,104 +142,6 @@ fn compare_jsons(a: &str, b: &str) -> Mismatch {
196142
}
197143
}
198144

199-
fn match_json(value1: &Value, value2: &Value) -> Mismatch {
200-
match (value1, value2) {
201-
(Value::Object(a), Value::Object(b)) => {
202-
let (left_only_keys, right_only_keys, intersection_keys) = intersect_maps(&a, &b);
203-
204-
let mut unequal_keys = KeyNode::Nil;
205-
let mut left_only_keys = get_map_of_keys(left_only_keys);
206-
let mut right_only_keys = get_map_of_keys(right_only_keys);
207-
208-
if let Some(intersection_keys) = intersection_keys {
209-
for key in intersection_keys {
210-
let Mismatch {
211-
left_only_keys: l,
212-
right_only_keys: r,
213-
keys_in_both: u,
214-
} = match_json(&a.get(&key).unwrap(), &b.get(&key).unwrap());
215-
left_only_keys = insert_child_key_map(left_only_keys, l, &key);
216-
right_only_keys = insert_child_key_map(right_only_keys, r, &key);
217-
unequal_keys = insert_child_key_map(unequal_keys, u, &key);
218-
}
219-
}
220-
Mismatch::new(left_only_keys, right_only_keys, unequal_keys)
221-
}
222-
(a, b) => {
223-
if a == b {
224-
Mismatch::new(KeyNode::Nil, KeyNode::Nil, KeyNode::Nil)
225-
} else {
226-
Mismatch::new(
227-
KeyNode::Nil,
228-
KeyNode::Nil,
229-
KeyNode::Value(a.clone(), b.clone()),
230-
)
231-
}
232-
}
233-
}
234-
}
235-
236-
fn get_map_of_keys(set: Option<HashSet<String>>) -> KeyNode {
237-
if let Some(set) = set {
238-
KeyNode::Node(
239-
set.iter()
240-
.map(|key| (String::from(key), KeyNode::Nil))
241-
.collect(),
242-
)
243-
} else {
244-
KeyNode::Nil
245-
}
246-
}
247-
248-
fn insert_child_key_map(parent: KeyNode, child: KeyNode, key: &String) -> KeyNode {
249-
if child == KeyNode::Nil {
250-
return parent;
251-
}
252-
if let KeyNode::Node(mut map) = parent {
253-
map.insert(String::from(key), child);
254-
KeyNode::Node(map) // This is weird! I just wanted to return back `parent` here
255-
} else if let KeyNode::Nil = parent {
256-
let mut map = HashMap::new();
257-
map.insert(String::from(key), child);
258-
KeyNode::Node(map)
259-
} else {
260-
parent // TODO Trying to insert child node in a Value variant : Should not happen => Throw an error instead.
261-
}
262-
}
263-
264-
fn intersect_maps(
265-
a: &Map<String, Value>,
266-
b: &Map<String, Value>,
267-
) -> (
268-
Option<HashSet<String>>,
269-
Option<HashSet<String>>,
270-
Option<HashSet<String>>,
271-
) {
272-
let mut intersection = HashSet::new();
273-
let mut left = HashSet::new();
274-
let mut right = HashSet::new();
275-
for a_key in a.keys() {
276-
if b.contains_key(a_key) {
277-
intersection.insert(String::from(a_key));
278-
} else {
279-
left.insert(String::from(a_key));
280-
}
281-
}
282-
for b_key in b.keys() {
283-
if !a.contains_key(b_key) {
284-
right.insert(String::from(b_key));
285-
}
286-
}
287-
let left = if left.len() == 0 { None } else { Some(left) };
288-
let right = if right.len() == 0 { None } else { Some(right) };
289-
let intersection = if intersection.len() == 0 {
290-
None
291-
} else {
292-
Some(intersection)
293-
};
294-
(left, right, intersection)
295-
}
296-
297145
#[cfg(test)]
298146
mod tests {
299147
use super::*;
@@ -331,7 +179,6 @@ mod tests {
331179
}
332180
}"#;
333181

334-
let mismatch = compare_jsons(data1, data2);
335182
let expected_left = KeyNode::Node(hashmap! {
336183
"b".to_string() => KeyNode::Node(hashmap! {
337184
"c".to_string() => KeyNode::Node(hashmap! {
@@ -371,6 +218,8 @@ mod tests {
371218
)
372219
});
373220
let expected = Mismatch::new(expected_left, expected_right, expected_uneq);
221+
222+
let mismatch = compare_jsons(data1, data2);
374223
assert_eq!(mismatch, expected, "Diff was incorrect.");
375224
}
376225

src/process.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use crate::ds::key_node::KeyNode;
2+
use crate::ds::mismatch::Mismatch;
3+
use serde_json::Map;
4+
use serde_json::Value;
5+
use std::collections::HashMap;
6+
use std::collections::HashSet;
7+
8+
pub fn match_json(value1: &Value, value2: &Value) -> Mismatch {
9+
match (value1, value2) {
10+
(Value::Object(a), Value::Object(b)) => {
11+
let (left_only_keys, right_only_keys, intersection_keys) = intersect_maps(&a, &b);
12+
13+
let mut unequal_keys = KeyNode::Nil;
14+
let mut left_only_keys = get_map_of_keys(left_only_keys);
15+
let mut right_only_keys = get_map_of_keys(right_only_keys);
16+
17+
if let Some(intersection_keys) = intersection_keys {
18+
for key in intersection_keys {
19+
let Mismatch {
20+
left_only_keys: l,
21+
right_only_keys: r,
22+
keys_in_both: u,
23+
} = match_json(&a.get(&key).unwrap(), &b.get(&key).unwrap());
24+
left_only_keys = insert_child_key_map(left_only_keys, l, &key);
25+
right_only_keys = insert_child_key_map(right_only_keys, r, &key);
26+
unequal_keys = insert_child_key_map(unequal_keys, u, &key);
27+
}
28+
}
29+
Mismatch::new(left_only_keys, right_only_keys, unequal_keys)
30+
}
31+
(a, b) => {
32+
if a == b {
33+
Mismatch::new(KeyNode::Nil, KeyNode::Nil, KeyNode::Nil)
34+
} else {
35+
Mismatch::new(
36+
KeyNode::Nil,
37+
KeyNode::Nil,
38+
KeyNode::Value(a.clone(), b.clone()),
39+
)
40+
}
41+
}
42+
}
43+
}
44+
45+
fn get_map_of_keys(set: Option<HashSet<String>>) -> KeyNode {
46+
if let Some(set) = set {
47+
KeyNode::Node(
48+
set.iter()
49+
.map(|key| (String::from(key), KeyNode::Nil))
50+
.collect(),
51+
)
52+
} else {
53+
KeyNode::Nil
54+
}
55+
}
56+
57+
fn insert_child_key_map(parent: KeyNode, child: KeyNode, key: &String) -> KeyNode {
58+
if child == KeyNode::Nil {
59+
return parent;
60+
}
61+
if let KeyNode::Node(mut map) = parent {
62+
map.insert(String::from(key), child);
63+
KeyNode::Node(map) // This is weird! I just wanted to return back `parent` here
64+
} else if let KeyNode::Nil = parent {
65+
let mut map = HashMap::new();
66+
map.insert(String::from(key), child);
67+
KeyNode::Node(map)
68+
} else {
69+
parent // TODO Trying to insert child node in a Value variant : Should not happen => Throw an error instead.
70+
}
71+
}
72+
73+
fn intersect_maps(
74+
a: &Map<String, Value>,
75+
b: &Map<String, Value>,
76+
) -> (
77+
Option<HashSet<String>>,
78+
Option<HashSet<String>>,
79+
Option<HashSet<String>>,
80+
) {
81+
let mut intersection = HashSet::new();
82+
let mut left = HashSet::new();
83+
let mut right = HashSet::new();
84+
for a_key in a.keys() {
85+
if b.contains_key(a_key) {
86+
intersection.insert(String::from(a_key));
87+
} else {
88+
left.insert(String::from(a_key));
89+
}
90+
}
91+
for b_key in b.keys() {
92+
if !a.contains_key(b_key) {
93+
right.insert(String::from(b_key));
94+
}
95+
}
96+
let left = if left.len() == 0 { None } else { Some(left) };
97+
let right = if right.len() == 0 { None } else { Some(right) };
98+
let intersection = if intersection.len() == 0 {
99+
None
100+
} else {
101+
Some(intersection)
102+
};
103+
(left, right, intersection)
104+
}

0 commit comments

Comments
 (0)