Skip to main content

mm1_address/
address_range.rs

1use std::fmt;
2
3use crate::address::Address;
4use crate::subnet::{NetAddress, NetMask};
5
6/// A range of addresses corresponding to some [`NetAddress`].
7///
8/// The only way to create an instance of [`AddressRange`] is from a
9/// [`NetAddress`] or [`Address`], thus only valid ranges are represented by
10/// this type.
11///
12/// This type can be used as a key in a key-value collection that uses `Ord` for
13/// its keys. (**NB:** the equality is defined as "if the ranges overlap — they
14/// are equal")
15#[derive(Debug, Clone, Copy)]
16pub struct AddressRange {
17    lo: Address,
18    hi: Address,
19}
20
21impl AddressRange {
22    pub fn lo(&self) -> Address {
23        self.lo
24    }
25
26    pub fn hi(&self) -> Address {
27        self.hi
28    }
29}
30
31impl From<Address> for AddressRange {
32    fn from(addr: Address) -> Self {
33        Self { lo: addr, hi: addr }
34    }
35}
36impl From<NetAddress> for AddressRange {
37    fn from(net: NetAddress) -> Self {
38        let lo = net.address;
39        let hi = Address::from_u64(net.address.into_u64() | !net.mask.into_u64());
40
41        Self { lo, hi }
42    }
43}
44
45impl From<AddressRange> for NetAddress {
46    fn from(range: AddressRange) -> Self {
47        let AddressRange { lo, hi } = range;
48        let address = lo;
49        let mask_bits = !(lo.into_u64() ^ hi.into_u64());
50        let mask = NetMask::try_from(mask_bits.leading_ones() as u8).expect("should be fine");
51        Self { address, mask }
52    }
53}
54
55impl Ord for AddressRange {
56    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
57        use std::cmp::Ordering::*;
58
59        assert!(self.lo <= self.hi);
60        assert!(other.lo <= other.hi);
61
62        match (self.hi.cmp(&other.lo), self.lo.cmp(&other.hi)) {
63            (Less, Less) => Less,
64            (Greater, Greater) => Greater,
65            (..) => Equal,
66        }
67    }
68}
69impl PartialEq for AddressRange {
70    fn eq(&self, other: &Self) -> bool {
71        Ord::cmp(self, other).is_eq()
72    }
73}
74impl Eq for AddressRange {}
75impl PartialOrd for AddressRange {
76    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
77        Some(Ord::cmp(self, other))
78    }
79}
80
81impl fmt::Display for AddressRange {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "{}-{}", self.lo, self.hi)
84    }
85}