1use crc;
2use serde::{de, Deserializer, Serializer};
3use std::fmt;
4
5const CRC_YUBICO: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC);
8
9const MODHEX: [char; 16] = [
10 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v',
11];
12
13pub fn get_crc(bytes: &[u8]) -> u16 {
14 let mut digest = CRC_YUBICO.digest();
15 digest.update(bytes);
16 return digest.finalize();
17}
18
19pub fn to_modkex(bytes: &[u8]) -> String {
20 let mut output = String::with_capacity(bytes.len() * 2);
21 for byte in bytes {
22 output.push(MODHEX[(byte >> 4) as usize]);
23 output.push(MODHEX[(byte & 0xf) as usize]);
24 }
25 output
26}
27
28pub fn serialize_hex<S>(array: &[u8], serializer: S) -> Result<S::Ok, S::Error>
29where
30 S: Serializer,
31{
32 serializer.serialize_str(&hex::encode(array))
33}
34
35pub fn deserialize_hex<'de, D, const N: usize>(deserializer: D) -> Result<[u8; N], D::Error>
36where
37 D: Deserializer<'de>,
38{
39 struct StringVisitor<const M: usize>;
40
41 impl<'de, const M: usize> de::Visitor<'de> for StringVisitor<M> {
42 type Value = [u8; M];
43 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
44 formatter.write_str("a hex string")
45 }
46
47 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
48 where
49 E: de::Error,
50 {
51 let mut output = [0u8; M];
52 hex::decode_to_slice(v, &mut output).map_err(E::custom)?;
53 Ok(output)
54 }
55 }
56 deserializer.deserialize_any(StringVisitor::<N>)
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn crc_check() {
65 assert_eq!(get_crc(b"123456789"), 0x906e)
66 }
67
68 #[test]
69 fn test_modhex() {
70 assert_eq!(to_modkex(&[0xaf, 0x1d, 0xc5]), "lvbtrg")
71 }
72}