1use self::super::super::util::{vec_merge, mul_str};
2use std::collections::BTreeMap;
3
4
5#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
6pub enum CompareResult {
7 FileAdded(String),
8 FileRemoved(String),
9 FileIgnored(String),
10}
11
12#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
13pub enum CompareFileResult {
14 FileMatches(String),
15 FileDiffers {
16 file: String,
17 was_hash: String,
18 new_hash: String,
19 },
20}
21
22#[derive(Debug, Clone, Hash, PartialEq, Eq)]
23pub enum CompareError {
24 HashLengthDiffers {
25 previous_len: usize,
26 current_len: usize,
27 },
28}
29
30
31pub fn compare_hashes(out_file: &str, mut current_hashes: BTreeMap<String, String>, mut loaded_hashes: BTreeMap<String, String>)
33 -> Result<(Vec<CompareResult>, Vec<CompareFileResult>), CompareError> {
34 let current_hashes_value_len = current_hashes.iter().next().unwrap().1.len();
35 let loaded_hashes_value_len = loaded_hashes.iter().next().unwrap().1.len();
36 if current_hashes_value_len != loaded_hashes_value_len {
37 return Err(CompareError::HashLengthDiffers {
38 previous_len: loaded_hashes_value_len,
39 current_len: current_hashes_value_len,
40 });
41 }
42 let placeholder_value = mul_str("-", current_hashes_value_len);
43 let mut file_compare_results = Vec::new();
44
45 current_hashes.remove(out_file);
46 loaded_hashes.remove(out_file);
47
48 let remove_results = process_ignores(|key, _, other| !other.contains_key(key),
49 CompareResult::FileAdded,
50 CompareResult::FileRemoved,
51 &mut current_hashes,
52 &mut loaded_hashes);
53 let ignore_results = process_ignores(|_, value, _| *value == placeholder_value,
54 CompareResult::FileIgnored,
55 CompareResult::FileIgnored,
56 &mut current_hashes,
57 &mut loaded_hashes);
58
59
60 assert_eq!(current_hashes.len(), loaded_hashes.len());
62
63 if !current_hashes.is_empty() {
64 for (key, loaded_value) in loaded_hashes {
65 let current_value = ¤t_hashes[&key];
66 if *current_value == loaded_value {
67 file_compare_results.push(CompareFileResult::FileMatches(key));
68 } else {
69 file_compare_results.push(CompareFileResult::FileDiffers {
70 file: key,
71 was_hash: loaded_value,
72 new_hash: current_value.clone(),
73 });
74 }
75 }
76 }
77
78 Ok((vec_merge(remove_results, ignore_results), file_compare_results))
79}
80
81
82fn process_ignores<F, Rc, Rl>(f: F, cres: Rc, lres: Rl, ch: &mut BTreeMap<String, String>, lh: &mut BTreeMap<String, String>) -> Vec<CompareResult>
83 where F: Fn(&str, &str, &BTreeMap<String, String>) -> bool,
84 Rc: Fn(String) -> CompareResult,
85 Rl: Fn(String) -> CompareResult
86{
87 let mut results = Vec::new();
88 let mut keys_to_remove = Vec::new();
89
90 process_ignores_iter(&f, &cres, ch, lh, &mut keys_to_remove, &mut results);
91 process_ignores_iter(&f, &lres, lh, ch, &mut keys_to_remove, &mut results);
92
93 for key in keys_to_remove {
94 ch.remove(&key);
95 lh.remove(&key);
96 }
97
98 results
99}
100
101fn process_ignores_iter<F, R>(f: &F, res: &R, curr: &BTreeMap<String, String>, other: &BTreeMap<String, String>, keys_to_remove: &mut Vec<String>,
102 results: &mut Vec<CompareResult>)
103 where F: Fn(&str, &str, &BTreeMap<String, String>) -> bool,
104 R: Fn(String) -> CompareResult
105{
106 for (key, value) in curr {
107 if f(key, value, other) {
108 results.push(res(key.clone()));
109 keys_to_remove.push(key.clone());
110 }
111 }
112}