use core::fmt;
use core::ops::Sub;
use core::str::FromStr;
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
pub const ETHER_ADDR_LEN: usize = 6;
const LOCAL_ADDR_BIT: u8 = 0x02;
const MULTICAST_ADDR_BIT: u8 = 0x01;
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
pub enum ParseMacError {
#[error("Invalid length")]
InvalidLength,
#[error("Invalid digit")]
InvalidDigit,
}
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct MacAddress(pub(crate) [u8; 6]);
impl MacAddress {
pub const fn new(mac: [u8; 6]) -> Self {
MacAddress(mac)
}
pub const fn new6(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> Self {
MacAddress([a, b, c, d, e, f])
}
pub const fn from_slice(mac: &[u8]) -> Result<Self, ParseMacError> {
if mac.len() != 6 {
return Err(ParseMacError::InvalidLength);
}
let bytes = [mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]];
Ok(MacAddress(bytes))
}
pub fn zero() -> Self {
Default::default()
}
pub fn broadcast() -> Self {
[0xff; ETHER_ADDR_LEN].into()
}
pub fn is_zero(&self) -> bool {
*self == Self::zero()
}
pub fn is_universal(&self) -> bool {
!self.is_local()
}
pub fn is_local(&self) -> bool {
(self.0[0] & LOCAL_ADDR_BIT) == LOCAL_ADDR_BIT
}
pub fn is_unicast(&self) -> bool {
!self.is_multicast()
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & MULTICAST_ADDR_BIT) == MULTICAST_ADDR_BIT
}
pub fn is_broadcast(&self) -> bool {
*self == Self::broadcast()
}
pub fn octets(&self) -> [u8; 6] {
self.0
}
}
impl From<[u8; 6]> for MacAddress {
fn from(value: [u8; 6]) -> Self {
Self(value)
}
}
impl fmt::Debug for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
impl fmt::Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
impl Sub for &MacAddress {
type Output = i64;
fn sub(self, rhs: Self) -> Self::Output {
let self_val = ((self.0[0] as u64) << 40)
| ((self.0[1] as u64) << 32)
| ((self.0[2] as u64) << 24)
| ((self.0[3] as u64) << 16)
| ((self.0[4] as u64) << 8)
| (self.0[5] as u64);
let rhs_val = ((rhs.0[0] as u64) << 40)
| ((rhs.0[1] as u64) << 32)
| ((rhs.0[2] as u64) << 24)
| ((rhs.0[3] as u64) << 16)
| ((rhs.0[4] as u64) << 8)
| (rhs.0[5] as u64);
self_val as i64 - rhs_val as i64
}
}
impl FromStr for MacAddress {
type Err = ParseMacError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = Self::from_str_sep(s, ':');
if value.is_ok() {
value
} else {
Self::from_str_sep(s, '-')
}
}
}
impl MacAddress {
fn from_str_sep(s: &str, separator: char) -> Result<Self, ParseMacError> {
let mut parts = [0u8; 6];
let splits = s.split(separator);
let mut i = 0;
for split in splits {
if i == 6 {
return Err(ParseMacError::InvalidLength);
}
match u8::from_str_radix(split, 16) {
Ok(b) if split.len() != 0 => parts[i] = b,
_ => return Err(ParseMacError::InvalidDigit),
}
i += 1;
}
if i == 6 {
Ok(Self(parts))
} else {
Err(ParseMacError::InvalidLength)
}
}
}
#[cfg(feature = "serde")]
impl Serialize for MacAddress {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
serializer.collect_str(self)
} else {
serializer.serialize_bytes(&self.0)
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for MacAddress {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct MacAddrVisitor;
impl<'de> de::Visitor<'de> for MacAddrVisitor {
type Value = MacAddress;
fn visit_str<E: de::Error>(self, value: &str) -> Result<MacAddress, E> {
value.parse().map_err(|err| E::custom(err))
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<MacAddress, E> {
if v.len() == 6 {
Ok(MacAddress::new([v[0], v[1], v[2], v[3], v[4], v[5]]))
} else {
Err(E::invalid_length(v.len(), &self))
}
}
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"either a string representation of a MAC address or 6-element byte array"
)
}
}
if deserializer.is_human_readable() {
deserializer.deserialize_str(MacAddrVisitor)
} else {
deserializer.deserialize_bytes(MacAddrVisitor)
}
}
}
#[cfg(feature = "pnet")]
impl From<pnet_base::MacAddr> for MacAddress {
fn from(value: pnet_base::MacAddr) -> Self {
Self(value.octets())
}
}