http_acl/
utils.rs

1//! Utility functions for the http-acl crate.
2
3use 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
14// Taken from https://stackoverflow.com/a/46767732
15pub(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
24/// Helper function to check if any ranges in a slice overlap.
25pub(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/// Checks if a range overlaps with any existing ranges in a slice.
39#[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
49/// Converts a type into an IP range.
50pub trait IntoIpRange {
51    /// Converts the type into an IP range.
52    fn into_range(self) -> Option<RangeInclusive<IpAddr>>;
53
54    /// Validates the IP range.
55    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}