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