net_backend_resources/
mac_address.rs1use inspect::Inspect;
8use mesh::payload::Protobuf;
9use std::fmt::Display;
10use std::str::FromStr;
11use thiserror::Error;
12
13#[derive(Debug, Protobuf, Inspect, Clone, Copy, PartialEq, Eq, Hash)]
15#[mesh(transparent)]
16#[inspect(display)]
17#[repr(transparent)]
18pub struct MacAddress([u8; 6]);
19
20impl MacAddress {
21 pub const fn new(value: [u8; 6]) -> Self {
23 Self(value)
24 }
25
26 pub const fn to_bytes(self) -> [u8; 6] {
28 self.0
29 }
30}
31
32impl From<[u8; 6]> for MacAddress {
33 fn from(value: [u8; 6]) -> Self {
34 Self::new(value)
35 }
36}
37
38impl From<MacAddress> for [u8; 6] {
39 fn from(value: MacAddress) -> Self {
40 value.0
41 }
42}
43
44impl Display for MacAddress {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(
47 f,
48 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
49 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
50 )
51 }
52}
53
54#[derive(Debug, Error)]
56#[error("invalid mac address")]
57pub struct InvalidMacAddress;
58
59impl FromStr for MacAddress {
60 type Err = InvalidMacAddress;
61
62 fn from_str(val: &str) -> Result<Self, InvalidMacAddress> {
63 if val.len() != 17 {
64 return Err(InvalidMacAddress);
65 }
66 let sep = val.as_bytes()[2];
67 if sep != b'-' && sep != b':' {
68 return Err(InvalidMacAddress);
69 }
70 let mut mac_address = [0u8; 6];
71 for (src, dst) in val.split(sep as char).zip(&mut mac_address) {
72 if src.len() != 2 {
73 return Err(InvalidMacAddress);
74 }
75 *dst = u8::from_str_radix(src, 16).map_err(|_| InvalidMacAddress)?;
76 }
77 Ok(MacAddress(mac_address))
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::mac_address::InvalidMacAddress;
84 use crate::mac_address::MacAddress;
85 use std::str::FromStr;
86
87 #[test]
88 fn test_parse_mac_address() {
89 let bad_macs = &[
90 "",
91 "00:00:00-00-00-00",
92 "00:00:00:00:00",
93 "00:00:00:00:00:00:",
94 "00:00:00:00:00:00:00",
95 "00:00:00:00:00::0",
96 "00:00:00:00:00:0g",
97 ];
98 for mac in bad_macs {
99 assert!(matches!(MacAddress::from_str(mac), Err(InvalidMacAddress)));
100 }
101
102 let good_macs = &[
103 ("00:00:00:00:00:00", [0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
104 ("00-00-00-00-00-00", [0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
105 ("ff:ff:ff:ff:ff:ff", [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
106 ("FF:FF:FF:FF:FF:FF", [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
107 ("01:23:45:67:89:ab", [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]),
108 ("01-23-45-67-89-ab", [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]),
109 ];
110 for &(mac, parsed) in good_macs {
111 assert_eq!(MacAddress::from_str(mac).unwrap().to_bytes(), parsed);
112 }
113 }
114}