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