1use std::convert::{TryFrom, TryInto};
4use std::fmt::{self, Debug, Display, Formatter, LowerHex, UpperHex};
5use std::str::FromStr;
6
7#[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub struct BDAddr {
10 address: [u8; 6],
11}
12
13#[derive(Debug, thiserror::Error, Clone, PartialEq)]
15pub enum ParseBDAddrError {
16 #[error("Bluetooth address has to be 6 bytes long")]
17 IncorrectByteCount,
18 #[error("Invalid digit in address: {0}")]
19 InvalidDigit(#[from] std::num::ParseIntError),
20}
21
22impl Display for BDAddr {
23 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
24 <Self as UpperHex>::fmt(self, f)
25 }
26}
27
28impl LowerHex for BDAddr {
29 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
30 let a = &self.address;
31 write!(
32 f,
33 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
34 a[0], a[1], a[2], a[3], a[4], a[5]
35 )
36 }
37}
38
39impl UpperHex for BDAddr {
40 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
41 let a = &self.address;
42 write!(
43 f,
44 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
45 a[0], a[1], a[2], a[3], a[4], a[5]
46 )
47 }
48}
49
50impl Debug for BDAddr {
51 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
52 <Self as Display>::fmt(self, f)
53 }
54}
55
56impl AsRef<[u8]> for BDAddr {
57 fn as_ref(&self) -> &[u8] {
58 &self.address
59 }
60}
61
62impl From<[u8; 6]> for BDAddr {
63 fn from(address: [u8; 6]) -> Self {
75 Self { address }
76 }
77}
78
79impl<'a> TryFrom<&'a [u8]> for BDAddr {
80 type Error = ParseBDAddrError;
81
82 fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
83 Ok(Self {
84 address: slice
85 .try_into()
86 .map_err(|_| ParseBDAddrError::IncorrectByteCount)?,
87 })
88 }
89}
90
91impl TryFrom<u64> for BDAddr {
92 type Error = ParseBDAddrError;
93
94 fn try_from(int: u64) -> Result<Self, Self::Error> {
95 let slice = int.to_be_bytes(); if slice[0..2] == [0, 0] {
97 Ok(Self {
98 address: slice[2..].try_into().unwrap(),
99 })
100 } else {
101 Err(ParseBDAddrError::IncorrectByteCount)
102 }
103 }
104}
105
106impl From<BDAddr> for u64 {
107 fn from(addr: BDAddr) -> Self {
108 let mut slice = [0; 8];
109 slice[2..].copy_from_slice(&addr.into_inner());
110 u64::from_be_bytes(slice)
111 }
112}
113
114impl FromStr for BDAddr {
115 type Err = ParseBDAddrError;
116
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 if s.contains(':') {
123 Self::from_str_delim(s)
124 } else {
125 Self::from_str_no_delim(s)
126 }
127 }
128}
129
130impl BDAddr {
131 pub fn into_inner(self) -> [u8; 6] {
133 self.address
134 }
135
136 pub fn is_random_static(&self) -> bool {
138 self.address[5] & 0b11 == 0b11
139 }
140
141 pub fn from_str_delim(s: &str) -> Result<Self, ParseBDAddrError> {
145 let bytes = s
146 .split(':')
147 .map(|part: &str| u8::from_str_radix(part, 16))
148 .collect::<Result<Vec<u8>, _>>()?;
149
150 if bytes.len() == 6 {
151 let mut address = [0; 6];
152 address.copy_from_slice(bytes.as_slice());
153 Ok(BDAddr { address })
154 } else {
155 Err(ParseBDAddrError::IncorrectByteCount)
156 }
157 }
158
159 pub fn from_str_no_delim(s: &str) -> Result<Self, ParseBDAddrError> {
163 if s.len() != 12 {
164 return Err(ParseBDAddrError::IncorrectByteCount);
165 }
166
167 let mut address = [0; 6];
168 let mut cur = s;
169 for byte in address.iter_mut() {
170 let (part, rest) = cur.split_at(2);
171 *byte = u8::from_str_radix(part, 16)?;
172 cur = rest;
173 }
174 Ok(Self { address })
175 }
176
177 pub fn write_no_delim(&self, f: &mut impl fmt::Write) -> fmt::Result {
179 for b in &self.address {
180 write!(f, "{:02x}", b)?;
181 }
182 Ok(())
183 }
184
185 pub fn to_string_no_delim(&self) -> String {
190 let mut s = String::with_capacity(12);
191 self.write_no_delim(&mut s)
192 .expect("A String-Writer never fails");
193 s
194 }
195}
196
197#[cfg(feature = "serde")]
199pub mod serde {
200 use std::fmt::{self, Write as _};
201
202 use serde::{
203 de::{Deserialize, Deserializer, Error as DeError, Visitor},
204 ser::{Serialize, Serializer},
205 };
206 use serde_cr as serde;
207
208 use super::*;
209
210 impl Serialize for BDAddr {
211 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
212 where
213 S: Serializer,
214 {
215 colon_delim::serialize(self, serializer)
216 }
217 }
218
219 impl<'de> Deserialize<'de> for BDAddr {
220 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
221 where
222 D: Deserializer<'de>,
223 {
224 colon_delim::deserialize(deserializer)
225 }
226 }
227
228 pub mod colon_delim {
251 use super::*;
252
253 struct ColonDelimVisitor;
254
255 pub fn serialize<S>(addr: &BDAddr, serializer: S) -> Result<S::Ok, S::Error>
256 where
257 S: Serializer,
258 {
259 let mut buf = String::with_capacity(17);
260 write!(&mut buf, "{:X}", addr).expect("never fails to write to string");
261 serializer.serialize_str(&buf)
262 }
263
264 pub fn deserialize<'de, D>(d: D) -> Result<BDAddr, D::Error>
265 where
266 D: Deserializer<'de>,
267 {
268 let buf = d.deserialize_str(ColonDelimVisitor)?;
269 BDAddr::from_str_delim(buf).map_err(D::Error::custom)
270 }
271
272 impl<'de> Visitor<'de> for ColonDelimVisitor {
273 type Value = &'de str;
274
275 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
276 write!(
277 formatter,
278 "A colon seperated Bluetooth address, like `00:11:22:33:44:55`"
279 )
280 }
281
282 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
283 where
284 E: DeError,
285 {
286 Ok(v)
287 }
288 }
289 }
290
291 pub mod no_delim {
313 use super::*;
314
315 struct NoDelimVisitor;
316
317 pub fn serialize<S>(addr: &BDAddr, serializer: S) -> Result<S::Ok, S::Error>
318 where
319 S: Serializer,
320 {
321 let mut buf = String::with_capacity(12);
322 addr.write_no_delim(&mut buf)
323 .expect("never fails to write to string");
324 serializer.serialize_str(&buf)
325 }
326
327 pub fn deserialize<'de, D>(d: D) -> Result<BDAddr, D::Error>
328 where
329 D: Deserializer<'de>,
330 {
331 let buf = d.deserialize_str(NoDelimVisitor)?;
332 BDAddr::from_str_no_delim(buf).map_err(D::Error::custom)
333 }
334
335 impl<'de> Visitor<'de> for NoDelimVisitor {
336 type Value = &'de str;
337
338 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
339 write!(
340 formatter,
341 "A Bluetooth address without any delimiters, like `001122334455`"
342 )
343 }
344
345 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
346 where
347 E: DeError,
348 {
349 Ok(v)
350 }
351 }
352 }
353
354 pub mod bytes {
376 use super::*;
377
378 pub fn serialize<S>(addr: &BDAddr, serializer: S) -> Result<S::Ok, S::Error>
379 where
380 S: Serializer,
381 {
382 addr.address.serialize(serializer)
383 }
384
385 pub fn deserialize<'de, D>(d: D) -> Result<BDAddr, D::Error>
386 where
387 D: Deserializer<'de>,
388 {
389 Ok(<[u8; 6]>::deserialize(d)?.into())
390 }
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 const ADDR: BDAddr = BDAddr {
400 address: [0x1f, 0x2a, 0x00, 0xcc, 0x22, 0xf1],
401 };
402 const HEX: u64 = 0x00_00_1f_2a_00_cc_22_f1;
404
405 #[test]
406 fn parse_addr() {
407 let addr = BDAddr::from([0x2a, 0x00, 0xaa, 0xbb, 0xcc, 0xdd]);
408
409 let result: Result<BDAddr, _> = "2a:00:aa:bb:cc:dd".parse();
410 assert_eq!(result, Ok(addr));
411 let result: Result<BDAddr, _> = "2a00AabbCcdd".parse();
412 assert_eq!(result, Ok(addr));
413 let result: Result<BDAddr, _> = "2A:00:00".parse();
414 assert_eq!(result, Err(ParseBDAddrError::IncorrectByteCount));
415 let result: Result<BDAddr, _> = "2A:00:AA:BB:CC:ZZ".parse();
416 assert!(matches!(result, Err(ParseBDAddrError::InvalidDigit(_))));
417 let result: Result<BDAddr, _> = "2A00aABbcCZz".parse();
418 assert!(matches!(result, Err(ParseBDAddrError::InvalidDigit(_))));
419 }
420
421 #[test]
422 fn display_addr() {
423 assert_eq!(format!("{}", ADDR), "1F:2A:00:CC:22:F1");
424 assert_eq!(format!("{:?}", ADDR), "1F:2A:00:CC:22:F1");
425 assert_eq!(format!("{:x}", ADDR), "1f:2a:00:cc:22:f1");
426 assert_eq!(format!("{:X}", ADDR), "1F:2A:00:CC:22:F1");
427 assert_eq!(format!("{}", ADDR.to_string_no_delim()), "1f2a00cc22f1");
428 }
429
430 #[test]
431 fn u64_to_addr() {
432 let hex_addr: BDAddr = HEX.try_into().unwrap();
433 assert_eq!(hex_addr, ADDR);
434
435 let hex_back: u64 = hex_addr.into();
436 assert_eq!(HEX, hex_back);
437 }
438
439 #[test]
440 fn invalid_u64_to_addr() {
441 assert_eq!(
442 BDAddr::try_from(0x1122334455667788),
443 Err(ParseBDAddrError::IncorrectByteCount)
444 );
445 }
446
447 #[test]
448 fn addr_to_u64() {
449 let addr_as_hex: u64 = ADDR.into();
450 assert_eq!(HEX, addr_as_hex);
451
452 let addr_back: BDAddr = addr_as_hex.try_into().unwrap();
453 assert_eq!(ADDR, addr_back);
454 }
455}