bluez_async/
macaddress.rs1use std::convert::TryInto;
2use std::fmt::{self, Debug, Display, Formatter, LowerHex, UpperHex};
3use std::str::FromStr;
4use thiserror::Error;
5
6#[derive(Clone, Debug, Error, Eq, PartialEq)]
8#[error("Invalid MAC address '{0}'")]
9pub struct ParseMacAddressError(String);
10
11#[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}