cidr/
internal_traits.rs

1use std::net::{
2	IpAddr,
3	Ipv4Addr,
4	Ipv6Addr,
5};
6
7use crate::num::NumberOfAddresses;
8
9/// Implemented for IPv4Addr, IPv6Addr AND IpAddr
10pub trait PrivUnspecAddress: Sized {
11	type _Tools;
12}
13
14/// seal `Cidr` trait
15pub trait PrivCidr {}
16
17/// seal `Inet` trait
18pub trait PrivInet {}
19
20/// seal `InetPair` trait
21pub trait PrivInetPair {
22	fn _covered_addresses(&self) -> NumberOfAddresses;
23	fn _inc_first(&mut self) -> bool;
24	fn _dec_second(&mut self) -> bool;
25}
26
27#[derive(Clone, Copy)]
28struct Ipv4OverflowingOp {
29	address: u32,
30	net_mask: u32,
31	host_mask: u32,
32}
33
34impl Ipv4OverflowingOp {
35	const fn new(address: Ipv4Addr, prefix_len: u8) -> Self {
36		let host_mask = Ipv4AddrTools::native_host_mask(prefix_len);
37		let net_mask = !host_mask;
38		let address: u32 = Ipv4AddrTools::to_native(address);
39		Self {
40			address,
41			net_mask,
42			host_mask,
43		}
44	}
45
46	const fn handle_result(self, (mut res, mut overflow): (u32, bool)) -> (Ipv4Addr, bool) {
47		let net_address = self.address & self.net_mask;
48		if res & self.net_mask != net_address {
49			// replace network in result with original network
50			res = (res & self.host_mask) | net_address;
51			overflow = true
52		}
53		(Ipv4AddrTools::from_native(res), overflow)
54	}
55}
56
57pub struct Ipv4AddrTools(());
58
59impl Ipv4AddrTools {
60	pub(crate) const fn to_native(ip: Ipv4Addr) -> u32 {
61		// const: u32::from
62		u32::from_be_bytes(ip.octets())
63	}
64
65	pub(crate) const fn from_native(ip: u32) -> Ipv4Addr {
66		// const: Ipv4Addr::from
67		let ip = ip.to_be_bytes();
68		Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3])
69	}
70
71	pub(crate) const fn native_host_mask(prefix_len: u8) -> u32 {
72		// const: unwrap_or(0)
73		if let Some(mask) = (!0u32).checked_shr(prefix_len as u32) {
74			mask
75		} else {
76			0
77		}
78	}
79
80	pub(crate) const fn _has_zero_host_part(address: Ipv4Addr, prefix_len: u8) -> bool {
81		let host_mask: u32 = Self::native_host_mask(prefix_len);
82		let addr_num = Self::to_native(address);
83		(addr_num & host_mask) == 0
84	}
85
86	pub(crate) const fn _overflowing_next(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) {
87		let op = Ipv4OverflowingOp::new(address, prefix_len);
88		op.handle_result(op.address.overflowing_add(1))
89	}
90
91	pub(crate) const fn _overflowing_inc_u32(
92		address: Ipv4Addr,
93		prefix_len: u8,
94		step_u32: u32,
95	) -> (Ipv4Addr, bool) {
96		let op = Ipv4OverflowingOp::new(address, prefix_len);
97		let (res, overflow) = op.handle_result(op.address.overflowing_add(step_u32));
98		(res, overflow)
99	}
100
101	pub(crate) const fn _overflowing_inc(
102		address: Ipv4Addr,
103		prefix_len: u8,
104		step: u128,
105	) -> (Ipv4Addr, bool) {
106		let step_u32 = step as u32;
107		let step_overflow = step_u32 as u128 != step;
108		let (res, overflow) = Self::_overflowing_inc_u32(address, prefix_len, step_u32);
109		(res, overflow || step_overflow)
110	}
111
112	pub(crate) const fn _overflowing_prev(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) {
113		let op = Ipv4OverflowingOp::new(address, prefix_len);
114		op.handle_result(op.address.overflowing_sub(1))
115	}
116
117	pub(crate) const fn _overflowing_dec_u32(
118		address: Ipv4Addr,
119		prefix_len: u8,
120		step_u32: u32,
121	) -> (Ipv4Addr, bool) {
122		let op = Ipv4OverflowingOp::new(address, prefix_len);
123		let (res, overflow) = op.handle_result(op.address.overflowing_sub(step_u32));
124		(res, overflow)
125	}
126
127	pub(crate) const fn _overflowing_dec(
128		address: Ipv4Addr,
129		prefix_len: u8,
130		step: u128,
131	) -> (Ipv4Addr, bool) {
132		let step_u32 = step as u32;
133		let step_overflow = step_u32 as u128 != step;
134		let (res, overflow) = Self::_overflowing_dec_u32(address, prefix_len, step_u32);
135		(res, overflow || step_overflow)
136	}
137
138	/*
139		pub(crate) const fn _overflowing_sub(address: Ipv4Addr, other: Ipv4Addr) -> (u128, bool) {
140			let (res, overflow) = Self::to_native(address).overflowing_sub(Self::to_native(other));
141			(res as u128, overflow)
142		}
143	*/
144
145	pub(crate) const fn _prefix_match(address: Ipv4Addr, other: Ipv4Addr, prefix_len: u8) -> bool {
146		let net_mask: u32 = !Self::native_host_mask(prefix_len);
147		(Self::to_native(address) & net_mask) == (Self::to_native(other) & net_mask)
148	}
149
150	pub(crate) const fn _network_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr {
151		let net_mask: u32 = !Self::native_host_mask(prefix_len);
152		Self::from_native(Self::to_native(address) & net_mask)
153	}
154
155	pub(crate) const fn _last_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr {
156		let host_mask: u32 = Self::native_host_mask(prefix_len);
157		Self::from_native(Self::to_native(address) | host_mask)
158	}
159
160	pub(crate) const fn _network_mask(prefix_len: u8) -> Ipv4Addr {
161		Self::from_native(!Self::native_host_mask(prefix_len))
162	}
163}
164
165impl PrivUnspecAddress for Ipv4Addr {
166	type _Tools = Ipv4AddrTools;
167}
168
169#[derive(Clone, Copy)]
170struct Ipv6OverflowingOp {
171	address: u128,
172	net_mask: u128,
173	host_mask: u128,
174}
175
176impl Ipv6OverflowingOp {
177	const fn new(address: Ipv6Addr, prefix_len: u8) -> Self {
178		let host_mask = Ipv6AddrTools::native_host_mask(prefix_len);
179		let net_mask = !host_mask;
180		let address: u128 = u128::from_be_bytes(address.octets());
181		Self {
182			address,
183			net_mask,
184			host_mask,
185		}
186	}
187
188	const fn handle_result(self, (mut res, mut overflow): (u128, bool)) -> (Ipv6Addr, bool) {
189		let net_address = self.address & self.net_mask;
190		if res & self.net_mask != net_address {
191			// replace network in result with original network
192			res = (res & self.host_mask) | net_address;
193			overflow = true
194		}
195		(Ipv6AddrTools::from_native(res), overflow)
196	}
197}
198
199pub struct Ipv6AddrTools(());
200
201impl Ipv6AddrTools {
202	pub(crate) const fn to_native(ip: Ipv6Addr) -> u128 {
203		// const: u128::from
204		u128::from_be_bytes(ip.octets())
205	}
206
207	pub(crate) const fn from_native(ip: u128) -> Ipv6Addr {
208		// const: Ipv6Addr::from
209		let ip = ip.to_be_bytes();
210		#[cfg(not(feature = "no_unsafe"))]
211		{
212			// Ipv6Addr is a newtype for the octets, it just doesn't have a constructor
213			// for it apart from Ipv6Addr::from, which isn't const
214			//
215			// this should be "safe":
216			// * if Ipv6Addr has a different size than [u8; 16] transmute won't compile
217			// * if the size matches, Ipv6Addr can't store any other data - it must store exactly the octets
218			// * it is unlikely std would ever store this in another endianness
219			unsafe { std::mem::transmute(ip) }
220		}
221		#[cfg(feature = "no_unsafe")]
222		{
223			// safe variant, but "slow"
224			Ipv6Addr::new(
225				u16::from_be_bytes([ip[0], ip[1]]),
226				u16::from_be_bytes([ip[2], ip[3]]),
227				u16::from_be_bytes([ip[4], ip[5]]),
228				u16::from_be_bytes([ip[6], ip[7]]),
229				u16::from_be_bytes([ip[8], ip[9]]),
230				u16::from_be_bytes([ip[10], ip[11]]),
231				u16::from_be_bytes([ip[12], ip[13]]),
232				u16::from_be_bytes([ip[14], ip[15]]),
233			)
234		}
235	}
236
237	pub(crate) const fn native_host_mask(prefix_len: u8) -> u128 {
238		// const: unwrap_or(0)
239		if let Some(mask) = (!0u128).checked_shr(prefix_len as u32) {
240			mask
241		} else {
242			0
243		}
244	}
245
246	pub(crate) const fn _has_zero_host_part(address: Ipv6Addr, prefix_len: u8) -> bool {
247		let host_mask: u128 = Self::native_host_mask(prefix_len);
248		let addr_num = Self::to_native(address);
249		(addr_num & host_mask) == 0
250	}
251
252	pub(crate) const fn _overflowing_next(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) {
253		let op = Ipv6OverflowingOp::new(address, prefix_len);
254		op.handle_result(op.address.overflowing_add(1))
255	}
256
257	pub(crate) const fn _overflowing_inc(
258		address: Ipv6Addr,
259		prefix_len: u8,
260		step: u128,
261	) -> (Ipv6Addr, bool) {
262		let op = Ipv6OverflowingOp::new(address, prefix_len);
263		op.handle_result(op.address.overflowing_add(step))
264	}
265
266	pub(crate) const fn _overflowing_prev(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) {
267		let op = Ipv6OverflowingOp::new(address, prefix_len);
268		op.handle_result(op.address.overflowing_sub(1))
269	}
270
271	pub(crate) const fn _overflowing_dec(
272		address: Ipv6Addr,
273		prefix_len: u8,
274		step: u128,
275	) -> (Ipv6Addr, bool) {
276		let op = Ipv6OverflowingOp::new(address, prefix_len);
277		op.handle_result(op.address.overflowing_sub(step))
278	}
279
280	/*
281		pub(crate) const fn _overflowing_sub(address: Ipv6Addr, other: Ipv6Addr) -> (u128, bool) {
282			Self::to_native(address).overflowing_sub(Self::to_native(other))
283		}
284	*/
285
286	pub(crate) const fn _prefix_match(address: Ipv6Addr, other: Ipv6Addr, prefix_len: u8) -> bool {
287		let net_mask: u128 = !Self::native_host_mask(prefix_len);
288		(Self::to_native(address) & net_mask) == (Self::to_native(other) & net_mask)
289	}
290
291	pub(crate) const fn _network_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
292		let net_mask: u128 = !Self::native_host_mask(prefix_len);
293		Self::from_native(Self::to_native(address) & net_mask)
294	}
295
296	pub(crate) const fn _last_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
297		let host_mask: u128 = Self::native_host_mask(prefix_len);
298		Self::from_native(Self::to_native(address) | host_mask)
299	}
300
301	pub(crate) const fn _network_mask(prefix_len: u8) -> Ipv6Addr {
302		Self::from_native(!Self::native_host_mask(prefix_len))
303	}
304}
305
306impl PrivUnspecAddress for Ipv6Addr {
307	type _Tools = Ipv6AddrTools;
308}
309
310pub struct IpAddrTools(());
311
312// we currently don't use the tools on IpAddr and related enums
313impl IpAddrTools {
314	/*
315		pub(crate) const fn _has_zero_host_part(address: IpAddr, prefix_len: u8) -> bool {
316			match address {
317				IpAddr::V4(a) => Ipv4AddrTools::_has_zero_host_part(a, prefix_len),
318				IpAddr::V6(a) => Ipv6AddrTools::_has_zero_host_part(a, prefix_len),
319			}
320		}
321
322		pub(crate) const fn _overflowing_next(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) {
323			match address {
324				IpAddr::V4(a) => {
325					let (res, of) = Ipv4AddrTools::_overflowing_next(a, prefix_len);
326					(IpAddr::V4(res), of)
327				},
328				IpAddr::V6(a) => {
329					let (res, of) = Ipv6AddrTools::_overflowing_next(a, prefix_len);
330					(IpAddr::V6(res), of)
331				},
332			}
333		}
334
335		pub(crate) const fn _overflowing_inc(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) {
336			match address {
337				IpAddr::V4(a) => {
338					let (res, of) = Ipv4AddrTools::_overflowing_inc(a, prefix_len, step);
339					(IpAddr::V4(res), of)
340				},
341				IpAddr::V6(a) => {
342					let (res, of) = Ipv6AddrTools::_overflowing_inc(a, prefix_len, step);
343					(IpAddr::V6(res), of)
344				},
345			}
346		}
347
348		pub(crate) const fn _overflowing_prev(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) {
349			match address {
350				IpAddr::V4(a) => {
351					let (res, of) = Ipv4AddrTools::_overflowing_prev(a, prefix_len);
352					(IpAddr::V4(res), of)
353				},
354				IpAddr::V6(a) => {
355					let (res, of) = Ipv6AddrTools::_overflowing_prev(a, prefix_len);
356					(IpAddr::V6(res), of)
357				},
358			}
359		}
360
361		pub(crate) const fn _overflowing_dec(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) {
362			match address {
363				IpAddr::V4(a) => {
364					let (res, of) = Ipv4AddrTools::_overflowing_dec(a, prefix_len, step);
365					(IpAddr::V4(res), of)
366				},
367				IpAddr::V6(a) => {
368					let (res, of) = Ipv6AddrTools::_overflowing_dec(a, prefix_len, step);
369					(IpAddr::V6(res), of)
370				},
371			}
372		}
373	*/
374
375	/*
376		pub(crate) const fn _overflowing_sub(address: IpAddr, other: IpAddr) -> (u128, bool) {
377			match (address, other) {
378				(IpAddr::V4(a), IpAddr::V4(other)) => Ipv4AddrTools::_overflowing_sub(a, other),
379				(IpAddr::V6(a), IpAddr::V6(other)) => Ipv6AddrTools::_overflowing_sub(a, other),
380				_ => (0, false),
381			}
382		}
383	*/
384
385	/*
386		fn _prefix_match(address: IpAddr, other: IpAddr, prefix_len: u8) -> bool {
387			match (address, other) {
388				(IpAddr::V4(a), IpAddr::V4(other)) => {
389					Ipv4AddrTools::_prefix_match(a, other, prefix_len)
390				},
391				(IpAddr::V6(a), IpAddr::V6(other)) => {
392					Ipv6AddrTools::_prefix_match(a, other, prefix_len)
393				},
394				_ => false,
395			}
396		}
397
398		pub(crate) const fn _network_address(address: IpAddr, prefix_len: u8) -> IpAddr {
399			match address {
400				IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_network_address(a, prefix_len)),
401				IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_network_address(a, prefix_len)),
402			}
403		}
404
405		fn _last_address(address: IpAddr, prefix_len: u8) -> IpAddr {
406			match address {
407				IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_last_address(a, prefix_len)),
408				IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_last_address(a, prefix_len)),
409			}
410		}
411	*/
412}
413
414impl PrivUnspecAddress for IpAddr {
415	type _Tools = IpAddrTools;
416}