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}