use super::ValidationError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacAddr {
octets: [u8; 6],
}
impl MacAddr {
pub fn new(octets: [u8; 6]) -> Self {
Self { octets }
}
pub fn octets(&self) -> [u8; 6] {
self.octets
}
pub fn is_unicast(&self) -> bool {
(self.octets[0] & 0x01) == 0
}
pub fn is_multicast(&self) -> bool {
(self.octets[0] & 0x01) == 1
}
pub fn is_universal(&self) -> bool {
(self.octets[0] & 0x02) == 0
}
pub fn is_local(&self) -> bool {
(self.octets[0] & 0x02) == 2
}
pub fn is_broadcast(&self) -> bool {
self.octets == [0xFF; 6]
}
pub fn is_null(&self) -> bool {
self.octets == [0x00; 6]
}
}
pub fn is_unicast(octets: &[u8; 6]) -> bool {
(octets[0] & 0x01) == 0
}
pub fn is_multicast(octets: &[u8; 6]) -> bool {
(octets[0] & 0x01) == 1
}
pub fn is_universal(octets: &[u8; 6]) -> bool {
(octets[0] & 0x02) == 0
}
pub fn is_local(octets: &[u8; 6]) -> bool {
(octets[0] & 0x02) == 2
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacUnicast(MacAddr);
impl MacUnicast {
pub fn new(octets: [u8; 6]) -> Result<Self, ValidationError> {
let mac = MacAddr::new(octets);
if mac.is_unicast() {
Ok(Self(mac))
} else {
Err(ValidationError::NotUnicastMac)
}
}
pub fn get(&self) -> &MacAddr {
&self.0
}
pub fn octets(&self) -> [u8; 6] {
self.0.octets()
}
pub fn into_inner(self) -> MacAddr {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacMulticast(MacAddr);
impl MacMulticast {
pub fn new(octets: [u8; 6]) -> Result<Self, ValidationError> {
let mac = MacAddr::new(octets);
if mac.is_multicast() {
Ok(Self(mac))
} else {
Err(ValidationError::NotMulticastMac)
}
}
pub fn get(&self) -> &MacAddr {
&self.0
}
pub fn octets(&self) -> [u8; 6] {
self.0.octets()
}
pub fn into_inner(self) -> MacAddr {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacUniversal(MacAddr);
impl MacUniversal {
pub fn new(octets: [u8; 6]) -> Result<Self, ValidationError> {
let mac = MacAddr::new(octets);
if mac.is_universal() {
Ok(Self(mac))
} else {
Err(ValidationError::NotUniversalMac)
}
}
pub fn get(&self) -> &MacAddr {
&self.0
}
pub fn octets(&self) -> [u8; 6] {
self.0.octets()
}
pub fn into_inner(self) -> MacAddr {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacLocal(MacAddr);
impl MacLocal {
pub fn new(octets: [u8; 6]) -> Result<Self, ValidationError> {
let mac = MacAddr::new(octets);
if mac.is_local() {
Ok(Self(mac))
} else {
Err(ValidationError::NotLocalMac)
}
}
pub fn get(&self) -> &MacAddr {
&self.0
}
pub fn octets(&self) -> [u8; 6] {
self.0.octets()
}
pub fn into_inner(self) -> MacAddr {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_unicast_detection() {
let unicast = [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E];
assert!(is_unicast(&unicast));
assert!(!is_multicast(&unicast));
let mac = MacAddr::new(unicast);
assert!(mac.is_unicast());
assert!(!mac.is_multicast());
let unicast_type = MacUnicast::new(unicast);
assert!(unicast_type.is_ok());
}
#[test]
fn test_multicast_detection() {
let multicast = [0x01, 0x00, 0x5E, 0x00, 0x00, 0x01];
assert!(is_multicast(&multicast));
assert!(!is_unicast(&multicast));
let mac = MacAddr::new(multicast);
assert!(mac.is_multicast());
assert!(!mac.is_unicast());
let multicast_type = MacMulticast::new(multicast);
assert!(multicast_type.is_ok());
}
#[test]
fn test_broadcast() {
let broadcast = [0xFF; 6];
let mac = MacAddr::new(broadcast);
assert!(mac.is_broadcast());
assert!(mac.is_multicast()); }
#[test]
fn test_null_address() {
let null = [0x00; 6];
let mac = MacAddr::new(null);
assert!(mac.is_null());
assert!(mac.is_unicast()); }
#[test]
fn test_universal_detection() {
let universal = [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E];
assert!(is_universal(&universal));
assert!(!is_local(&universal));
let mac = MacAddr::new(universal);
assert!(mac.is_universal());
assert!(!mac.is_local());
let universal_type = MacUniversal::new(universal);
assert!(universal_type.is_ok());
}
#[test]
fn test_local_detection() {
let local = [0x02, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E];
assert!(is_local(&local));
assert!(!is_universal(&local));
let mac = MacAddr::new(local);
assert!(mac.is_local());
assert!(!mac.is_universal());
let local_type = MacLocal::new(local);
assert!(local_type.is_ok());
}
#[test]
fn test_unicast_rejects_multicast() {
let multicast = [0x01, 0x00, 0x5E, 0x00, 0x00, 0x01];
let result = MacUnicast::new(multicast);
assert!(result.is_err());
}
#[test]
fn test_multicast_rejects_unicast() {
let unicast = [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E];
let result = MacMulticast::new(unicast);
assert!(result.is_err());
}
#[test]
fn test_combined_bits() {
let local_multicast = [0x03, 0x00, 0x00, 0x00, 0x00, 0x01];
let mac = MacAddr::new(local_multicast);
assert!(mac.is_multicast());
assert!(mac.is_local());
let local_unicast = [0x02, 0x00, 0x00, 0x00, 0x00, 0x01];
let mac = MacAddr::new(local_unicast);
assert!(mac.is_unicast());
assert!(mac.is_local());
let universal_multicast = [0x01, 0x00, 0x5E, 0x00, 0x00, 0x01];
let mac = MacAddr::new(universal_multicast);
assert!(mac.is_multicast());
assert!(mac.is_universal());
}
}