blob: 9c33d76d7aa197c09cd9a777722f702039e73b13 [file] [log] [blame]
Yi Kong87d88892021-03-17 17:48:07 +08001use core::{fmt, str::FromStr};
2
3use 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))]
9pub struct MacAddr8([u8; 8]);
10
11impl 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
170impl 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
178impl From<[u8; 8]> for MacAddr8 {
179 fn from(bytes: [u8; 8]) -> Self {
180 MacAddr8(bytes)
181 }
182}
183
184impl AsRef<[u8]> for MacAddr8 {
185 fn as_ref(&self) -> &[u8] {
186 &self.0
187 }
188}
189
190impl 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/// ```
208impl 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}