proxmox_api/types/
mac_addr.rs

1use serde::{Deserialize, Serialize};
2
3/// A MAC address.
4///
5/// `B` represents whether this address is a unicast address, or if it may be unicast
6/// _or_ multicast.
7///
8/// If `B` is `false`, this is a unicast address. If `B` is `true` this is address
9/// may represent either a unicast _or_ a multicast address.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(try_from = "String", into = "String")]
12pub struct MacAddr<const B: bool>([u8; 6]);
13
14impl MacAddr<false> {
15    pub fn try_new(addr: [u8; 6]) -> Option<Self> {
16        let me = Self(addr);
17
18        (!me.ig_bit_int()).then_some(me)
19    }
20}
21
22impl TryFrom<MacAddr<true>> for MacAddr<false> {
23    type Error = ();
24
25    fn try_from(value: MacAddr<true>) -> Result<Self, Self::Error> {
26        MacAddr::<false>::try_new(value.0).ok_or(())
27    }
28}
29
30impl From<MacAddr<false>> for MacAddr<true> {
31    fn from(value: MacAddr<false>) -> Self {
32        Self(value.0)
33    }
34}
35
36impl MacAddr<true> {
37    pub fn new(addr: [u8; 6]) -> Self {
38        Self(addr)
39    }
40}
41
42impl<const B: bool> MacAddr<B> {
43    pub fn get(&self) -> [u8; 6] {
44        self.0
45    }
46
47    fn ig_bit_int(&self) -> bool {
48        (self.0[0] & 0x80) == 0x80
49    }
50
51    pub fn ig_bit(&self) -> bool {
52        // Gotta make sure we actually uphold this...
53        debug_assert!(self.ig_bit_int());
54        B
55    }
56}
57
58impl<const B: bool> From<MacAddr<B>> for String {
59    fn from(value: MacAddr<B>) -> Self {
60        format!(
61            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
62            value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5]
63        )
64    }
65}
66
67impl<const B: bool> TryFrom<String> for MacAddr<B> {
68    type Error = String;
69
70    fn try_from(value: String) -> Result<Self, Self::Error> {
71        let (count, addr) =
72            value
73                .split(':')
74                .try_fold((0usize, [0u8; 6]), |(mut idx, mut accum), input| {
75                    if idx == 6 {
76                        Err(format!("Too many segments in MAC address"))
77                    } else if let Ok(value) = u8::from_str_radix(input, 16) {
78                        accum[idx] = value;
79                        idx += 1;
80                        Ok((idx, accum))
81                    } else {
82                        Err(format!("Invalid mac address segment: {input}"))
83                    }
84                })?;
85
86        let addr = MacAddr(addr);
87
88        if count != 6 {
89            Err(format!(
90                "Not enough segments in MAC address. Expected 6, got {count}"
91            ))
92        } else if !B && addr.ig_bit_int() {
93            Err(format!("Mac address "))
94        } else {
95            Ok(addr)
96        }
97    }
98}