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 TryFrom<Vec<u8>> for NfcUid {
58 type Error = Error;
59
60 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
61 Self::try_from(&value[..])
62 }
63}
64
65impl FromHex for NfcUid {
66 type Error = FromHexError;
67
68 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
69 let hex_bytes = hex.as_ref();
70 let mut decoded = vec![0u8; hex_bytes.len() / 2];
71 decode_to_slice(hex, &mut decoded)?;
72
73 NfcUid::try_from(decoded.as_slice()).map_err(|_| FromHexError::InvalidStringLength)
74 }
75}
76
77impl NfcUid {
78 pub fn as_bytes(&self) -> &[u8] {
79 match self {
80 NfcUid::Single(data) => data,
81 NfcUid::Double(data) => data,
82 NfcUid::Triple(data) => data,
83 }
84 }
85
86 pub fn to_vec(&self) -> Vec<u8> {
87 self.as_bytes().to_vec()
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use hex::FromHex;
95
96 #[test]
97 fn from_valid_bytes() {
98 let bytes4 = [0x01, 0x02, 0x03, 0x04];
99 let bytes7 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
100 let bytes10 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A];
101
102 let uid4 = NfcUid::try_from(&bytes4[..]).unwrap();
103 let uid7 = NfcUid::try_from(&bytes7[..]).unwrap();
104 let uid10 = NfcUid::try_from(&bytes10[..]).unwrap();
105
106 assert_eq!(uid4.as_bytes(), &bytes4);
107 assert_eq!(uid7.as_bytes(), &bytes7);
108 assert_eq!(uid10.as_bytes(), &bytes10);
109 }
110
111 #[test]
112 fn from_invalid_bytes_length() {
113 let bytes = [0x01, 0x02];
114 let err = NfcUid::try_from(&bytes[..]).unwrap_err();
115 assert!(matches!(err, Error::InvalidLength));
116
117 let bytes = [0u8; 5];
118 let err = NfcUid::try_from(&bytes[..]).unwrap_err();
119 assert!(matches!(err, Error::InvalidLength));
120 }
121
122 #[test]
123 fn from_valid_hex() {
124 let hex4 = "01020304";
125 let hex7 = "01020304050607";
126 let hex10 = "0102030405060708090a";
127
128 let uid4 = NfcUid::from_hex(hex4).unwrap();
129 let uid7 = NfcUid::from_hex(hex7).unwrap();
130 let uid10 = NfcUid::from_hex(hex10).unwrap();
131
132 assert_eq!(uid4.as_bytes(), &[0x01, 0x02, 0x03, 0x04]);
133 assert_eq!(uid7.as_bytes(), &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
134 assert_eq!(
135 uid10.as_bytes(),
136 &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a]
137 );
138 }
139
140 #[test]
141 fn from_invalid_hex_format() {
142 let invalid_hex = "xyz"; assert!(NfcUid::from_hex(invalid_hex).is_err());
144
145 let invalid_length = "010203"; let result = NfcUid::from_hex(invalid_length);
147 assert!(matches!(result, Err(FromHexError::InvalidStringLength)));
148 }
149}