1use std::str::FromStr;
16
17use serde::Deserialize;
18use serde::de::{self, Visitor};
19use serde_aco::{Help, TypedHelp};
20use zerocopy::{FromBytes, Immutable, IntoBytes};
21
22#[derive(Debug, Clone, Default, FromBytes, Immutable, IntoBytes, PartialEq, Eq)]
23#[repr(transparent)]
24pub struct MacAddr(pub [u8; 6]);
25
26#[derive(Debug)]
27pub enum Error {
28 InvalidLength { len: usize },
29 InvalidNumber { num: String },
30}
31
32impl FromStr for MacAddr {
33 type Err = Error;
34
35 fn from_str(s: &str) -> Result<Self, Self::Err> {
36 let mut addr = [0u8; 6];
37 let iter = s.split(':');
38 let mut index = 0;
39 for b_s in iter {
40 let Ok(v) = u8::from_str_radix(b_s, 16) else {
41 return Err(Error::InvalidNumber {
42 num: b_s.to_owned(),
43 });
44 };
45 if let Some(b) = addr.get_mut(index) {
46 *b = v;
47 };
48 index += 1;
49 }
50 if index != 6 {
51 return Err(Error::InvalidLength { len: index });
52 }
53 Ok(MacAddr(addr))
54 }
55}
56
57impl Help for MacAddr {
58 const HELP: TypedHelp = TypedHelp::Custom { desc: "mac-addr" };
59}
60
61struct MacAddrVisitor;
62
63impl<'de> Visitor<'de> for MacAddrVisitor {
64 type Value = MacAddr;
65
66 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
67 formatter.write_str("a MAC address like ea:d7:a8:e8:c6:2f")
68 }
69
70 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
71 where
72 E: de::Error,
73 {
74 match v.parse::<MacAddr>() {
75 Ok(v) => Ok(v),
76 Err(Error::InvalidLength { len }) => Err(E::invalid_length(len, &"6")),
77 Err(Error::InvalidNumber { num }) => Err(E::invalid_value(
78 de::Unexpected::Str(num.as_str()),
79 &"hexadecimal",
80 )),
81 }
82 }
83}
84
85impl<'de> Deserialize<'de> for MacAddr {
86 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
87 where
88 D: de::Deserializer<'de>,
89 {
90 deserializer.deserialize_str(MacAddrVisitor)
91 }
92}
93
94#[cfg(test)]
95#[path = "net_test.rs"]
96mod tests;