bloop_server_framework/
nfc_uid.rs1use hex::{FromHex, FromHexError, decode_to_slice};
2use thiserror::Error;
3
4#[derive(Debug, Error)]
5pub enum Error {
6 #[error("Invalid UID length, must be 4, 7 or 10")]
7 InvalidLength,
8}
9
10#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
32pub enum NfcUid {
33 Single([u8; 4]),
34 Double([u8; 7]),
35 Triple([u8; 10]),
36}
37
38impl Default for NfcUid {
39 fn default() -> Self {
40 Self::Single(Default::default())
41 }
42}
43
44impl TryFrom<&[u8]> for NfcUid {
45 type Error = Error;
46
47 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
48 match value.len() {
49 4 => Ok(NfcUid::Single(value.try_into().unwrap())),
50 7 => Ok(NfcUid::Double(value.try_into().unwrap())),
51 10 => Ok(NfcUid::Triple(value.try_into().unwrap())),
52 _ => Err(Error::InvalidLength),
53 }
54 }
55}
56
57impl FromHex for NfcUid {
58 type Error = FromHexError;
59
60 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
61 let hex_bytes = hex.as_ref();
62 let mut decoded = vec![0u8; hex_bytes.len() / 2];
63 decode_to_slice(hex, &mut decoded)?;
64
65 NfcUid::try_from(decoded.as_slice()).map_err(|_| FromHexError::InvalidStringLength)
66 }
67}
68
69impl NfcUid {
70 pub fn as_bytes(&self) -> &[u8] {
71 match self {
72 NfcUid::Single(data) => data,
73 NfcUid::Double(data) => data,
74 NfcUid::Triple(data) => data,
75 }
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use hex::FromHex;
83
84 #[test]
85 fn from_valid_bytes() {
86 let bytes4 = [0x01, 0x02, 0x03, 0x04];
87 let bytes7 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
88 let bytes10 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A];
89
90 let uid4 = NfcUid::try_from(&bytes4[..]).unwrap();
91 let uid7 = NfcUid::try_from(&bytes7[..]).unwrap();
92 let uid10 = NfcUid::try_from(&bytes10[..]).unwrap();
93
94 assert_eq!(uid4.as_bytes(), &bytes4);
95 assert_eq!(uid7.as_bytes(), &bytes7);
96 assert_eq!(uid10.as_bytes(), &bytes10);
97 }
98
99 #[test]
100 fn from_invalid_bytes_length() {
101 let bytes = [0x01, 0x02];
102 let err = NfcUid::try_from(&bytes[..]).unwrap_err();
103 assert!(matches!(err, Error::InvalidLength));
104
105 let bytes = [0u8; 5];
106 let err = NfcUid::try_from(&bytes[..]).unwrap_err();
107 assert!(matches!(err, Error::InvalidLength));
108 }
109
110 #[test]
111 fn from_valid_hex() {
112 let hex4 = "01020304";
113 let hex7 = "01020304050607";
114 let hex10 = "0102030405060708090a";
115
116 let uid4 = NfcUid::from_hex(hex4).unwrap();
117 let uid7 = NfcUid::from_hex(hex7).unwrap();
118 let uid10 = NfcUid::from_hex(hex10).unwrap();
119
120 assert_eq!(uid4.as_bytes(), &[0x01, 0x02, 0x03, 0x04]);
121 assert_eq!(uid7.as_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
122 assert_eq!(
123 uid10.as_bytes(),
124 &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a]
125 );
126 }
127
128 #[test]
129 fn from_invalid_hex_format() {
130 let invalid_hex = "xyz"; assert!(NfcUid::from_hex(invalid_hex).is_err());
132
133 let invalid_length = "010203"; let result = NfcUid::from_hex(invalid_length);
135 assert!(matches!(result, Err(FromHexError::InvalidStringLength)));
136 }
137}