pacsea/ui/helpers/logging.rs
1/// What: Track the last logged state to avoid repeating identical debug lines.
2///
3/// Inputs:
4/// - `T`: A clonable, comparable state type to track between log attempts.
5///
6/// Output:
7/// - `ChangeLogger`: Helper that indicates whether a new log should be emitted.
8///
9/// Details:
10/// - Calling `should_log` updates the cached state and returns `true` only when
11/// the provided state differs from the previous one.
12/// - `clear` resets the cached state, forcing the next call to log.
13pub struct ChangeLogger<T> {
14 /// Last logged state value.
15 last: Option<T>,
16}
17
18impl<T: PartialEq + Clone> Default for ChangeLogger<T> {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl<T: PartialEq + Clone> ChangeLogger<T> {
25 /// What: Create a new `ChangeLogger` with no cached state.
26 ///
27 /// Inputs:
28 /// - None
29 ///
30 /// Output:
31 /// - A `ChangeLogger` ready to track state changes.
32 ///
33 /// Details:
34 /// - The first call to `should_log` after construction will return `true`.
35 #[must_use]
36 pub const fn new() -> Self {
37 Self { last: None }
38 }
39
40 /// What: Decide whether a log should be emitted for the provided state.
41 ///
42 /// Inputs:
43 /// - `next`: The next state to compare against the cached state.
44 ///
45 /// Output:
46 /// - `true` when the state differs from the cached value; otherwise `false`.
47 ///
48 /// Details:
49 /// - Updates the cached state when it changes.
50 #[must_use]
51 pub fn should_log(&mut self, next: &T) -> bool {
52 if self.last.as_ref() == Some(next) {
53 return false;
54 }
55 self.last = Some(next.clone());
56 true
57 }
58
59 /// What: Reset the cached state so the next call logs.
60 ///
61 /// Inputs:
62 /// - None
63 ///
64 /// Output:
65 /// - None
66 ///
67 /// Details:
68 /// - Useful for tests or after major UI transitions.
69 pub fn clear(&mut self) {
70 self.last = None;
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::ChangeLogger;
77
78 #[test]
79 /// What: Ensure `ChangeLogger` only triggers when state changes.
80 ///
81 /// Inputs:
82 /// - Sequence of repeated and differing states.
83 ///
84 /// Output:
85 /// - Boolean results from `should_log` reflecting change detection.
86 ///
87 /// Details:
88 /// - First call logs, repeat skips, new value logs, clear resets behavior.
89 fn change_logger_emits_only_on_change() {
90 let mut logger = ChangeLogger::new();
91 assert!(logger.should_log(&"a"));
92 assert!(!logger.should_log(&"a"));
93 assert!(logger.should_log(&"b"));
94 assert!(!logger.should_log(&"b"));
95 logger.clear();
96 assert!(logger.should_log(&"b"));
97 }
98}