hardware_address/
mac.rs

1const MAC_ADDRESS_SIZE: usize = 6;
2
3addr_ty!(
4  /// Represents a physical hardware address (MAC address).
5  #[doc(alias = "Eui48Addr")]
6  #[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
7  MacAddr[MAC_ADDRESS_SIZE]
8);
9
10#[cfg(test)]
11mod tests {
12  use super::*;
13  use crate::{ParseError, TestCase};
14
15  use std::{string::ToString, vec, vec::Vec};
16
17  fn test_cases() -> Vec<TestCase<MAC_ADDRESS_SIZE>> {
18    vec![
19      // RFC 7042, Section 2.1.1
20      TestCase {
21        input: "00:00:5e:00:53:01",
22        output: Some(vec![0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]),
23        err: None,
24      },
25      TestCase {
26        input: "00-00-5e-00-53-01",
27        output: Some(vec![0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]),
28        err: None,
29      },
30      TestCase {
31        input: "0000.5e00.5301",
32        output: Some(vec![0x00, 0x00, 0x5e, 0x00, 0x53, 0x01]),
33        err: None,
34      },
35      TestCase {
36        input: "ab:cd:ef:AB:CD:EF",
37        output: Some(vec![0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef]),
38        err: None,
39      },
40      // Invalid MAC-48 cases
41      TestCase {
42        input: "01.02.03.04.05.06",
43        output: None,
44        err: Some(ParseError::InvalidSeparator(b'.')),
45      },
46      TestCase {
47        input: "01:02:03:04:05:06:",
48        output: None,
49        err: Some(ParseError::InvalidLength(18)),
50      },
51      TestCase {
52        input: "x1:02:03:04:05:06",
53        output: None,
54        err: Some(ParseError::InvalidHexDigit([b'x', b'1'])),
55      },
56      TestCase {
57        input: "01-02:03:04:05:06",
58        output: None,
59        err: Some(ParseError::UnexpectedSeparator {
60          expected: b'-',
61          actual: b':',
62        }),
63      },
64    ]
65  }
66
67  #[test]
68  fn parse() {
69    let cases = test_cases();
70    for (i, test) in cases.iter().enumerate() {
71      let result = MacAddr::try_from(test.input);
72
73      match (result, &test.output) {
74        (Ok(out), Some(expected)) => {
75          assert_eq!(
76            out.as_bytes(),
77            expected.as_slice(),
78            "Test case {}: MacAddr::parse({}) output mismatch",
79            i,
80            test.input
81          );
82
83          // Test round-trip if this was a valid case
84          if test.err.is_none() {
85            let formatted = out.to_string();
86            let round_trip = MacAddr::try_from(formatted.as_str());
87            assert!(
88              round_trip.is_ok(),
89              "Test case {}: Round-trip parse failed for {}",
90              i,
91              formatted
92            );
93            assert_eq!(
94              round_trip.unwrap(),
95              out,
96              "Test case {}: Round-trip value mismatch",
97              i
98            );
99          }
100        }
101        (Err(err), None) => {
102          assert_eq!(
103            Some(&err),
104            test.err.as_ref(),
105            "Test case {}: Expected error containing '{:?}', got '{:?}'",
106            i,
107            test.err,
108            err
109          );
110        }
111        (Ok(out), None) => {
112          panic!(
113            "Test case {}: Expected error '{:?}', got success: {:?}",
114            i, test.err, out
115          );
116        }
117        (Err(err), Some(expected)) => {
118          panic!(
119            "Test case {}: Expected {:?}, got error: {:?}",
120            i, expected, err
121          );
122        }
123      }
124    }
125  }
126
127  #[test]
128  fn formatted() {
129    let addr = MacAddr::try_from("00:00:5e:00:53:01").unwrap();
130    assert_eq!(addr.to_string(), "00:00:5e:00:53:01");
131
132    let dot = addr.to_dot_seperated_array();
133    let dot_str = core::str::from_utf8(&dot).unwrap();
134    assert_eq!(dot_str, "0000.5e00.5301");
135
136    let dashed = addr.to_hyphen_seperated_array();
137    let dashed_str = core::str::from_utf8(&dashed).unwrap();
138    assert_eq!(dashed_str, "00-00-5e-00-53-01");
139  }
140
141  #[cfg(feature = "serde")]
142  #[test]
143  fn serde_human_readable() {
144    let addr = MacAddr::try_from("00:00:5e:00:53:01").unwrap();
145    let json = serde_json::to_string(&addr).unwrap();
146    assert_eq!(json, "\"00:00:5e:00:53:01\"");
147
148    let addr2: MacAddr = serde_json::from_str(&json).unwrap();
149    assert_eq!(addr, addr2);
150  }
151
152  #[cfg(feature = "serde")]
153  #[test]
154  fn serde_human_unreadable() {
155    let addr = MacAddr::try_from("00:00:5e:00:53:01").unwrap();
156    let json = bincode::serialize(&addr).unwrap();
157    assert_eq!(json, [0, 0, 94, 0, 83, 1]);
158    assert_eq!(addr.octets(), [0, 0, 94, 0, 83, 1]);
159
160    let addr2: MacAddr = bincode::deserialize(&json).unwrap();
161    assert_eq!(addr, addr2);
162
163    let addr3 = MacAddr::new([0, 0, 94, 0, 83, 1]);
164    assert_eq!(addr, addr3);
165
166    println!("{:?}", addr);
167  }
168}