1#[cfg(all(not(feature = "std"), feature = "alloc"))]
2extern crate alloc;
3
4#[cfg(all(not(feature = "std"), feature = "alloc"))]
5use alloc::format;
6
7use crate::addr::MacAddr;
8use crate::error::ParseMacAddrError;
9use core::fmt;
10use core::str::FromStr; #[cfg(feature = "serde")]
13use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
14
15#[cfg(all(feature = "alloc", not(feature = "std")))]
16use alloc as alloc_mod;
17#[cfg(feature = "std")]
18use std as alloc_mod;
19
20#[cfg(any(feature = "std", feature = "alloc"))]
21use alloc_mod::string::String;
22
23#[repr(C)]
25#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default, Debug)]
26pub struct MacAddr8(
27 pub u8,
28 pub u8,
29 pub u8,
30 pub u8,
31 pub u8,
32 pub u8,
33 pub u8,
34 pub u8,
35);
36
37impl MacAddr8 {
38 #[inline]
40 pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) -> MacAddr8 {
41 MacAddr8(a, b, c, d, e, f, g, h)
42 }
43
44 #[inline]
46 pub fn from_octets(octets: [u8; 8]) -> MacAddr8 {
47 MacAddr8(
48 octets[0], octets[1], octets[2], octets[3], octets[4], octets[5], octets[6], octets[7],
49 )
50 }
51
52 #[inline]
54 pub fn octets(&self) -> [u8; 8] {
55 [
56 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7,
57 ]
58 }
59
60 #[cfg(any(feature = "std", feature = "alloc"))]
62 #[inline]
63 pub fn address(&self) -> String {
64 format!(
65 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
66 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7
67 )
68 }
69
70 #[inline]
72 pub fn is_multicast(&self) -> bool {
73 self.0 & 0x01 == 0x01
74 }
75
76 #[inline]
78 pub fn is_unicast(&self) -> bool {
79 !self.is_multicast()
80 }
81
82 #[inline]
84 pub fn is_locally_administered(&self) -> bool {
85 self.0 & 0x02 == 0x02
86 }
87
88 #[inline]
90 pub fn is_universal(&self) -> bool {
91 !self.is_locally_administered()
92 }
93
94 #[inline]
96 pub fn oui(&self) -> [u8; 3] {
97 [self.0, self.1, self.2]
98 }
99
100 #[inline]
103 pub fn from_eui48(mac: MacAddr) -> MacAddr8 {
104 let [a, b, c, d, e, f] = mac.octets();
105 MacAddr8(a, b, c, 0xff, 0xfe, d, e, f)
106 }
107
108 #[inline]
110 pub fn to_eui48(&self) -> Option<MacAddr> {
111 if self.3 == 0xff && self.4 == 0xfe {
112 Some(MacAddr::new(self.0, self.1, self.2, self.5, self.6, self.7))
113 } else {
114 None
115 }
116 }
117}
118
119impl fmt::Display for MacAddr8 {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 let _ = write!(
123 f,
124 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
125 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7
126 );
127 Ok(())
128 }
129}
130
131impl fmt::LowerHex for MacAddr8 {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 write!(
134 f,
135 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
136 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7
137 )
138 }
139}
140
141impl fmt::UpperHex for MacAddr8 {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(
144 f,
145 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
146 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7
147 )
148 }
149}
150
151impl FromStr for MacAddr8 {
152 type Err = ParseMacAddrError;
153
154 fn from_str(s: &str) -> Result<MacAddr8, ParseMacAddrError> {
155 let mut parts = [0u8; 8];
156 let mut i = 0;
157 for split in s.split(':') {
158 if i == 8 {
159 return Err(ParseMacAddrError::TooManyComponents);
160 }
161 match u8::from_str_radix(split, 16) {
162 Ok(b) if !split.is_empty() => parts[i] = b,
163 _ => return Err(ParseMacAddrError::InvalidComponent),
164 }
165 i += 1;
166 }
167 if i == 8 {
168 Ok(MacAddr8(
169 parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7],
170 ))
171 } else {
172 Err(ParseMacAddrError::TooFewComponents)
173 }
174 }
175}
176
177#[cfg(feature = "serde")]
178impl Serialize for MacAddr8 {
179 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
180 if serializer.is_human_readable() {
181 serializer.collect_str(self)
182 } else {
183 serializer.serialize_bytes(&[
184 self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7,
185 ])
186 }
187 }
188}
189
190#[cfg(feature = "serde")]
191impl<'de> Deserialize<'de> for MacAddr8 {
192 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
193 struct MacAddr8Visitor;
194 impl<'de> de::Visitor<'de> for MacAddr8Visitor {
195 type Value = MacAddr8;
196
197 fn visit_str<E: de::Error>(self, value: &str) -> Result<MacAddr8, E> {
198 value.parse().map_err(E::custom)
199 }
200 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<MacAddr8, E> {
201 if v.len() == 8 {
202 Ok(MacAddr8::new(
203 v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],
204 ))
205 } else {
206 Err(E::invalid_length(v.len(), &self))
207 }
208 }
209 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
210 f.write_str("either a string EUI-64 address or 8-byte array")
211 }
212 }
213
214 if deserializer.is_human_readable() {
215 deserializer.deserialize_str(MacAddr8Visitor)
216 } else {
217 deserializer.deserialize_bytes(MacAddr8Visitor)
218 }
219 }
220}
221
222impl From<[u8; 8]> for MacAddr8 {
223 #[inline]
224 fn from(v: [u8; 8]) -> Self {
225 MacAddr8::from_octets(v)
226 }
227}
228
229impl From<MacAddr8> for [u8; 8] {
230 #[inline]
231 fn from(m: MacAddr8) -> Self {
232 m.octets()
233 }
234}
235
236impl TryFrom<&[u8]> for MacAddr8 {
237 type Error = ();
238
239 #[inline]
240 fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
241 if s.len() == 8 {
242 Ok(MacAddr8::new(
243 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],
244 ))
245 } else {
246 Err(())
247 }
248 }
249}
250
251impl AsRef<[u8; 8]> for MacAddr8 {
252 #[inline]
256 fn as_ref(&self) -> &[u8; 8] {
257 unsafe { &*(self as *const MacAddr8 as *const [u8; 8]) }
258 }
259}