#[cfg(feature = "serde")]
use serde_with::{DeserializeFromStr, SerializeDisplay};
use std::{error::Error, fmt, str::FromStr};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(DeserializeFromStr, SerializeDisplay))]
pub struct Mac(pub [u8; 6]);
#[derive(Debug, PartialEq, Eq)]
pub struct MacParseError;
impl fmt::Display for MacParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid mac address")
}
}
impl Error for MacParseError {}
impl From<u64> for Mac {
fn from(value: u64) -> Self {
let x = value.to_be_bytes();
Self([x[2], x[3], x[4], x[5], x[6], x[7]])
}
}
impl From<Mac> for u64 {
fn from(value: Mac) -> Self {
let b = value.0;
let x = [0, 0, b[0], b[1], b[2], b[3], b[4], b[5]];
u64::from_be_bytes(x)
}
}
impl FromStr for Mac {
type Err = MacParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut mac = [0u8; 6];
let parts = s.chars().filter(|x| *x == ':').count() + 1;
match s.len() {
12 if parts == 1 => {
for i in 0..6 {
let j = i * 2;
let d = &s[j..=(j + 1)];
mac[i] = u8::from_str_radix(d, 16).map_err(|_| MacParseError)?;
}
}
11..=17 if parts == 6 => {
for (i, d) in s.split(':').enumerate() {
mac[i] = u8::from_str_radix(d, 16).map_err(|_| MacParseError)?;
}
}
_ => return Err(MacParseError),
}
Ok(Self(mac))
}
}
impl fmt::Display for Mac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let b = self.0;
write!(
f,
"{:<02X}:{:<02X}:{:<02X}:{:<02X}:{:<02X}:{:<02X}",
b[0], b[1], b[2], b[3], b[4], b[5]
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u64() {
let mac = Mac::from(78187493530);
assert_eq!(mac, Mac([0x00, 0x12, 0x34, 0x56, 0x78, 0x9a]));
assert_eq!(u64::from(mac), 78187493530);
}
#[test]
fn from_str() {
assert_eq!(
Mac::from_str("123456789abc"),
Ok(Mac([0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]))
);
assert_eq!(
Mac::from_str("12:34:56:78:9a:bc"),
Ok(Mac([0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc]))
);
assert_eq!(
Mac::from_str("1:2:3:a:b:c"),
Ok(Mac([0x1, 0x2, 0x3, 0xa, 0xb, 0xc]))
);
assert_eq!(
Mac::from_str("12:3:0:ab:c:0"),
Ok(Mac([0x12, 0x3, 0x0, 0xab, 0xc, 0x0]))
);
assert_eq!(Mac::from_str(""), Err(MacParseError));
}
}