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 self_index: Option<usize>,
44) -> bool {
45 ranges
46 .iter()
47 .enumerate()
48 .filter_map(|(i, r)| {
49 self_index.map_or(Some(r), |index| if i != index { Some(r) } else { None })
50 })
51 .any(|r| r.start() <= range.end() && r.end() >= range.start())
52}
53
54pub trait IntoIpRange {
56 fn into_range(self) -> Option<RangeInclusive<IpAddr>>;
58
59 fn validate(ip_range: RangeInclusive<IpAddr>) -> Option<RangeInclusive<IpAddr>> {
61 if ip_range.start() <= ip_range.end() {
62 Some(ip_range)
63 } else {
64 None
65 }
66 }
67}
68
69impl IntoIpRange for IpNet {
70 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
71 let start = self.network();
72 let end = self.broadcast();
73 Some(start..=end)
74 }
75}
76
77impl IntoIpRange for RangeInclusive<IpAddr> {
78 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
79 Self::validate(self)
80 }
81}
82
83impl IntoIpRange for (IpAddr, IpAddr) {
84 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
85 Self::validate(self.0..=self.1)
86 }
87}