1use crate::IpBitwiseExt;
2
3use std::net::Ipv4Addr;
4use std::str::FromStr;
5
6use std::ops::Not;
7
8use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
9
10#[repr(align(4))]
12#[derive(Copy, Clone, Eq, PartialEq, Hash)]
13pub struct Ipv4Mask {
14 mask: [u8; 4],
15}
16
17impl Ipv4Mask {
18 pub const fn new(len: u8) -> Self {
24 #[rustfmt::skip]
25 const MASKS: [[u8; 4]; 33] = [
26 [0, 0, 0, 0],
28 [128, 0, 0, 0], [192, 0, 0, 0], [224, 0, 0, 0], [240, 0, 0, 0],
30 [248, 0, 0, 0], [252, 0, 0, 0], [254, 0, 0, 0], [255, 0, 0, 0],
31 [255, 128, 0, 0], [255, 192, 0, 0], [255, 224, 0, 0], [255, 240, 0, 0],
33 [255, 248, 0, 0], [255, 252, 0, 0], [255, 254, 0, 0], [255, 255, 0, 0],
34 [255, 255, 128, 0], [255, 255, 192, 0], [255, 255, 224, 0], [255, 255, 240, 0],
36 [255, 255, 248, 0], [255, 255, 252, 0], [255, 255, 254, 0], [255, 255, 255, 0],
37 [255, 255, 255, 128], [255, 255, 255, 192], [255, 255, 255, 224], [255, 255, 255, 240],
39 [255, 255, 255, 248], [255, 255, 255, 252], [255, 255, 255, 254], [255, 255, 255, 255],
40 ];
41 let mask = MASKS[len as usize];
42 Self { mask }
43 }
44 pub fn from_bytes(bytes: [u8; 4]) -> Option<Self> {
46 Self::from_u32(u32::from_be_bytes(bytes))
47 }
48 pub fn from_u32(x: u32) -> Option<Self> {
50 let ones = if cfg!(target_feature = "popcnt") {
51 x.count_ones() as u8 } else {
53 (!x).leading_zeros() as u8 };
55 let zeros = x.trailing_zeros() as u8; if ones + zeros == 32 {
58 let mask = x.to_be_bytes();
59 Some(Self { mask })
60 } else {
61 None
62 }
63 }
64 pub const fn octets(self) -> [u8; 4] {
66 self.mask
67 }
68 pub const fn as_u32(self) -> u32 {
70 let bytes = self.octets();
71 (bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 | bytes[3] as u32
72 }
73 pub const fn len(self) -> u8 {
75 let x = self.as_u32();
76 #[cfg(target_feature = "popcnt")]
77 let len = x.count_ones() as u8;
78 #[cfg(not(target_feature = "popcnt"))]
79 let len = (!x).leading_zeros() as u8;
80 len
81 }
82}
83
84impl Display for Ipv4Mask {
85 fn fmt(&self, f: &mut Formatter) -> FmtResult {
86 if f.alternate() {
87 write!(f, "/{}", self.len())
88 } else {
89 let bytes = self.octets();
90 write!(f, "{}.{}.{}.{}", bytes[0], bytes[1], bytes[2], bytes[3])
91 }
92 }
93}
94
95impl Debug for Ipv4Mask {
96 fn fmt(&self, f: &mut Formatter) -> FmtResult {
97 Display::fmt(self, f)
98 }
99}
100
101impl Not for Ipv4Mask {
102 type Output = [u8; 4];
103 fn not(self) -> [u8; 4] {
104 let x = u32::from_ne_bytes(self.octets());
105 (!x).to_ne_bytes()
106 }
107}
108
109impl FromStr for Ipv4Mask {
110 type Err = InvalidIpv4Mask;
111 fn from_str(s: &str) -> Result<Self, InvalidIpv4Mask> {
112 let bytes = s.parse::<Ipv4Addr>().map_err(|_| InvalidIpv4Mask)?.octets();
113 Self::from_bytes(bytes).ok_or(InvalidIpv4Mask)
114 }
115}
116#[derive(Debug)]
118pub struct InvalidIpv4Mask;
119#[derive(Copy, Clone, Eq, PartialEq, Hash)]
122pub struct MaskedIpv4 {
123 pub ip: Ipv4Addr,
125 pub mask: Ipv4Mask,
127}
128
129impl MaskedIpv4 {
130 pub const fn new(ip: Ipv4Addr, mask: Ipv4Mask) -> Self {
132 Self { ip, mask }
133 }
134 pub const fn cidr(ip: Ipv4Addr, mask_len: u8) -> Self {
140 let mask = Ipv4Mask::new(mask_len);
141 Self::new(ip, mask)
142 }
143 pub fn from_cidr_str(s: &str) -> Option<Self> {
145 let mut parts = s.split("/");
146 let ip = parts.next()?.parse::<Ipv4Addr>().ok()?;
147 let mask_len = parts.next()?.parse::<u8>().ok()?;
148 if mask_len > 32 {
149 None
150 } else {
151 Some(Self::cidr(ip, mask_len))
152 }
153 }
154 pub fn from_network_str(s: &str) -> Option<Self> {
156 let mut parts = s.split(" ");
157 let ip = parts.next()?.parse().ok()?;
158 let mask = parts.next()?.parse().ok()?;
159 Some(Self::new(ip, mask))
160 }
161 pub fn to_cidr_string(&self) -> String {
163 format!("{:#}", self)
164 }
165 pub fn to_network_string(&self) -> String {
167 format!("{}", self)
168 }
169 pub fn network_address(&self) -> Ipv4Addr {
171 self.ip.bitand(self.mask)
172 }
173 pub fn network(&self) -> MaskedIpv4 {
175 Self::new(self.network_address(), self.mask)
176 }
177 pub fn is_network_address(&self) -> bool {
179 self.mask.len() <= 30 && self.ip == self.network_address()
180 }
181 pub fn broadcast_address(&self) -> Ipv4Addr {
183 self.ip.bitor(!self.mask)
184 }
185 pub fn is_broadcast_address(&self) -> bool {
187 self.mask.len() <= 30 && self.ip == self.broadcast_address()
188 }
189 pub fn network_bits(&self) -> u8 {
191 self.mask.len()
192 }
193 pub fn host_bits(&self) -> u8 {
195 32 - self.network_bits()
196 }
197 pub fn host_count(&self) -> usize {
203 let host_bits = self.host_bits();
204 match host_bits {
205 0 => 1,
206 1 => 2,
207 _ => 2usize.checked_shl(host_bits as u32).unwrap() - 2,
208 }
209 }
210 pub fn host_count_u64(&self) -> u64 {
212 let host_bits = self.host_bits();
213 match host_bits {
214 0 => 1,
215 1 => 2,
216 _ => (2 << host_bits) - 2,
217 }
218 }
219 pub fn network_count(&self, len: u8) -> usize {
225 if len < self.mask.len() {
226 0
227 } else if len > 32 {
228 panic!("Invalid mask length > 32")
229 } else {
230 let borrowed_bits = len - self.mask.len();
231 2usize.checked_shl(borrowed_bits as u32).unwrap()
232 }
233 }
234 pub fn network_count_u64(&self, len: u8) -> u64 {
241 if len < self.mask.len() {
242 0
243 } else if len > 32 {
244 panic!("Invalid mask length > 32")
245 } else {
246 let borrowed_bits = len - self.mask.len();
247 2 << borrowed_bits
248 }
249 }
250 pub fn contains(&self, ip: Ipv4Addr) -> bool {
252 self.ip.bitand(self.mask) == ip.bitand(self.mask)
253 }
254}
255
256impl Display for MaskedIpv4 {
257 fn fmt(&self, f: &mut Formatter) -> FmtResult {
258 if f.alternate() {
259 write!(f, "{}/{}", self.ip, self.mask.len())
260 } else {
261 write!(f, "{} {}", self.ip, self.mask)
262 }
263 }
264}
265
266impl Debug for MaskedIpv4 {
267 fn fmt(&self, f: &mut Formatter) -> FmtResult {
268 Display::fmt(self, f)
269 }
270}
271
272impl FromStr for MaskedIpv4 {
273 type Err = InvalidMaskedIpv4;
274 fn from_str(s: &str) -> Result<Self, InvalidMaskedIpv4> {
275 Self::from_cidr_str(s)
276 .or_else(|| Self::from_network_str(s))
277 .ok_or(InvalidMaskedIpv4)
278 }
279}
280#[derive(Debug)]
282pub struct InvalidMaskedIpv4;
283
284
285
286