1const MAGIC: u8 = 0xA0;
7const MAGIC_MASK: u8 = 0xF8;
8const ASLEEP: u8 = 1 << 0;
9const SILENT: u8 = 1 << 1;
10const BATTERY_CRITICAL: u8 = 1 << 2;
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub struct UserPreferences {
14 pub asleep: bool,
15 pub silent: bool,
16 pub battery_critical: bool,
18}
19
20impl UserPreferences {
21 pub const fn try_decode(value: u8) -> Option<Self> {
22 if value & MAGIC_MASK != MAGIC {
23 return None;
24 }
25 Some(Self {
26 asleep: value & ASLEEP != 0,
27 silent: value & SILENT != 0,
28 battery_critical: value & BATTERY_CRITICAL != 0,
29 })
30 }
31
32 pub const fn encode(self) -> u8 {
33 MAGIC
34 | (self.asleep as u8) * ASLEEP
35 | (self.silent as u8) * SILENT
36 | (self.battery_critical as u8) * BATTERY_CRITICAL
37 }
38
39 pub const fn decode(value: u8) -> Self {
40 match Self::try_decode(value) {
41 Some(preferences) => preferences,
42 None => Self {
43 asleep: false,
44 silent: false,
45 battery_critical: false,
46 },
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn every_preference_combination_round_trips() {
57 for asleep in [false, true] {
58 for silent in [false, true] {
59 for battery_critical in [false, true] {
60 let expected = UserPreferences {
61 asleep,
62 silent,
63 battery_critical,
64 };
65 assert_eq!(UserPreferences::decode(expected.encode()), expected);
66 }
67 }
68 }
69 }
70
71 #[test]
72 fn erased_or_foreign_register_defaults_awake_and_noisy() {
73 for value in [0x00, 0x57, 0xff] {
74 assert_eq!(UserPreferences::decode(value), UserPreferences::default());
75 }
76 }
77}