Yi Kong | 87d8889 | 2021-03-17 17:48:07 +0800 | [diff] [blame] | 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)] |
| 21 | 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 | /// ``` |
| 34 | 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 | /// ``` |
| 47 | 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)] |
| 62 | 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)] |
| 77 | 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)] |
| 92 | 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)] |
| 107 | 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)] |
| 122 | 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)] |
| 137 | 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 | /// ``` |
| 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 | /// ``` |
| 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 | |
| 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 { |
| 179 | fn from(bytes: [u8; 8]) -> Self { |
| 180 | MacAddr8(bytes) |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | impl AsRef<[u8]> for MacAddr8 { |
| 185 | fn as_ref(&self) -> &[u8] { |
| 186 | &self.0 |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | impl AsMut<[u8]> for MacAddr8 { |
| 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 { |
| 209 | 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 | } |