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 host_pattern;
12pub(crate) mod ip;
13pub mod url;
14
15pub(crate) fn has_unique_elements<T>(iter: T) -> bool
17where
18 T: IntoIterator,
19 T::Item: Eq + Hash,
20{
21 let mut uniq = HashSet::new();
22 iter.into_iter().all(move |x| uniq.insert(x))
23}
24
25pub(crate) fn has_overlapping_ranges<T: Ord + Clone>(ranges: &[RangeInclusive<T>]) -> bool {
27 let mut sorted = ranges.to_vec();
28 sorted.sort_by(|a, b| a.start().cmp(b.start()));
29 for pair in sorted.windows(2) {
30 if let [a, b] = pair
31 && a.end() >= b.start()
32 {
33 return true;
34 }
35 }
36 false
37}
38
39#[inline]
41pub(crate) fn range_overlaps<T: Ord + Clone>(
42 ranges: &[RangeInclusive<T>],
43 range: &RangeInclusive<T>,
44 self_index: Option<usize>,
45) -> bool {
46 ranges
47 .iter()
48 .enumerate()
49 .filter_map(|(i, r)| {
50 self_index.map_or(Some(r), |index| if i != index { Some(r) } else { None })
51 })
52 .any(|r| r.start() <= range.end() && r.end() >= range.start())
53}
54
55pub trait IntoIpRange {
62 fn into_range(self) -> Option<RangeInclusive<IpAddr>>;
65
66 fn validate(ip_range: RangeInclusive<IpAddr>) -> Option<RangeInclusive<IpAddr>> {
73 let same_family = matches!(
74 (ip_range.start(), ip_range.end()),
75 (IpAddr::V4(_), IpAddr::V4(_)) | (IpAddr::V6(_), IpAddr::V6(_))
76 );
77 if same_family && ip_range.start() <= ip_range.end() {
78 Some(ip_range)
79 } else {
80 None
81 }
82 }
83}
84
85impl IntoIpRange for IpNet {
86 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
87 let start = self.network();
88 let end = self.broadcast();
89 Some(start..=end)
90 }
91}
92
93impl IntoIpRange for RangeInclusive<IpAddr> {
94 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
95 Self::validate(self)
96 }
97}
98
99impl IntoIpRange for (IpAddr, IpAddr) {
100 fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
101 Self::validate(self.0..=self.1)
102 }
103}