bluez_async/
macaddress.rs

1use std::convert::TryInto;
2use std::fmt::{self, Debug, Display, Formatter, LowerHex, UpperHex};
3use std::str::FromStr;
4use thiserror::Error;
5
6/// An error parsing a MAC address from a string.
7#[derive(Clone, Debug, Error, Eq, PartialEq)]
8#[error("Invalid MAC address '{0}'")]
9pub struct ParseMacAddressError(String);
10
11/// MAC address of a Bluetooth device.
12#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
13pub struct MacAddress([u8; 6]);
14
15impl Display for MacAddress {
16    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
17        UpperHex::fmt(self, f)
18    }
19}
20
21impl Debug for MacAddress {
22    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
23        UpperHex::fmt(self, f)
24    }
25}
26
27impl UpperHex for MacAddress {
28    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
29        write!(
30            f,
31            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
32            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
33        )
34    }
35}
36
37impl LowerHex for MacAddress {
38    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
39        write!(
40            f,
41            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
42            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
43        )
44    }
45}
46
47impl FromStr for MacAddress {
48    type Err = ParseMacAddressError;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        Ok(MacAddress(
52            s.split(':')
53                .map(|octet| {
54                    if octet.len() != 2 {
55                        Err(ParseMacAddressError(s.to_string()))
56                    } else {
57                        u8::from_str_radix(octet, 16)
58                            .map_err(|_| ParseMacAddressError(s.to_string()))
59                    }
60                })
61                .collect::<Result<Vec<u8>, _>>()?
62                .try_into()
63                .map_err(|_| ParseMacAddressError(s.to_string()))?,
64        ))
65    }
66}
67
68impl From<[u8; 6]> for MacAddress {
69    fn from(octets: [u8; 6]) -> Self {
70        MacAddress(octets)
71    }
72}
73
74impl From<MacAddress> for [u8; 6] {
75    fn from(mac_address: MacAddress) -> Self {
76        mac_address.0
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn from_str() {
86        assert_eq!(
87            "11:22:33:44:55:66".parse(),
88            Ok(MacAddress([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]))
89        );
90        assert_eq!(
91            "ab:cd:ef:44:55:66".parse(),
92            Ok(MacAddress([0xab, 0xcd, 0xef, 0x44, 0x55, 0x66]))
93        );
94        assert_eq!(
95            "AB:CD:EF:44:55:66".parse(),
96            Ok(MacAddress([0xab, 0xcd, 0xef, 0x44, 0x55, 0x66]))
97        );
98    }
99
100    #[test]
101    fn from_str_invalid() {
102        assert_eq!(
103            MacAddress::from_str(""),
104            Err(ParseMacAddressError("".to_string()))
105        );
106        assert_eq!(
107            MacAddress::from_str("11:22:33:44:55"),
108            Err(ParseMacAddressError("11:22:33:44:55".to_string()))
109        );
110        assert_eq!(
111            MacAddress::from_str("11:22:33:44:55:66:77"),
112            Err(ParseMacAddressError("11:22:33:44:55:66:77".to_string()))
113        );
114        assert_eq!(
115            MacAddress::from_str("11:22:33:44:555:6"),
116            Err(ParseMacAddressError("11:22:33:44:555:6".to_string()))
117        );
118        assert_eq!(
119            MacAddress::from_str("1g:22:33:44:55:66"),
120            Err(ParseMacAddressError("1g:22:33:44:55:66".to_string()))
121        );
122    }
123
124    #[test]
125    fn to_string() {
126        assert_eq!(
127            MacAddress([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]).to_string(),
128            "11:22:33:44:55:66"
129        );
130        assert_eq!(
131            MacAddress([0xab, 0xcd, 0xef, 0x44, 0x55, 0x66]).to_string(),
132            "AB:CD:EF:44:55:66"
133        );
134    }
135
136    #[test]
137    fn format() {
138        let mac_address = MacAddress([0x12, 0x34, 0x56, 0xab, 0xcd, 0xef]);
139
140        assert_eq!(format!("{}", mac_address), "12:34:56:AB:CD:EF");
141        assert_eq!(format!("{:X}", mac_address), "12:34:56:AB:CD:EF");
142        assert_eq!(format!("{:x}", mac_address), "12:34:56:ab:cd:ef");
143    }
144}