use std::convert::TryFrom;
pub mod oui;
use oui::*;
use serde::{Deserialize, Serialize};
use crate::{checks::data_link::validate_mac_length, errors::data_link::mac_addres::MacParseError};
pub const MAC_LEN: usize = 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct MacAddress(pub [u8; MAC_LEN]);
impl MacAddress {
pub fn display_with_oui(&self) -> String {
match self.get_oui() {
Oui::Unknown => format!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
),
oui => format!(
"{:?}:{:02x}:{:02x}:{:02x}",
oui, self.0[3], self.0[4], self.0[5]
),
}
}
pub fn get_oui(&self) -> Oui {
Oui::from_bytes(&self.0[0..3])
}
}
impl TryFrom<&[u8]> for MacAddress {
type Error = MacParseError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
validate_mac_length(bytes)?;
let mut addr = [0u8; MAC_LEN];
addr.copy_from_slice(bytes);
Ok(Self(addr))
}
}
impl TryFrom<String> for MacAddress {
type Error = MacParseError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let bytes = value
.split(':')
.map(|s| u8::from_str_radix(s, 16).unwrap())
.collect::<Vec<u8>>();
Self::try_from(&bytes[..])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_mac_address_with_known_oui() {
let bytes = [0x2C, 0xFD, 0xA1, 0x3C, 0x4D, 0x5E];
let mac = MacAddress::try_from(&bytes[..]).expect("Conversion should succeed");
assert_eq!(mac.display_with_oui(), "ASUSTek:3c:4d:5e");
}
#[test]
fn display_mac_address_with_unknown_oui() {
let bytes = [0xAA, 0xBB, 0xCC, 0x3C, 0x4D, 0x5E];
let mac = MacAddress::try_from(&bytes[..]).expect("Conversion should succeed");
assert_eq!(mac.display_with_oui(), "aa:bb:cc:3c:4d:5e");
}
#[test]
fn valid_mac_address_conversion() {
let bytes = [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E];
let mac = MacAddress::try_from(&bytes[..]).expect("Conversion should succeed");
assert_eq!(mac, MacAddress([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]));
}
#[test]
fn invalid_mac_address_length() {
let bytes = [0x00, 0x1A, 0x2B, 0x3C, 0x4D];
let result = MacAddress::try_from(&bytes[..]);
assert_eq!(
result,
Err(MacParseError::InvalidLength {
actual: bytes.len()
})
);
}
#[test]
fn display_mac_address_format() {
let mac = MacAddress([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]);
assert_eq!(mac.to_string(), "00:1a:2b:3c:4d:5e");
}
#[test]
fn valid_mac_address_conversion_all_zeros() {
let bytes = [0x00; 6];
let mac = MacAddress::try_from(&bytes[..]).expect("Conversion should succeed");
assert_eq!(mac, MacAddress([0x00; 6]));
}
#[test]
fn invalid_mac_address_format_too_long() {
let bytes = [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F];
let result = MacAddress::try_from(&bytes[..]);
assert_eq!(
result,
Err(MacParseError::InvalidLength {
actual: bytes.len()
})
);
}
}