rips_packets/ethernet/
macaddr.rs

1use std::error::Error;
2use std::fmt;
3use std::str::FromStr;
4
5#[derive(Debug, Eq, PartialEq)]
6pub struct MacAddrLengthError;
7
8impl fmt::Display for MacAddrLengthError {
9    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10        self.description().fmt(f)
11    }
12}
13
14impl Error for MacAddrLengthError {
15    fn description(&self) -> &str {
16        "Given data not six bytes long"
17    }
18}
19
20/// A MAC address. Six bytes representing a link layer network address.
21#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
22pub struct MacAddr(pub [u8; 6]);
23
24impl MacAddr {
25    /// The broadcast MAC address. Used to broadcast to the local network.
26    pub const BROADCAST: MacAddr = MacAddr([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
27
28    /// Constructs a `MacAddr` from a slice of bytes.
29    /// Will fail if the given slice is not 6 bytes long.
30    pub fn try_from_slice(slice: &[u8]) -> Result<MacAddr, MacAddrLengthError> {
31        if slice.len() == 6 {
32            Ok(Self::from_slice(slice))
33        } else {
34            Err(MacAddrLengthError)
35        }
36    }
37
38    /// Constructs a `MacAddr` from a slice of bytes.
39    /// # Panics
40    /// This function panics if the given slice is not 6 bytes long.
41    pub fn from_slice(slice: &[u8]) -> MacAddr {
42        let mut mac = MacAddr::default();
43        <[u8; 6] as AsMut<[u8]>>::as_mut(&mut mac.0).copy_from_slice(slice);
44        mac
45    }
46
47    /// Constructs a `MacAddr` from six individual bytes.
48    pub fn from_bytes(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8) -> MacAddr {
49        MacAddr([b0, b1, b2, b3, b4, b5])
50    }
51}
52
53impl AsRef<[u8]> for MacAddr {
54    fn as_ref(&self) -> &[u8] {
55        &self.0[..]
56    }
57}
58
59impl AsRef<[u8; 6]> for MacAddr {
60    fn as_ref(&self) -> &[u8; 6] {
61        &self.0
62    }
63}
64
65impl From<[u8; 6]> for MacAddr {
66    fn from(data: [u8; 6]) -> Self {
67        MacAddr(data)
68    }
69}
70
71#[derive(Debug, Eq, PartialEq)]
72pub struct MacAddrParseError(String);
73
74impl fmt::Display for MacAddrParseError {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        write!(f, "Invalid MAC string: {}", self.0)
77    }
78}
79
80impl Error for MacAddrParseError {
81    fn description(&self) -> &str {
82        "Invalid MAC address string"
83    }
84}
85
86impl FromStr for MacAddr {
87    type Err = MacAddrParseError;
88
89    fn from_str(s: &str) -> Result<Self, Self::Err> {
90        use std::num::ParseIntError;
91
92        let bytes: Result<Vec<u8>, ParseIntError> =
93            s.split(":").map(|s| u8::from_str_radix(s, 16)).collect();
94        match bytes {
95            Ok(ref bytes) if bytes.len() == 6 => Ok(Self::from_slice(&bytes)),
96            _ => Err(MacAddrParseError(s.to_owned())),
97        }
98    }
99}
100
101impl fmt::Display for MacAddr {
102    /// Format the MAC address with each byte in hexadecimal form and separated
103    /// by colons
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        write!(
106            f,
107            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
108            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
109        )
110    }
111}
112
113impl fmt::Debug for MacAddr {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        (self as &fmt::Display).fmt(f)
116    }
117}
118
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn from_slice() {
126        let data = [5, 6, 7, 8, 9, 10];
127        let mac = MacAddr::from_slice(&data[..]);
128        assert_eq!(data, mac.as_ref());
129    }
130
131    #[test]
132    #[should_panic]
133    fn from_short_slice() {
134        MacAddr::from_slice(&[1, 2, 3, 4, 5]);
135    }
136
137    #[test]
138    #[should_panic]
139    fn from_long_slice() {
140        MacAddr::from_slice(&[1, 2, 3, 4, 5, 6, 7]);
141    }
142
143    #[test]
144    fn from_bytes() {
145        let mac = MacAddr::from_bytes(2, 3, 4, 5, 6, 7);
146        assert_eq!([2, 3, 4, 5, 6, 7], mac.as_ref());
147    }
148
149    #[test]
150    fn as_ref() {
151        let data = [5, 6, 7, 8, 9, 10];
152        let mac = MacAddr(data);
153        assert_eq!(data, mac.as_ref());
154    }
155
156    #[test]
157    fn display() {
158        let mac = MacAddr([255, 6, 7, 8, 9, 10]);
159        assert_eq!("ff:06:07:08:09:0a", mac.to_string());
160    }
161
162    #[test]
163    fn from_str() {
164        let result = MacAddr::from_str("01:02:ff:ac:13:37");
165        assert_eq!(result, Ok(MacAddr([0x01, 0x02, 0xff, 0xac, 0x13, 0x37])));
166    }
167}