From dc560c9663853bfd67da8774a6e87e73cd2bb41b Mon Sep 17 00:00:00 2001 From: Ossi Herrala Date: Mon, 24 Oct 2022 22:08:46 +0300 Subject: [PATCH] Change MacAddr to hold u64 instead of byte array Compiler probably does this anyway. And this way we can have access to upper two bytes if we want to. --- luomu-common/src/macaddr.rs | 91 ++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/luomu-common/src/macaddr.rs b/luomu-common/src/macaddr.rs index 4e72002..4dafc04 100644 --- a/luomu-common/src/macaddr.rs +++ b/luomu-common/src/macaddr.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::fmt; use super::InvalidAddress; @@ -10,55 +10,71 @@ use super::InvalidAddress; /// address to reside in lowest 6 bytes. All `From` and /// `TryFrom` implementations return their bytes as big endian. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct MacAddr([u8; 6]); +pub struct MacAddr(u64); + +impl MacAddr { + /// A broadcast MAC address (FF:FF:FF:FF:FF:FF) + pub const BROADCAST: MacAddr = MacAddr(0x0000FFFFFFFFFFFF); +} impl From<[u8; 6]> for MacAddr { - fn from(val: [u8; 6]) -> Self { - Self(val) + fn from(v: [u8; 6]) -> Self { + Self::from(&v) } } impl From<&[u8; 6]> for MacAddr { - fn from(val: &[u8; 6]) -> Self { - Self(val.to_owned()) + fn from(v: &[u8; 6]) -> Self { + let r = (u64::from(v[0]) << 40) + + (u64::from(v[1]) << 32) + + (u64::from(v[2]) << 24) + + (u64::from(v[3]) << 16) + + (u64::from(v[4]) << 8) + + u64::from(v[5]); + Self(r) } } -impl From for [u8; 6] { - fn from(val: MacAddr) -> Self { - val.0 +impl TryFrom for MacAddr { + type Error = InvalidAddress; + + fn try_from(mac: u64) -> Result { + if mac > 0x0000FFFFFFFFFFFF { + return Err(InvalidAddress); + } + + Ok(Self(mac)) } } -impl<'a> From<&'a MacAddr> for &'a [u8; 6] { - fn from(val: &'a MacAddr) -> Self { - &val.0 +impl From for u64 { + fn from(mac: MacAddr) -> Self { + mac.0 } } -impl<'a> From<&'a MacAddr> for &'a [u8] { - fn from(val: &'a MacAddr) -> Self { - &val.0 +impl From<&MacAddr> for u64 { + fn from(mac: &MacAddr) -> Self { + mac.0 } } -impl TryFrom for MacAddr { - type Error = InvalidAddress; - - fn try_from(mac: u64) -> Result { - if mac > 0x0000FFFFFFFFFFFF { - return Err(InvalidAddress); - } +impl From for [u8; 6] { + fn from(mac: MacAddr) -> Self { + (&mac).into() + } +} - let b = mac.to_be_bytes(); - Ok(MacAddr([b[2], b[3], b[4], b[5], b[6], b[7]])) +impl From<&MacAddr> for [u8; 6] { + fn from(mac: &MacAddr) -> Self { + u64::from(mac).to_be_bytes()[2..=7].try_into().unwrap() } } impl fmt::Debug for MacAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let h = self - .0 + let b: [u8; 6] = self.into(); + let h = b .iter() .map(|b| format!("{:02x}", b)) .collect::>() @@ -67,13 +83,6 @@ impl fmt::Debug for MacAddr { } } -impl std::ops::Deref for MacAddr { - type Target = [u8; 6]; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; @@ -89,6 +98,14 @@ mod tests { assert_eq!(&debug, "00:ff:11:ee:22:dd"); } + #[test] + fn test_mac_to_array() { + let slice = [0x00, 0xff, 0x11, 0xee, 0x22, 0xdd]; + let mac: MacAddr = slice.into(); + let array: [u8; 6] = mac.into(); + assert_eq!(slice, array); + } + #[test] fn test_try_from_u64_bounds() { let i0 = 0x0000000000000000; @@ -108,15 +125,15 @@ mod tests { fn test_try_from_u64_byteoder() { let i = 0x0000123456789ABC; let mac = MacAddr::try_from(i).unwrap(); - let b: &[u8] = (&mac).into(); - assert_eq!(b, &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]); + let b: [u8; 6] = mac.into(); + assert_eq!(&b, &[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]); } quickcheck! { fn prop_macaddr_to_from(xs: (u8, u8, u8, u8, u8, u8)) -> bool { - let b1 = &[xs.0, xs.1, xs.2, xs.3, xs.4, xs.5]; + let b1: [u8; 6] = [xs.0, xs.1, xs.2, xs.3, xs.4, xs.5]; let mac = MacAddr::from(b1); - let b2: &[u8] = (&mac).into(); + let b2: [u8; 6] = mac.into(); b1 == b2 } }