epicinium_keycode/
keycode.rs1use crate::base32;
17
18use serde::Deserialize;
19use serde::Deserializer;
20use serde::Serialize;
21use serde::Serializer;
22
23#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
26pub struct Keycode(pub u64);
27
28pub fn keycode(key: u16, data: u64) -> Keycode
33{
34 const BITES: [i8; 12] = [5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0];
39
40 let mut k_bitstring = key as u64;
41 let mut d_bitstring = data;
42 let mut result: u64 = 0;
43 let mut placement_offset = 0;
44
45 for i in (0..12).rev()
47 {
48 let bite = BITES[i];
52 let k_mask = (1u64 << bite) - 1;
53 let d_mask = (1u64 << (5 - bite)) - 1;
54 let k_bits = k_bitstring & k_mask;
55 let d_bits = d_bitstring & d_mask;
56 let r_bits = (k_bits << (5 - bite)) | d_bits;
57 k_bitstring >>= bite;
58 d_bitstring >>= 5 - bite;
59 result |= r_bits << placement_offset;
61 placement_offset += 5;
62 }
63
64 debug_assert!(result < (1 << 60));
65 Keycode(result)
66}
67
68impl std::fmt::Display for Keycode
69{
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
71 {
72 let mut bits: u64 = self.0;
73 let mut word = vec![0u8; 12];
74
75 for i in (0..12).rev()
77 {
78 let nickel = (bits & 0x1F) as u8;
81 bits >>= 5;
82 word[i] = base32::letter_from_nickel(nickel);
84 }
85
86 let x = String::from_utf8(word).unwrap();
87 write!(f, "{}", x)
88 }
89}
90
91impl std::str::FromStr for Keycode
92{
93 type Err = base32::DecodeError;
94
95 fn from_str(s: &str) -> Result<Keycode, base32::DecodeError>
96 {
97 let mut bits: u64 = 0;
98
99 if !s.is_ascii()
100 {
101 return Err(base32::DecodeError::NonAscii {
102 source: s.to_string(),
103 });
104 }
105 else if s.len() < 12
106 {
107 return Err(base32::DecodeError::WordTooShort {
108 source: s.to_string(),
109 min_length_in_bits: 60,
110 });
111 }
112 else if s.len() > 12
113 {
114 return Err(base32::DecodeError::WordTooLong {
115 source: s.to_string(),
116 max_length_in_bits: 60,
117 });
118 }
119
120 for x in s.bytes()
122 {
123 let nickel: u8 = base32::nickel_from_letter(x)?;
124 debug_assert!(nickel <= 31);
125
126 bits <<= 5;
128 bits |= nickel as u64;
129 }
130
131 Ok(Keycode(bits))
132 }
133}
134
135impl Serialize for Keycode
136{
137 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
138 where
139 S: Serializer,
140 {
141 self.to_string().serialize(serializer)
142 }
143}
144
145impl<'de> Deserialize<'de> for Keycode
146{
147 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
148 where
149 D: Deserializer<'de>,
150 {
151 let s = String::deserialize(deserializer)?;
152 std::str::FromStr::from_str(&s).map_err(::serde::de::Error::custom)
153 }
154}
155
156#[cfg(test)]
157mod tests
158{
159 use super::*;
160 use pretty_assertions::assert_eq;
161
162 #[test]
163 fn test_inverse() -> Result<(), base32::DecodeError>
164 {
165 for _ in 0..1000
166 {
167 let key: u16 = rand::random();
168 let data: u64 = rand::random();
169 let keycode = keycode(key, data);
170 let repr = keycode.to_string();
171 let base32_word = base32::encode(&keycode.0.to_be_bytes());
172 assert_eq!(base32_word, format!("0{}", repr));
173 assert_eq!(base32::decode(&base32_word)?, keycode.0.to_be_bytes());
174 let decoded: Keycode = repr.parse()?;
175 assert_eq!(decoded, keycode, "(repr = {})", repr);
176 assert_eq!(decoded.to_string(), repr);
177 }
178 Ok(())
179 }
180
181 #[test]
182 fn test_endianness() -> Result<(), base32::DecodeError>
183 {
184 for _ in 0..1000
185 {
186 let key: u16 = rand::random();
187 let key2: u16 = rand::random();
188 let data: u64 = rand::random();
189 let data2: u64 = rand::random();
190 let keycode1 = keycode(key, data);
191 let keycode_with_key2 = keycode(key2, data);
192 let keycode_with_data2 = keycode(key, data2);
193 let repr1 = keycode1.to_string();
194 let repr_with_key2 = keycode_with_key2.to_string();
195 let repr_with_data2 = keycode_with_data2.to_string();
196 assert_eq!(&repr1[6..12], &repr_with_key2[6..12]);
197 assert_eq!(&repr1[0..1], &repr_with_data2[0..1]);
198 }
199 Ok(())
200 }
201}