1use std::collections::HashSet;
4use std::hash::Hash;
5use std::net::IpAddr;
6use std::ops::RangeInclusive;
7
8use ipnet::IpNet;
9
10pub mod authority;
11pub(crate) mod ip;
12pub mod url;
13
14pub(crate) fn has_unique_elements<T>(iter: T) -> bool
16where
17 T: IntoIterator,
18 T::Item: Eq + Hash,
19{
20 let mut uniq = HashSet::new();
21 iter.into_iter().all(move |x| uniq.insert(x))
22}
23
24pub(crate) fn has_overlapping_ranges<T: Ord + Clone>(ranges: &[RangeInclusive<T>]) -> bool {
26 let mut sorted = ranges.to_vec();
27 sorted.sort_by(|a, b| a.start().cmp(b.start()));
28 for pair in sorted.windows(2) {
29 if let [a, b] = pair {
30 if a.end() >= b.start() {
31 return true;
32 }
33 }
34 }
35 false
36}
37
38#[inline]
40pub(crate) fn range_overlaps<T: Ord + Clone>(
41 ranges: &[RangeInclusive<T>],
42 range: &RangeInclusive<T>,
43) -> bool {
44 ranges
45 .iter()
46 .any(|r| r.start() <= range.end() && r.end() >= range.start())
47}
48
49pub trait IntoIpRange {
51 fn into_range(self) -> Option<RangeInclusive<IpAddr>>;
53
54 fn validate(ip_range: RangeInclusive<IpAddr>) -> Option<RangeInclusive<IpAddr>> {
56 if ip_range.start() <= ip_range.end() {
57 Some(ip_range)
58 } else {
59 None
60 }
61 }
62}
63
64impl IntoIpRange for IpNet {
65 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
66 let start = self.network();
67 let end = self.broadcast();
68 Some(start..=end)
69 }
70}
71
72impl IntoIpRange for RangeInclusive<IpAddr> {
73 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
74 Self::validate(self)
75 }
76}
77
78impl IntoIpRange for (IpAddr, IpAddr) {
79 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
80 Self::validate(self.0..=self.1)
81 }
82}