1 use core::{fmt, str::FromStr}; 2 3 use crate::parser; 4 5 /// MAC address in *EUI-64* format. 6 #[repr(C)] 7 #[derive(Debug, Default, Hash, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] 8 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 9 pub struct MacAddr8([u8; 8]); 10 11 impl MacAddr8 { 12 /// Creates a new `MacAddr8` address from the bytes. 13 /// 14 /// ## Example 15 /// 16 /// ```rust 17 /// # use macaddr::MacAddr8; 18 /// let addr = MacAddr8::new(0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF); 19 /// ``` 20 #[allow(clippy::many_single_char_names, clippy::too_many_arguments)] new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) -> MacAddr821 pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8, h: u8) -> MacAddr8 { 22 MacAddr8([a, b, c, d, e, f, g, h]) 23 } 24 25 /// Create a new nil `MacAddr8`. 26 /// 27 /// ## Example 28 /// 29 /// ```rust 30 /// # use macaddr::MacAddr8; 31 /// let addr = MacAddr8::nil(); 32 /// assert!(addr.is_nil()); 33 /// ``` nil() -> MacAddr834 pub const fn nil() -> MacAddr8 { 35 MacAddr8([0x00; 8]) 36 } 37 38 /// Create a new broadcast `MacAddr8`. 39 /// 40 /// ## Example 41 /// 42 /// ```rust 43 /// # use macaddr::MacAddr8; 44 /// let addr = MacAddr8::broadcast(); 45 /// assert!(addr.is_broadcast()); 46 /// ``` broadcast() -> MacAddr847 pub const fn broadcast() -> MacAddr8 { 48 MacAddr8([0xFF; 8]) 49 } 50 51 /// Returns `true` if the address is nil. 52 /// 53 /// ## Example 54 /// 55 /// ```rust 56 /// # use macaddr::MacAddr8; 57 /// let addr = MacAddr8::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 58 /// 59 /// assert_eq!(addr.is_nil(), true); 60 /// ``` 61 #[allow(clippy::trivially_copy_pass_by_ref)] is_nil(&self) -> bool62 pub fn is_nil(&self) -> bool { 63 self.0.iter().all(|&b| b == 0) 64 } 65 66 /// Returns `true` if the address is broadcast. 67 /// 68 /// ## Example 69 /// 70 /// ```rust 71 /// # use macaddr::MacAddr8; 72 /// let addr = MacAddr8::new(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); 73 /// 74 /// assert_eq!(addr.is_broadcast(), true); 75 /// ``` 76 #[allow(clippy::trivially_copy_pass_by_ref)] is_broadcast(&self) -> bool77 pub fn is_broadcast(&self) -> bool { 78 self.0.iter().all(|&b| b == 0xFF) 79 } 80 81 /// Returns `true` if the address is unicast. 82 /// 83 /// ## Example 84 /// 85 /// ```rust 86 /// # use macaddr::MacAddr8; 87 /// let addr = MacAddr8::new(0x00, 0x01, 0x44, 0x55, 0x66, 0x77, 0xCD, 0xEF); 88 /// 89 /// assert_eq!(addr.is_unicast(), true); 90 /// ``` 91 #[allow(clippy::trivially_copy_pass_by_ref)] is_unicast(&self) -> bool92 pub const fn is_unicast(&self) -> bool { 93 self.0[0] & 1 == 0 94 } 95 96 /// Returns `true` if the address is multicast. 97 /// 98 /// ## Example 99 /// 100 /// ```rust 101 /// # use macaddr::MacAddr8; 102 /// let addr = MacAddr8::new(0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC); 103 /// 104 /// assert_eq!(addr.is_multicast(), true); 105 /// ``` 106 #[allow(clippy::trivially_copy_pass_by_ref)] is_multicast(&self) -> bool107 pub const fn is_multicast(&self) -> bool { 108 self.0[0] & 1 == 1 109 } 110 111 /// Returns `true` if the address is universally administered address (UAA). 112 /// 113 /// ## Example 114 /// 115 /// ```rust 116 /// # use macaddr::MacAddr8; 117 /// let addr = MacAddr8::new(0x01, 0x00, 0x0C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC); 118 /// 119 /// assert_eq!(addr.is_universal(), true); 120 /// ``` 121 #[allow(clippy::trivially_copy_pass_by_ref)] is_universal(&self) -> bool122 pub const fn is_universal(&self) -> bool { 123 self.0[0] & 1 << 1 == 0 124 } 125 126 /// Returns `true` if the address is locally administered (LAA). 127 /// 128 /// ## Example 129 /// 130 /// ```rust 131 /// # use macaddr::MacAddr8; 132 /// let addr = MacAddr8::new(0x02, 0x00, 0x0C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC); 133 /// 134 /// assert_eq!(addr.is_local(), true); 135 /// ``` 136 #[allow(clippy::trivially_copy_pass_by_ref)] is_local(&self) -> bool137 pub const fn is_local(&self) -> bool { 138 self.0[0] & 1 << 1 == 2 139 } 140 141 /// Converts a `MacAddr8` address to a byte slice. 142 /// 143 /// ## Example 144 /// 145 /// ```rust 146 /// # use macaddr::MacAddr8; 147 /// let addr = MacAddr8::new(0xAC, 0xDE, 0x48, 0x23, 0x45, 0x67, 0x89, 0xAB); 148 /// 149 /// assert_eq!(addr.as_bytes(), &[0xAC, 0xDE, 0x48, 0x23, 0x45, 0x67, 0x89, 0xAB]); 150 /// ``` as_bytes(&self) -> &[u8]151 pub fn as_bytes(&self) -> &[u8] { 152 &self.0 153 } 154 155 /// Consumes a `MacAddr8` address and returns raw bytes. 156 /// 157 /// ## Example 158 /// 159 /// ```rust 160 /// # use macaddr::MacAddr8; 161 /// let addr = MacAddr8::new(0xAC, 0xDE, 0x48, 0x23, 0x45, 0x67, 0x89, 0xAB); 162 /// 163 /// assert_eq!(addr.into_array(), [0xAC, 0xDE, 0x48, 0x23, 0x45, 0x67, 0x89, 0xAB]); 164 /// ``` into_array(self) -> [u8; 8]165 pub const fn into_array(self) -> [u8; 8] { 166 self.0 167 } 168 } 169 170 impl FromStr for MacAddr8 { 171 type Err = parser::ParseError; 172 from_str(s: &str) -> Result<Self, Self::Err>173 fn from_str(s: &str) -> Result<Self, Self::Err> { 174 parser::Parser::new(s).read_v8_addr() 175 } 176 } 177 178 impl From<[u8; 8]> for MacAddr8 { from(bytes: [u8; 8]) -> Self179 fn from(bytes: [u8; 8]) -> Self { 180 MacAddr8(bytes) 181 } 182 } 183 184 impl AsRef<[u8]> for MacAddr8 { as_ref(&self) -> &[u8]185 fn as_ref(&self) -> &[u8] { 186 &self.0 187 } 188 } 189 190 impl AsMut<[u8]> for MacAddr8 { as_mut(&mut self) -> &mut [u8]191 fn as_mut(&mut self) -> &mut [u8] { 192 &mut self.0 193 } 194 } 195 196 /// `MacAddr8` can be displayed in different formats. 197 /// 198 /// # Example 199 /// 200 /// ``` 201 /// # use macaddr::MacAddr8; 202 /// let addr = MacAddr8::new(0xab, 0x0d, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9A); 203 /// 204 /// assert_eq!(&format!("{}", addr), "AB:0D:EF:12:34:56:78:9A"); 205 /// assert_eq!(&format!("{:-}", addr), "AB-0D-EF-12-34-56-78-9A"); 206 /// assert_eq!(&format!("{:#}", addr), "AB0D.EF12.3456.789A"); 207 /// ``` 208 impl fmt::Display for MacAddr8 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 210 if f.sign_minus() { 211 f.write_fmt(format_args!( 212 "{:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}", 213 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7], 214 )) 215 } else if f.alternate() { 216 f.write_fmt(format_args!( 217 "{:02X}{:02X}.{:02X}{:02X}.{:02X}{:02X}.{:02X}{:02X}", 218 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7], 219 )) 220 } else { 221 f.write_fmt(format_args!( 222 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 223 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7], 224 )) 225 } 226 } 227 } 228