nazrin/api/src/net/mac.rs
2023-01-16 20:42:01 -08:00

108 lines
2.5 KiB
Rust

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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for MacAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<usize> 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<Self, Self::Err> {
let octets = s
.split(':')
.map(|s| u8::from_str_radix(s, 16))
.collect::<Result<Vec<u8>, std::num::ParseIntError>>()
.map_err(Error::ParseError)?;
Ok(MacAddr {
octets: octets
.try_into()
.map_err(|v: Vec<u8>| 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<T>(value: T) -> Result<MacAddr, Error>
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
}
}