1use core::fmt;
2use core::ops::Sub;
3use core::str::FromStr;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
7
8use crate::OuiDb;
9
10pub const ETHER_ADDR_LEN: usize = 6;
12
13const LOCAL_ADDR_BIT: u8 = 0x02;
14const MULTICAST_ADDR_BIT: u8 = 0x01;
15
16#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
17pub enum ParseMacError {
18 #[error("Invalid length")]
19 InvalidLength,
20 #[error("Invalid digit")]
21 InvalidDigit,
22}
23
24#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[repr(transparent)]
27pub struct MacAddress(pub(crate) [u8; 6]);
28
29impl MacAddress {
30 pub const fn new(mac: [u8; 6]) -> Self {
32 MacAddress(mac)
33 }
34
35 pub const fn new6(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> Self {
37 MacAddress([a, b, c, d, e, f])
38 }
39
40 pub const fn from_slice(mac: &[u8]) -> Result<Self, ParseMacError> {
42 if mac.len() != 6 {
43 return Err(ParseMacError::InvalidLength);
44 }
45 let bytes = [mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]];
46 Ok(MacAddress(bytes))
47 }
48
49 pub const fn zero() -> Self {
51 Self([0; ETHER_ADDR_LEN])
52 }
53
54 pub const fn broadcast() -> Self {
56 Self([0xff; ETHER_ADDR_LEN])
57 }
58
59 pub fn is_zero(&self) -> bool {
61 *self == Self::zero()
62 }
63
64 pub fn is_universal(&self) -> bool {
66 !self.is_local()
67 }
68
69 pub fn is_local(&self) -> bool {
71 (self.0[0] & LOCAL_ADDR_BIT) == LOCAL_ADDR_BIT
72 }
73
74 pub fn is_unicast(&self) -> bool {
76 !self.is_multicast()
77 }
78
79 pub fn is_multicast(&self) -> bool {
81 (self.0[0] & MULTICAST_ADDR_BIT) == MULTICAST_ADDR_BIT
82 }
83
84 pub fn is_broadcast(&self) -> bool {
86 *self == Self::broadcast()
87 }
88
89 pub fn is_virtual_nic(&self) -> bool {
91 crate::OUI_DB
92 .lookup_mac(*self)
93 .map_or(false, |name| OuiDb::is_virtual_nic(name))
94 }
95
96 pub fn oui(&self) -> Option<&'static str> {
98 crate::OUI_DB.lookup_mac(*self)
99 }
100
101 pub fn octets(&self) -> [u8; 6] {
102 self.0
103 }
104
105 pub fn to_u64(&self) -> u64 {
106 ((self.0[0] as u64) << 40)
107 | ((self.0[1] as u64) << 32)
108 | ((self.0[2] as u64) << 24)
109 | ((self.0[3] as u64) << 16)
110 | ((self.0[4] as u64) << 8)
111 | (self.0[5] as u64)
112 }
113}
114
115impl From<[u8; 6]> for MacAddress {
116 fn from(value: [u8; 6]) -> Self {
117 Self(value)
118 }
119}
120
121impl fmt::Debug for MacAddress {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(
124 f,
125 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
126 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
127 )
128 }
129}
130impl fmt::Display for MacAddress {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 write!(
133 f,
134 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
135 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
136 )
137 }
138}
139
140impl Sub for &MacAddress {
141 type Output = i64;
142
143 fn sub(self, rhs: Self) -> Self::Output {
144 let self_val = self.to_u64();
145 let rhs_val = rhs.to_u64();
146 self_val as i64 - rhs_val as i64
147 }
148}
149
150impl Sub for MacAddress {
151 type Output = i64;
152
153 fn sub(self, rhs: Self) -> Self::Output {
154 let self_val = self.to_u64();
155 let rhs_val = rhs.to_u64();
156 self_val as i64 - rhs_val as i64
157 }
158}
159
160impl FromStr for MacAddress {
161 type Err = ParseMacError;
162
163 fn from_str(s: &str) -> Result<Self, Self::Err> {
165 let value = Self::from_str_sep(s, ':');
166 if value.is_ok() {
167 value
168 } else {
169 Self::from_str_sep(s, '-')
170 }
171 }
172}
173
174impl core::convert::TryFrom<&'_ str> for MacAddress {
175 type Error = ParseMacError;
176
177 fn try_from(value: &str) -> Result<Self, Self::Error> {
178 value.parse()
179 }
180}
181
182impl core::convert::TryFrom<&'_ [u8]> for MacAddress {
183 type Error = ParseMacError;
184
185 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
186 Self::from_slice(value)
187 }
188}
189
190#[cfg(feature = "std")]
191impl core::convert::TryFrom<std::borrow::Cow<'_, str>> for MacAddress {
192 type Error = ParseMacError;
193
194 fn try_from(value: std::borrow::Cow<'_, str>) -> Result<Self, Self::Error> {
195 value.parse()
196 }
197}
198
199impl MacAddress {
200 fn from_str_sep(s: &str, separator: char) -> Result<Self, ParseMacError> {
202 let mut parts = [0u8; 6];
203 let splits = s.split(separator);
204 let mut i = 0;
205 for split in splits {
206 if i == 6 {
207 return Err(ParseMacError::InvalidLength);
208 }
209 match u8::from_str_radix(split, 16) {
210 Ok(b) if split.len() != 0 => parts[i] = b,
211 _ => return Err(ParseMacError::InvalidDigit),
212 }
213 i += 1;
214 }
215
216 if i == 6 {
217 Ok(Self(parts))
218 } else {
219 Err(ParseMacError::InvalidLength)
220 }
221 }
222}
223
224#[cfg(feature = "serde")]
225impl Serialize for MacAddress {
226 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
231 if serializer.is_human_readable() {
232 serializer.collect_str(self)
233 } else {
234 serializer.serialize_bytes(&self.0)
235 }
236 }
237}
238
239#[cfg(feature = "serde")]
240impl<'de> Deserialize<'de> for MacAddress {
241 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
247 struct MacAddrVisitor;
248 impl<'de> de::Visitor<'de> for MacAddrVisitor {
249 type Value = MacAddress;
250
251 fn visit_str<E: de::Error>(self, value: &str) -> Result<MacAddress, E> {
252 value.parse().map_err(|err| E::custom(err))
253 }
254
255 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<MacAddress, E> {
256 if v.len() == 6 {
257 Ok(MacAddress::new([v[0], v[1], v[2], v[3], v[4], v[5]]))
258 } else {
259 Err(E::invalid_length(v.len(), &self))
260 }
261 }
262
263 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
264 write!(
265 formatter,
266 "either a string representation of a MAC address or 6-element byte array"
267 )
268 }
269 }
270
271 if deserializer.is_human_readable() {
273 deserializer.deserialize_str(MacAddrVisitor)
274 } else {
275 deserializer.deserialize_bytes(MacAddrVisitor)
276 }
277 }
278}
279
280#[cfg(feature = "pnet")]
281impl From<pnet_base::MacAddr> for MacAddress {
282 fn from(value: pnet_base::MacAddr) -> Self {
283 Self(value.octets())
284 }
285}