use std::{fmt, str::FromStr}; use serde::{de, Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct MacAddr { octets: [u8; 6], } impl Serialize for MacAddr { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(&self.to_string()) } } impl<'de> Deserialize<'de> for MacAddr { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s: String = Deserialize::deserialize(deserializer)?; MacAddr::from_str(s.as_str()).map_err(de::Error::custom) } } impl std::ops::Index for MacAddr { type Output = u8; fn index(&self, index: usize) -> &Self::Output { &self.octets[index] } } #[derive(Debug)] pub enum Error { ParseError(std::num::ParseIntError), SizeError(usize), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::ParseError(er) => write!(f, "Couldn't parse octets: {}", er), Self::SizeError(sz) => write!(f, "Too many octets; expected 6, string had {}", sz), } } } impl std::error::Error for Error {} impl fmt::Display for MacAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", self.octets.map(|oct| format!("{:02x}", oct)).join(":") ) } } impl FromStr for MacAddr { type Err = Error; fn from_str(s: &str) -> Result { let octets = s .split(':') .map(|s| u8::from_str_radix(s, 16)) .collect::, std::num::ParseIntError>>() .map_err(Error::ParseError)?; Ok(MacAddr { octets: octets .try_into() .map_err(|v: Vec| Error::SizeError(v.len()))?, }) } } impl MacAddr { pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr { MacAddr { octets: [a, b, c, d, e, f], } } pub fn invalid() -> MacAddr { MacAddr { octets: [0u8; 6] } } pub fn from_bytes(value: T) -> Result where T: AsRef<[u8]>, { let slice = value.as_ref(); if slice.len() < 6 { Err(Error::SizeError(slice.len())) } else { Ok(MacAddr { octets: slice[0..6].try_into().unwrap(), }) } } pub fn octets(&self) -> [u8; 6] { self.octets } }