cidr/cidr/
direct.rs

1#[cfg(feature = "bitstring")]
2use bitstring::FixedBitString;
3
4use core::{
5	fmt,
6	net::{
7		Ipv4Addr,
8		Ipv6Addr,
9	},
10	str::FromStr,
11};
12
13use crate::{
14	errors::*,
15	internal_traits::{
16		PrivCidr,
17		PrivUnspecAddress,
18	},
19	Cidr,
20	Family,
21	InetIterator,
22	Ipv4Cidr,
23	Ipv4Inet,
24	Ipv4InetPair,
25	Ipv6Cidr,
26	Ipv6Inet,
27	Ipv6InetPair,
28};
29
30macro_rules! impl_cidr_for {
31	($n:ident : inet $inet:ident : addr $addr:ident : pair $pair:ident : family $family:expr) => {
32		#[cfg(feature = "bitstring")]
33		impl bitstring::BitString for $n {
34			fn get(&self, ndx: usize) -> bool {
35				self.address.get(ndx)
36			}
37
38			fn set(&mut self, ndx: usize, bit: bool) {
39				assert!(ndx < self.network_length as usize);
40				self.address.set(ndx, bit);
41			}
42
43			fn flip(&mut self, ndx: usize) {
44				assert!(ndx < self.network_length as usize);
45				self.address.flip(ndx);
46			}
47
48			fn len(&self) -> usize {
49				self.network_length as usize
50			}
51
52			fn clip(&mut self, len: usize) {
53				if len > 255 {
54					return;
55				}
56				self.address.set_false_from(len);
57				self.network_length = core::cmp::min(self.network_length, len as u8);
58			}
59
60			fn append(&mut self, bit: bool) {
61				self.address.set(self.network_length as usize, bit);
62				self.network_length += 1;
63			}
64
65			fn null() -> Self {
66				Self {
67					address: FixedBitString::new_all_false(),
68					network_length: 0,
69				}
70			}
71
72			fn shared_prefix_len(&self, other: &Self) -> usize {
73				let max_len = core::cmp::min(self.network_length, other.network_length) as usize;
74				core::cmp::min(
75					FixedBitString::shared_prefix_len(&self.address, &other.address),
76					max_len,
77				)
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				crate::parsers::parse_cidr(s, FromStr::from_str)
278			}
279		}
280
281		impl From<$addr> for $n {
282			fn from(address: $addr) -> Self {
283				Self::new_host(address)
284			}
285		}
286
287		/// Iterate over all the addresses in the CIDR.
288		impl IntoIterator for $n {
289			type IntoIter = $crate::InetIterator<$addr>;
290			type Item = $inet;
291
292			fn into_iter(self) -> Self::IntoIter {
293				self._range_pair().iter()
294			}
295		}
296	};
297}
298
299impl_cidr_for! {Ipv4Cidr : inet Ipv4Inet : addr Ipv4Addr : pair Ipv4InetPair : family Family::Ipv4}
300impl_cidr_for! {Ipv6Cidr : inet Ipv6Inet : addr Ipv6Addr : pair Ipv6InetPair : family Family::Ipv6}
301
302#[cfg(test)]
303mod tests {
304	use core::net::Ipv4Addr;
305
306	use crate::Ipv4Cidr;
307
308	fn check_list_iter<T: PartialEq + core::fmt::Debug>(
309		data: impl AsRef<[T]>,
310		iter: impl IntoIterator<Item = T>,
311	) {
312		let mut iter = iter.into_iter();
313		for elem in data.as_ref() {
314			assert_eq!(Some(elem), iter.next().as_ref());
315		}
316		assert_eq!(None, iter.next());
317	}
318
319	#[test]
320	fn v4_ref_into_iter() {
321		let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
322		check_list_iter(
323			[
324				Ipv4Addr::new(1, 2, 3, 0),
325				Ipv4Addr::new(1, 2, 3, 1),
326				Ipv4Addr::new(1, 2, 3, 2),
327				Ipv4Addr::new(1, 2, 3, 3),
328			],
329			cidr.into_iter().addresses(),
330		);
331	}
332
333	#[test]
334	fn v4_owned_into_iter() {
335		let cidr = Ipv4Cidr::new(Ipv4Addr::new(1, 2, 3, 0), 30).unwrap();
336		check_list_iter(
337			[
338				Ipv4Addr::new(1, 2, 3, 0),
339				Ipv4Addr::new(1, 2, 3, 1),
340				Ipv4Addr::new(1, 2, 3, 2),
341				Ipv4Addr::new(1, 2, 3, 3),
342			],
343			cidr.into_iter().addresses(),
344		);
345	}
346}