1 use crate::backport::*;
2 use crate::identifier::Identifier;
3 use crate::{BuildMetadata, Comparator, Prerelease, VersionReq};
4 use core::cmp::Ordering;
5 use core::hash::{Hash, Hasher};
6 use core::iter::FromIterator;
7 use core::ops::Deref;
8 
9 impl Default for Identifier {
default() -> Self10     fn default() -> Self {
11         Identifier::empty()
12     }
13 }
14 
15 impl Eq for Identifier {}
16 
17 impl Hash for Identifier {
hash<H: Hasher>(&self, hasher: &mut H)18     fn hash<H: Hasher>(&self, hasher: &mut H) {
19         self.as_str().hash(hasher);
20     }
21 }
22 
23 impl Deref for Prerelease {
24     type Target = str;
25 
deref(&self) -> &Self::Target26     fn deref(&self) -> &Self::Target {
27         self.identifier.as_str()
28     }
29 }
30 
31 impl Deref for BuildMetadata {
32     type Target = str;
33 
deref(&self) -> &Self::Target34     fn deref(&self) -> &Self::Target {
35         self.identifier.as_str()
36     }
37 }
38 
39 impl PartialOrd for Prerelease {
partial_cmp(&self, rhs: &Self) -> Option<Ordering>40     fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
41         Some(Ord::cmp(self, rhs))
42     }
43 }
44 
45 impl PartialOrd for BuildMetadata {
partial_cmp(&self, rhs: &Self) -> Option<Ordering>46     fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
47         Some(Ord::cmp(self, rhs))
48     }
49 }
50 
51 impl Ord for Prerelease {
cmp(&self, rhs: &Self) -> Ordering52     fn cmp(&self, rhs: &Self) -> Ordering {
53         match self.is_empty() {
54             true if rhs.is_empty() => return Ordering::Equal,
55             // A real release compares greater than prerelease.
56             true => return Ordering::Greater,
57             // Prerelease compares less than the real release.
58             false if rhs.is_empty() => return Ordering::Less,
59             false => {}
60         }
61 
62         let lhs = self.as_str().split('.');
63         let mut rhs = rhs.as_str().split('.');
64 
65         for lhs in lhs {
66             let rhs = match rhs.next() {
67                 // Spec: "A larger set of pre-release fields has a higher
68                 // precedence than a smaller set, if all of the preceding
69                 // identifiers are equal."
70                 None => return Ordering::Greater,
71                 Some(rhs) => rhs,
72             };
73 
74             let string_cmp = || Ord::cmp(lhs, rhs);
75             let is_ascii_digit = |b: u8| b.is_ascii_digit();
76             let ordering = match (
77                 lhs.bytes().all(is_ascii_digit),
78                 rhs.bytes().all(is_ascii_digit),
79             ) {
80                 // Respect numeric ordering, for example 99 < 100. Spec says:
81                 // "Identifiers consisting of only digits are compared
82                 // numerically."
83                 (true, true) => Ord::cmp(&lhs.len(), &rhs.len()).then_with(string_cmp),
84                 // Spec: "Numeric identifiers always have lower precedence than
85                 // non-numeric identifiers."
86                 (true, false) => return Ordering::Less,
87                 (false, true) => return Ordering::Greater,
88                 // Spec: "Identifiers with letters or hyphens are compared
89                 // lexically in ASCII sort order."
90                 (false, false) => string_cmp(),
91             };
92 
93             if ordering != Ordering::Equal {
94                 return ordering;
95             }
96         }
97 
98         if rhs.next().is_none() {
99             Ordering::Equal
100         } else {
101             Ordering::Less
102         }
103     }
104 }
105 
106 impl Ord for BuildMetadata {
cmp(&self, rhs: &Self) -> Ordering107     fn cmp(&self, rhs: &Self) -> Ordering {
108         let lhs = self.as_str().split('.');
109         let mut rhs = rhs.as_str().split('.');
110 
111         for lhs in lhs {
112             let rhs = match rhs.next() {
113                 None => return Ordering::Greater,
114                 Some(rhs) => rhs,
115             };
116 
117             let is_ascii_digit = |b: u8| b.is_ascii_digit();
118             let ordering = match (
119                 lhs.bytes().all(is_ascii_digit),
120                 rhs.bytes().all(is_ascii_digit),
121             ) {
122                 (true, true) => {
123                     // 0 < 00 < 1 < 01 < 001 < 2 < 02 < 002 < 10
124                     let lhval = lhs.trim_start_matches('0');
125                     let rhval = rhs.trim_start_matches('0');
126                     Ord::cmp(&lhval.len(), &rhval.len())
127                         .then_with(|| Ord::cmp(lhval, rhval))
128                         .then_with(|| Ord::cmp(&lhs.len(), &rhs.len()))
129                 }
130                 (true, false) => return Ordering::Less,
131                 (false, true) => return Ordering::Greater,
132                 (false, false) => Ord::cmp(lhs, rhs),
133             };
134 
135             if ordering != Ordering::Equal {
136                 return ordering;
137             }
138         }
139 
140         if rhs.next().is_none() {
141             Ordering::Equal
142         } else {
143             Ordering::Less
144         }
145     }
146 }
147 
148 impl FromIterator<Comparator> for VersionReq {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = Comparator>,149     fn from_iter<I>(iter: I) -> Self
150     where
151         I: IntoIterator<Item = Comparator>,
152     {
153         let comparators = Vec::from_iter(iter);
154         VersionReq { comparators }
155     }
156 }
157