mm1_address/
subnet.rs

1use std::fmt;
2use std::str::FromStr;
3
4use crate::address::{Address, AddressParseError};
5
6mod net_mask;
7
8const ADDRESS_BITS: u8 = u64::BITS as u8;
9
10#[derive(
11    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
12)]
13pub struct NetMask(u8);
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct NetAddress {
17    pub address: Address,
18    pub mask:    NetMask,
19}
20
21#[derive(Debug, thiserror::Error)]
22pub enum MaskParseError {
23    #[error("invalid mask")]
24    InvalidMask(InvalidMask),
25    #[error("parse int error")]
26    ParseIntError(<u64 as FromStr>::Err),
27}
28
29#[derive(Debug, thiserror::Error)]
30#[error("invalid mask: {}", _0)]
31pub struct InvalidMask(u8);
32
33#[derive(Debug, thiserror::Error)]
34pub enum NetAddressParseError {
35    #[error("no slash")]
36    NoSlash,
37    #[error("parse addr error")]
38    ParseAddrError(AddressParseError),
39    #[error("parse mask error")]
40    ParseMaskError(MaskParseError),
41}
42
43impl NetMask {
44    pub fn bits_fixed(&self) -> u8 {
45        self.0
46    }
47
48    pub fn bits_available(&self) -> u8 {
49        ADDRESS_BITS - self.bits_fixed()
50    }
51
52    pub fn into_u64(self) -> u64 {
53        match self.0 as u32 {
54            0 => 0u64,
55            zero_to_63 => u64::MAX << (u64::BITS - zero_to_63),
56        }
57    }
58}
59
60impl From<(Address, NetMask)> for NetAddress {
61    fn from((address, mask): (Address, NetMask)) -> Self {
62        Self { address, mask }
63    }
64}
65
66impl TryFrom<u8> for NetMask {
67    type Error = InvalidMask;
68
69    fn try_from(value: u8) -> Result<Self, Self::Error> {
70        match value {
71            0..=ADDRESS_BITS => Ok(Self(value)),
72            invalid => Err(InvalidMask(invalid)),
73        }
74    }
75}
76
77impl From<NetMask> for u8 {
78    fn from(value: NetMask) -> Self {
79        value.0
80    }
81}
82
83impl FromStr for NetMask {
84    type Err = MaskParseError;
85
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        s.parse::<u8>()
88            .map_err(MaskParseError::ParseIntError)?
89            .try_into()
90            .map_err(MaskParseError::InvalidMask)
91    }
92}
93
94impl FromStr for NetAddress {
95    type Err = NetAddressParseError;
96
97    fn from_str(s: &str) -> Result<Self, Self::Err> {
98        let (addr, mask) = s.split_once('/').ok_or(NetAddressParseError::NoSlash)?;
99        let address = addr.parse().map_err(NetAddressParseError::ParseAddrError)?;
100        let mask = mask.parse().map_err(NetAddressParseError::ParseMaskError)?;
101
102        Ok(Self { address, mask })
103    }
104}
105
106impl fmt::Display for NetMask {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        fmt::Display::fmt(&self.0, f)
109    }
110}
111
112impl fmt::Display for NetAddress {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        write!(f, "{}/{}", self.address, self.mask)
115    }
116}
117
118impl serde::Serialize for NetAddress {
119    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120    where
121        S: serde::Serializer,
122    {
123        self.to_string().serialize(serializer)
124    }
125}
126impl<'de> serde::Deserialize<'de> for NetAddress {
127    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
128    where
129        D: serde::Deserializer<'de>,
130    {
131        String::deserialize(deserializer)?
132            .parse()
133            .map_err(<D::Error as serde::de::Error>::custom)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn parse_mask() {
143        for i in 0..=64 {
144            let _: NetMask = i.to_string().parse().expect("parse mask");
145        }
146        for i in 65..128 {
147            assert!(NetMask::from_str(&i.to_string()).is_err());
148        }
149    }
150
151    #[test]
152    fn net_address_parse() {
153        for i in 0..=64 {
154            let address = Address::from_u64(i);
155            let mask = i.to_string().parse().unwrap();
156            eprintln!("{}", NetAddress { address, mask });
157        }
158    }
159
160    #[test]
161    fn mask_to_u64() {
162        for (input, expected) in [
163            (64, u64::MAX),
164            (60, 0xFFFF_FFFF_FFFF_FFF0),
165            (56, 0xFFFF_FFFF_FFFF_FF00),
166            (52, 0xFFFF_FFFF_FFFF_F000),
167            (48, 0xFFFF_FFFF_FFFF_0000),
168            (44, 0xFFFF_FFFF_FFF0_0000),
169            (40, 0xFFFF_FFFF_FF00_0000),
170            (36, 0xFFFF_FFFF_F000_0000),
171            (32, 0xFFFF_FFFF_0000_0000),
172            (28, 0xFFFF_FFF0_0000_0000),
173            (24, 0xFFFF_FF00_0000_0000),
174            (20, 0xFFFF_F000_0000_0000),
175            (16, 0xFFFF_0000_0000_0000),
176            (12, 0xFFF0_0000_0000_0000),
177            (8, 0xFF00_0000_0000_0000),
178            (4, 0xF000_0000_0000_0000),
179            (0, 0x0000_0000_0000_0000),
180        ] {
181            assert_eq!(NetMask(input).into_u64(), expected, "/{}", input);
182        }
183    }
184}