cidr/cidr/
direct.rs

1#[cfg(feature = "bitstring")]
2#[cfg_attr(doc_cfg, doc(cfg(feature = "bitstring")))]
3use bitstring::FixedBitString;
4
5use core::{
6	fmt,
7	str::FromStr,
8};
9use std::net::{
10	Ipv4Addr,
11	Ipv6Addr,
12};
13
14use super::from_str::cidr_from_str;
15use crate::{
16	errors::*,
17	internal_traits::{
18		PrivCidr,
19		PrivUnspecAddress,
20	},
21	Cidr,
22	Family,
23	InetIterator,
24	Ipv4Cidr,
25	Ipv4Inet,
26	Ipv4InetPair,
27	Ipv6Cidr,
28	Ipv6Inet,
29	Ipv6InetPair,
30};
31
32macro_rules! impl_cidr_for {
33	($n:ident : inet $inet:ident : addr $addr:ident : pair $pair:ident : family $family:expr) => {
34		#[cfg(feature = "bitstring")]
35		#[cfg_attr(doc_cfg, doc(cfg(feature = "bitstring")))]
36		impl bitstring::BitString for $n {
37			fn get(&self, ndx: usize) -> bool {
38				self.address.get(ndx)
39			}
40
41			fn set(&mut self, ndx: usize, bit: bool) {
42				assert!(ndx < self.network_length as usize);
43				self.address.set(ndx, bit);
44			}
45
46			fn flip(&mut self, ndx: usize) {
47				assert!(ndx < self.network_length as usize);
48				self.address.flip(ndx);
49			}
50
51			fn len(&self) -> usize {
52				self.network_length as usize
53			}
54
55			fn clip(&mut self, len: usize) {
56				if len > 255 {
57					return;
58				}
59				self.address.set_false_from(len);
60				self.network_length = core::cmp::min(self.network_length, len as u8);
61			}
62
63			fn append(&mut self, bit: bool) {
64				self.address.set(self.network_length as usize, bit);
65				self.network_length += 1;
66			}
67
68			fn null() -> Self {
69				Self {
70					address: FixedBitString::new_all_false(),
71					network_length: 0,
72				}
73			}
74
75			fn shared_prefix_len(&self, other: &Self) -> usize {
76				let max_len = core::cmp::min(self.network_length, other.network_length) as usize;
77				FixedBitString::shared_prefix_len(&self.address, &other.address, max_len)
78			}
79		}
80
81		impl $n {
82			/// Create new network from address and prefix length.  If the
83			/// network length exceeds the address length or the address is not
84			/// the first address in the network ("host part not zero") an
85			/// error is returned.
86			pub const fn new(addr: $addr, len: u8) -> Result<Self, NetworkParseError> {
87				if len > $family.len() {
88					Err(NetworkParseError::NetworkLengthTooLongError(
89						NetworkLengthTooLongError::new(len as usize, $family),
90					))
91				} else if !<$addr as PrivUnspecAddress>::_Tools::_has_zero_host_part(addr, len) {
92					Err(NetworkParseError::InvalidHostPart)
93				} else {
94					Ok(Self {
95						address: addr,
96						network_length: len,
97					})
98				}
99			}
100
101			/// Create a network containing a single address (network length =
102			/// address length).
103			pub const fn new_host(addr: $addr) -> Self {
104				Self {
105					address: addr,
106					network_length: $family.len(),
107				}
108			}
109
110			/// Iterate over all addresses in the range.  With IPv6 addresses
111			/// this can produce really long iterations (up to 2<sup>128</sup>
112			/// addresses).
113			pub const fn iter(&self) -> InetIterator<$addr> {
114				self._range_pair().iter()
115			}
116
117			/// first address in the network as plain address
118			pub const fn first_address(&self) -> $addr {
119				self.address
120			}
121
122			/// first address in the network
123			pub const fn first(&self) -> $inet {
124				$inet {
125					address: self.first_address(),
126					network_length: self.network_length,
127				}
128			}
129
130			/// last address in the network as plain address
131			pub const fn last_address(&self) -> $addr {
132				<$addr as PrivUnspecAddress>::_Tools::_last_address(
133					self.address,
134					self.network_length,
135				)
136			}
137
138			/// last address in the network
139			pub const fn last(&self) -> $inet {
140				$inet {
141					address: self.last_address(),
142					network_length: self.network_length,
143				}
144			}
145
146			/// length in bits of the shared prefix of the contained addresses
147			pub const fn network_length(&self) -> u8 {
148				self.network_length
149			}
150
151			/// IP family of the contained address ([`Ipv4`] or [`Ipv6`]).
152			///
153			/// [`Ipv4`]: Family::Ipv4
154			/// [`Ipv6`]: Family::Ipv6
155			pub const fn family(&self) -> Family {
156				$family
157			}
158
159			/// whether network represents a single host address
160			pub const fn is_host_address(&self) -> bool {
161				self.network_length() == self.family().len()
162			}
163
164			/// network mask: an pseudo address which has the first `network
165			/// length` bits set to 1 and the remaining to 0.
166			pub const fn mask(&self) -> $addr {
167				<$addr as PrivUnspecAddress>::_Tools::_network_mask(self.network_length)
168			}
169
170			/// check whether an address is contained in the network
171			pub const fn contains(&self, addr: &$addr) -> bool {
172				<$addr as PrivUnspecAddress>::_Tools::_prefix_match(
173					self.address,
174					*addr,
175					self.network_length,
176				)
177			}
178
179			pub(crate) const fn _range_pair(&self) -> $pair {
180				$pair {
181					first: self.first_address(),
182					second: self.last_address(),
183					network_length: self.network_length,
184				}
185			}
186		}
187
188		impl PrivCidr for $n {}
189
190		impl Cidr for $n {
191			type Address = $addr;
192
193			fn new(addr: $addr, len: u8) -> Result<Self, NetworkParseError> {
194				Self::new(addr, len)
195			}
196
197			fn new_host(addr: $addr) -> Self {
198				Self::new_host(addr)
199			}
200
201			fn iter(&self) -> InetIterator<$addr> {
202				self.iter()
203			}
204
205			fn first_address(&self) -> $addr {
206				self.first_address()
207			}
208
209			fn first(&self) -> $inet {
210				self.first()
211			}
212
213			fn last_address(&self) -> $addr {
214				self.last_address()
215			}
216
217			fn last(&self) -> $inet {
218				self.last()
219			}
220
221			fn network_length(&self) -> u8 {
222				self.network_length()
223			}
224
225			fn family(&self) -> Family {
226				self.family()
227			}
228
229			fn is_host_address(&self) -> bool {
230				self.is_host_address()
231			}
232
233			fn mask(&self) -> $addr {
234				self.mask()
235			}
236
237			fn contains(&self, addr: &$addr) -> bool {
238				self.contains(addr)
239			}
240		}
241
242		impl fmt::Debug for $n {
243			fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244				write!(f, "{:?}/{}", self.address, self.network_length)
245			}
246		}
247
248		impl fmt::Display for $n {
249			fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250				if f.alternate() || !self.is_host_address() {
251					write!(f, "{}/{}", self.address, self.network_length)?;
252				} else {
253					write!(f, "{}", self.address)?;
254				}
255				Ok(())
256			}
257		}
258
259		impl PartialOrd<$n> for $n {
260			fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
261				Some(self.cmp(other))
262			}
263		}
264
265		impl Ord for $n {
266			fn cmp(&self, other: &Self) -> core::cmp::Ordering {
267				self.address
268					.cmp(&other.address)
269					.then(self.network_length.cmp(&other.network_length))
270			}
271		}
272
273		impl FromStr for $n {
274			type Err = NetworkParseError;
275
276			fn from_str(s: &str) -> Result<$n, NetworkParseError> {
277				cidr_from_str(s)
278			}
279		}
280
281		/// Iterate over all the addresses in the CIDR.
282		impl IntoIterator for $n {
283			type IntoIter = $crate::InetIterator<$addr>;
284			type Item = $inet;
285
286			fn into_iter(self) -> Self::IntoIter {
287				self._range_pair().iter()
288			}
289		}
290	};
291}
292
293impl_cidr_for! {Ipv4Cidr : inet Ipv4Inet : addr Ipv4Addr : pair Ipv4InetPair : family Family::Ipv4}
294impl_cidr_for! {Ipv6Cidr : inet Ipv6Inet : addr Ipv6Addr : pair Ipv6InetPair : family Family::Ipv6}
295
296#[cfg(test)]
297mod tests {
298	use std::net::Ipv4Addr;
299
300	use crate::Ipv4Cidr;
301
302	#[test]
303	fn v4_ref_into_iter() {
304		let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
305		assert_eq!(
306			vec![
307				Ipv4Addr::new(1, 2, 3, 0),
308				Ipv4Addr::new(1, 2, 3, 1),
309				Ipv4Addr::new(1, 2, 3, 2),
310				Ipv4Addr::new(1, 2, 3, 3),
311			],
312			cidr.into_iter().addresses().collect::<Vec<_>>()
313		);
314	}
315
316	#[test]
317	fn v4_owned_into_iter() {
318		let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
319		assert_eq!(
320			vec![
321				Ipv4Addr::new(1, 2, 3, 0),
322				Ipv4Addr::new(1, 2, 3, 1),
323				Ipv4Addr::new(1, 2, 3, 2),
324				Ipv4Addr::new(1, 2, 3, 3),
325			],
326			cidr.into_iter().addresses().collect::<Vec<_>>()
327		);
328	}
329}