Skip to main content

macaddr/
addr8.rs

1use 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}