buddy_up_lib/algorithm/
history.rs1use crate::BuddyError;
2use crate::Person;
3use glob::glob;
4use serde::Deserialize;
5use serde::Serialize;
6use std::collections::HashMap;
7use tracing::debug;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct History {
12 map: HashMap<(usize, usize), usize>,
13 #[serde(skip)]
14 stats: HistoryStats,
15}
16
17impl Default for History {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl History {
24 pub fn from_dir(dir: &str) -> Result<Self, BuddyError> {
28 let mut history = Self::new();
29
30 let pattern = format!("{dir}/*.json");
32 for path in glob(&pattern)? {
33 debug!("Reading history file {path:?}");
34 let pairs = std::fs::read_to_string(path?)?;
35 let pairs: Vec<(Person, Person)> = serde_json::from_str(&pairs)?;
36 let pairs = pairs.iter().map(|p| (p.0.id, p.1.id)).collect();
37 history.stats.files_read += 1;
38 merge(&mut history, &pairs);
39 }
40 history.stats.pairs = history.len();
41 Ok(history)
42 }
43
44 #[allow(dead_code)]
45 fn max_iteration(&self) -> usize {
46 *self.map.values().max().unwrap_or(&0)
47 }
48
49 fn new() -> Self {
50 let scores = HashMap::new();
51 Self {
52 map: scores,
53 stats: HistoryStats::default(),
54 }
55 }
56
57 pub fn stats(&self) -> HistoryStats {
58 self.stats
59 }
60
61 fn insert(&mut self, pair: (usize, usize), iteration: usize) {
62 if self.map.contains_key(&pair) {
66 self.map.insert(pair, iteration);
67 } else {
68 self.map.insert((pair.1, pair.0), iteration);
69 }
70 }
71
72 pub fn len(&self) -> usize {
73 self.map.len()
74 }
75
76 pub fn is_empty(&self) -> bool {
77 self.len() == 0
78 }
79
80 fn contains(&self, pair: &(usize, usize)) -> bool {
81 self.map.contains_key(pair) || self.map.contains_key(&(pair.1, pair.0))
82 }
83
84 pub fn get(&self, pair: (usize, usize)) -> Option<usize> {
85 Some(match self.map.get(&pair) {
86 Some(x) => *x,
87 None => *self.map.get(&(pair.1, pair.0))?,
88 })
89 }
90
91 pub fn min(&self) -> usize {
92 *self.map.values().min().unwrap_or(&0)
93 }
94 pub fn max(&self) -> usize {
95 *self.map.values().max().unwrap_or(&0)
96 }
97}
98
99fn merge(history: &mut History, pairs: &Vec<(usize, usize)>) {
100 for p in pairs {
101 if history.contains(p) {
102 let it = history.get(*p).unwrap();
103
104 history.insert(*p, it + 1);
105 } else {
106 history.insert(*p, 1);
107 }
108 }
109}
110
111#[derive(Debug, Copy, Clone, Default)]
113pub struct HistoryStats {
114 pub files_read: usize,
116
117 pub pairs: usize,
119}
120
121#[cfg(test)]
122mod test {
123 use super::*;
124
125 #[test]
126 fn test_max_iteration_empty_history() {
127 let h = History::new();
128 assert_eq!(h.max_iteration(), 0);
129 }
130 #[test]
131 fn test_max_iteration() {
132 let mut h = History::new();
133 h.insert((1, 2), 4);
134 assert_eq!(h.max_iteration(), 4);
135 }
136
137 #[test]
138 fn test_merge() {
139 let mut h = History::new();
140 let pairs = vec![(1, 2)];
141 merge(&mut h, &pairs);
142 assert_eq!(h.max_iteration(), 1);
143 assert_eq!(h.len(), 1);
144
145 merge(&mut h, &pairs);
148 assert_eq!(h.max_iteration(), 2);
149 assert_eq!(h.len(), 1);
150 }
151
152 #[test]
153 fn test_merge_same() {
154 let mut h = History::new();
155
156 let pairs = vec![(1, 2)];
157 let pairs2 = vec![(2, 1)];
158 merge(&mut h, &pairs);
159 assert_eq!(h.max_iteration(), 1);
160 assert_eq!(h.len(), 1);
161 merge(&mut h, &pairs2);
162 assert_eq!(h.max_iteration(), 2);
163 assert_eq!(h.len(), 1);
164 }
165
166 #[test]
167 fn test_contains_either_order() {
168 let mut h = History::new();
169 let pairs = vec![(1, 2)];
170 merge(&mut h, &pairs);
171 assert_eq!(h.max_iteration(), 1);
172 assert_eq!(h.len(), 1);
173
174 let pair1 = h.contains(&(1, 2));
176 let pair2 = h.contains(&(2, 1));
177 assert!(pair1);
178 assert!(pair2);
179 assert_eq!(h.len(), 1);
180 }
181
182 #[test]
183 fn test_insert_same_pair() {
184 let mut h = History::new();
185 let pair1 = (1, 2);
186 let pair2 = (2, 1);
187 h.insert(pair1, 1);
188 assert_eq!(h.len(), 1);
189 h.insert(pair2, 2);
190 assert_eq!(h.len(), 1);
191 }
192
193 #[test]
194 fn test_get_either_order() {
195 let mut h = History::new();
196 let pairs = vec![(1, 2)];
197 merge(&mut h, &pairs);
198 assert_eq!(h.max_iteration(), 1);
199 assert_eq!(h.len(), 1);
200
201 let pair1 = h.get((1, 2));
203 let pair2 = h.get((2, 1));
204 assert_eq!(pair1, Some(1));
205 assert_eq!(pair2, Some(1));
206 assert_eq!(h.len(), 1);
207 }
208}