ip/concrete/prefix/
ord.rs1use core::cmp::Ordering::{self, Equal, Greater, Less};
2
3use super::{Address, Prefix};
4use crate::traits::Afi;
5
6#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
8pub enum PrefixOrdering<A: Afi> {
9 Equal,
11 Subprefix(Prefix<A>),
13 Superprefix(Prefix<A>),
15 Divergent(Prefix<A>),
17}
18
19impl<A: Afi> Prefix<A> {
20 pub fn compare(&self, other: &Self) -> PrefixOrdering<A> {
23 let common = self.common_with(other);
24 match (
25 self.length().cmp(&common.length()),
26 other.length().cmp(&common.length()),
27 ) {
28 (Equal, Equal) => PrefixOrdering::Equal,
29 (Equal, Greater) => PrefixOrdering::Subprefix(common),
30 (Greater, Equal) => PrefixOrdering::Superprefix(common),
31 (Greater, Greater) => PrefixOrdering::Divergent(common),
32 (Less, _) | (_, Less) => {
33 unreachable!("common must be shorter than both prefixes")
34 }
35 }
36 }
37}
38
39impl<A: Afi> PartialOrd<Self> for Prefix<A> {
40 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
41 match self.compare(other) {
42 PrefixOrdering::Equal => Some(Equal),
43 PrefixOrdering::Subprefix(_) => Some(Greater),
44 PrefixOrdering::Superprefix(_) => Some(Less),
45 PrefixOrdering::Divergent(_) => None,
46 }
47 }
48}
49
50impl<A: Afi> PartialEq<Address<A>> for Prefix<A> {
51 fn eq(&self, other: &Address<A>) -> bool {
52 self.eq(&Self::from(*other))
53 }
54}
55
56impl<A: Afi> PartialOrd<Address<A>> for Prefix<A> {
57 fn partial_cmp(&self, other: &Address<A>) -> Option<Ordering> {
58 self.partial_cmp(&Self::from(*other))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use crate::{Ipv4, Ipv6};
66
67 mod ipv4 {
68 use super::*;
69
70 #[test]
71 fn equal() {
72 let x = "10.0.0.0/8".parse::<Prefix<Ipv4>>().unwrap();
73 let y = "10.0.0.0/8".parse::<Prefix<Ipv4>>().unwrap();
74 assert!(x == y);
75 }
76
77 #[test]
78 fn lt() {
79 let x = "10.0.0.0/16".parse::<Prefix<Ipv4>>().unwrap();
80 let y = "10.0.0.0/8".parse::<Prefix<Ipv4>>().unwrap();
81 assert!(x < y);
82 }
83
84 #[test]
85 fn gt() {
86 let x = "10.0.0.0/16".parse::<Prefix<Ipv4>>().unwrap();
87 let y = "10.0.0.0/24".parse::<Prefix<Ipv4>>().unwrap();
88 assert!(x > y);
89 }
90
91 #[test]
92 fn divergent() {
93 let x = "10.0.0.0/16".parse::<Prefix<Ipv4>>().unwrap();
94 let y = "10.1.0.0/16".parse::<Prefix<Ipv4>>().unwrap();
95 assert!(x.partial_cmp(&y).is_none());
96 }
97 }
98
99 mod ipv6 {
100 use super::*;
101
102 #[test]
103 fn equal() {
104 let x = "2001:db8::/32".parse::<Prefix<Ipv6>>().unwrap();
105 let y = "2001:db8::/32".parse::<Prefix<Ipv6>>().unwrap();
106 assert!(x == y);
107 }
108
109 #[test]
110 fn lt() {
111 let x = "2001:db8::/48".parse::<Prefix<Ipv6>>().unwrap();
112 let y = "2001:db8::/32".parse::<Prefix<Ipv6>>().unwrap();
113 assert!(x < y);
114 }
115
116 #[test]
117 fn gt() {
118 let x = "2001:db8::/48".parse::<Prefix<Ipv6>>().unwrap();
119 let y = "2001:db8::/64".parse::<Prefix<Ipv6>>().unwrap();
120 assert!(x > y);
121 }
122
123 #[test]
124 fn divergent() {
125 let x = "2001:db8:f::/48".parse::<Prefix<Ipv6>>().unwrap();
126 let y = "2001:db8:a::/48".parse::<Prefix<Ipv6>>().unwrap();
127 assert!(x.partial_cmp(&y).is_none());
128 }
129 }
130}