smart_keymap/keymap/
distinct_reports.rs

1use core::fmt::Debug;
2
3/// For tracking distinct HID reports from the keymap.
4#[cfg(feature = "std")]
5#[derive(Debug, Clone, Eq)]
6pub struct DistinctReports(Vec<[u8; 8]>);
7
8#[cfg(feature = "std")]
9impl Default for DistinctReports {
10    fn default() -> Self {
11        Self::new()
12    }
13}
14
15#[cfg(feature = "std")]
16impl core::cmp::PartialEq for DistinctReports {
17    fn eq(&self, other: &Self) -> bool {
18        // First element in DistinctReports should be [0; 8].
19        if self.0[0] != other.0[0] {
20            return false;
21        }
22
23        let mut i: usize = 1;
24        let mut j: usize = 1;
25
26        let self_len = self.0.len();
27        let other_len = other.0.len();
28
29        // Compare the rest of the elements.
30        while i < self_len && j < other_len {
31            // Ignore [0; 8] elements.
32            // (The reports are distinct; so, no two elements should be equal)
33            while (i < self_len - 1) && self.0[i] == [0; 8] {
34                i += 1;
35            }
36            while (j < other_len - 1) && other.0[j] == [0; 8] {
37                j += 1;
38            }
39
40            if self.0[i] != other.0[j] {
41                // Special cases
42                //  - comparing "modifier pressed" in two reports, vs one report.
43                //  - comparing "modifier released" in two reports, vs one report.
44                if i > 0
45                    && i < self_len - 1
46                    && self.0[i + 1] == other.0[j]
47                    && ((self.0[i - 1][0] == self.0[i][0] && self.0[i][2..] == self.0[i + 1][2..])
48                        || (self.0[i - 1][2..] == self.0[i][2..]
49                            && self.0[i][0] == self.0[i + 1][0]))
50                {
51                    // self uses two reports for equivalent of one report in other
52                    i += 1;
53                } else if j > 0
54                    && j < other_len - 1
55                    && self.0[i] == other.0[j + 1]
56                    && ((other.0[j - 1][0] == other.0[j][0]
57                        && other.0[j][2..] == other.0[j + 1][2..])
58                        || (other.0[j - 1][2..] == other.0[j][2..]
59                            && other.0[j][0] == other.0[j + 1][0]))
60                {
61                    // other uses two reports for equivalent of one report in self
62                    j += 1;
63                } else {
64                    return false;
65                }
66            }
67
68            i += 1;
69            j += 1;
70        }
71
72        i == self_len && j == other_len
73    }
74}
75
76#[cfg(feature = "std")]
77impl DistinctReports {
78    /// Constructs a new DistinctReports.
79    pub fn new() -> Self {
80        Self(vec![[0; 8]])
81    }
82
83    /// Adds the report to the distinct reports.
84    pub fn update(&mut self, report: [u8; 8]) {
85        match self.0.last() {
86            Some(last_report) if last_report == &report => {}
87            _ => self.0.push(report),
88        }
89    }
90
91    /// Access reports as slice of reports.
92    pub fn reports(&self) -> &[[u8; 8]] {
93        self.0.as_slice()
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_distinct_reports_equal() {
103        // Assemble
104        let lhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x04, 0, 0, 0, 0, 0]]);
105        let rhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x04, 0, 0, 0, 0, 0]]);
106
107        // Act
108
109        // Assert
110        assert!(lhs == rhs);
111    }
112
113    #[test]
114    fn test_distinct_reports_not_equal() {
115        // Assemble
116        let lhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x04, 0, 0, 0, 0, 0]]);
117        let rhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x05, 0, 0, 0, 0, 0]]);
118
119        // Act
120
121        // Assert
122        assert!(lhs != rhs);
123    }
124
125    #[test]
126    fn test_distinct_reports_not_equal_modif() {
127        // Assemble
128        let lhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x04, 0, 0, 0, 0, 0]]);
129        let rhs = DistinctReports(vec![
130            [0, 0, 0, 0, 0, 0, 0, 0],
131            [0x01, 0, 0x04, 0, 0, 0, 0, 0],
132        ]);
133
134        // Act
135
136        // Assert
137        assert!(lhs != rhs);
138    }
139
140    #[test]
141    fn test_distinct_reports_equal_ignores_0_between() {
142        // Assemble
143        let lhs = DistinctReports(vec![
144            [0, 0, 0, 0, 0, 0, 0, 0],
145            [0, 0, 0x04, 0, 0, 0, 0, 0],
146            [0, 0, 0x05, 0, 0, 0, 0, 0],
147        ]);
148        let rhs = DistinctReports(vec![
149            [0, 0, 0, 0, 0, 0, 0, 0],
150            [0, 0, 0x04, 0, 0, 0, 0, 0],
151            [0, 0, 0, 0, 0, 0, 0, 0],
152            [0, 0, 0x05, 0, 0, 0, 0, 0],
153        ]);
154
155        // Act
156
157        // Assert
158        assert!(lhs == rhs);
159    }
160
161    #[test]
162    fn test_distinct_reports_not_equal_respects_trailing_0() {
163        // Assemble
164        let lhs = DistinctReports(vec![
165            [0, 0, 0, 0, 0, 0, 0, 0],
166            [0, 0, 0x04, 0, 0, 0, 0, 0],
167            [0, 0, 0x05, 0, 0, 0, 0, 0],
168            [0, 0, 0, 0, 0, 0, 0, 0],
169        ]);
170        let rhs = DistinctReports(vec![
171            [0, 0, 0, 0, 0, 0, 0, 0],
172            [0, 0, 0x04, 0, 0, 0, 0, 0],
173            [0, 0, 0, 0, 0, 0, 0, 0],
174            [0, 0, 0x05, 0, 0, 0, 0, 0],
175        ]);
176
177        // Act
178
179        // Assert
180        assert!(lhs != rhs);
181    }
182
183    #[test]
184    fn test_distinct_reports_update_ignores_consecutive_duplicate() {
185        // Assemble
186        let lhs = DistinctReports(vec![[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0x04, 0, 0, 0, 0, 0]]);
187
188        // Act
189        let mut rhs = DistinctReports::new();
190        rhs.update([0, 0, 0x04, 0, 0, 0, 0, 0]);
191        rhs.update([0, 0, 0x04, 0, 0, 0, 0, 0]);
192        rhs.update([0, 0, 0x04, 0, 0, 0, 0, 0]);
193
194        // Assert
195        assert!(lhs == rhs);
196    }
197
198    #[test]
199    fn test_distinct_reports_allows_modifier_press_equivalence() {
200        // Assemble
201        let lhs = DistinctReports(vec![
202            [0, 0, 0, 0, 0, 0, 0, 0],
203            [0x01, 0, 0x04, 0, 0, 0, 0, 0],
204        ]);
205        let rhs = DistinctReports(vec![
206            [0, 0, 0, 0, 0, 0, 0, 0],
207            [0x01, 0, 0, 0, 0, 0, 0, 0],
208            [0x01, 0, 0x04, 0, 0, 0, 0, 0],
209        ]);
210
211        // Act
212
213        // Assert
214        assert!(lhs == rhs);
215    }
216
217    #[test]
218    fn test_distinct_reports_allows_modifier_release_equivalence() {
219        // Assemble
220        let lhs = DistinctReports(vec![
221            [0, 0, 0, 0, 0, 0, 0, 0],
222            [0x01, 0, 0x04, 0, 0, 0, 0, 0],
223            [0, 0, 0, 0, 0, 0, 0, 0],
224        ]);
225        let rhs = DistinctReports(vec![
226            [0, 0, 0, 0, 0, 0, 0, 0],
227            [0x01, 0, 0, 0, 0, 0, 0, 0],
228            [0x01, 0, 0x04, 0, 0, 0, 0, 0],
229            [0x01, 0, 0, 0, 0, 0, 0, 0],
230            [0, 0, 0, 0, 0, 0, 0, 0],
231        ]);
232
233        // Act
234
235        // Assert
236        assert!(lhs == rhs);
237    }
238}