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}