fallow_config/config/
entry_effect.rs1use std::sync::{Arc, Mutex};
2
3#[derive(Debug, Clone, Default)]
14pub struct EntryEffectRecord {
15 effective: Arc<Mutex<Option<Vec<bool>>>>,
16}
17
18impl EntryEffectRecord {
19 pub fn record(&self, effective: Vec<bool>) {
22 if let Ok(mut slot) = self.effective.lock() {
23 *slot = Some(effective);
24 }
25 }
26
27 #[must_use]
31 pub fn ineffective<'a>(&self, entries: &'a [String]) -> Vec<&'a str> {
32 let Ok(slot) = self.effective.lock() else {
33 return Vec::new();
34 };
35 let Some(effective) = slot.as_ref() else {
36 return Vec::new();
37 };
38 if effective.len() != entries.len() {
39 return Vec::new();
40 }
41 entries
42 .iter()
43 .zip(effective)
44 .filter(|(_, effective)| !**effective)
45 .map(|(entry, _)| entry.as_str())
46 .collect()
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 fn entries(values: &[&str]) -> Vec<String> {
55 values.iter().map(|value| (*value).to_owned()).collect()
56 }
57
58 #[test]
59 fn no_answer_reports_nothing() {
60 let record = EntryEffectRecord::default();
61 assert!(record.ineffective(&entries(&["a"])).is_empty());
62 }
63
64 #[test]
65 fn the_latest_answer_wins_and_clones_share_it() {
66 let record = EntryEffectRecord::default();
67 let clone = record.clone();
68 let list = entries(&["a", "b", "c"]);
69 clone.record(vec![true, false, false]);
70 assert_eq!(record.ineffective(&list), vec!["b", "c"]);
71 record.record(vec![true, true, false]);
72 assert_eq!(clone.ineffective(&list), vec!["c"]);
73 }
74
75 #[test]
76 fn an_answer_of_another_length_reports_nothing() {
77 let record = EntryEffectRecord::default();
78 record.record(vec![false]);
79 assert!(record.ineffective(&entries(&["a", "b"])).is_empty());
80 }
81}