1use crate::backport::*;
2use crate::identifier::Identifier;
3use crate::{BuildMetadata, Comparator, Prerelease, VersionReq};
4use core::cmp::Ordering;
5use core::hash::{Hash, Hasher};
6use core::iter::FromIterator;
7use core::ops::Deref;
8
9impl Default for Identifier {
10 fn default() -> Self {
11 Identifier::empty()
12 }
13}
14
15impl Eq for Identifier {}
16
17impl Hash for Identifier {
18 fn hash<H: Hasher>(&self, hasher: &mut H) {
19 self.as_str().hash(hasher);
20 }
21}
22
23impl Deref for Prerelease {
24 type Target = str;
25
26 fn deref(&self) -> &Self::Target {
27 self.identifier.as_str()
28 }
29}
30
31impl Deref for BuildMetadata {
32 type Target = str;
33
34 fn deref(&self) -> &Self::Target {
35 self.identifier.as_str()
36 }
37}
38
39impl PartialOrd for Prerelease {
40 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
41 Some(self.cmp(rhs))
42 }
43}
44
45impl PartialOrd for BuildMetadata {
46 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
47 Some(self.cmp(rhs))
48 }
49}
50
51impl Ord for Prerelease {
52 fn cmp(&self, rhs: &Self) -> Ordering {
53 if self.identifier.ptr_eq(&rhs.identifier) {
54 return Ordering::Equal;
55 }
56
57 match self.is_empty() {
58 true => return Ordering::Greater,
60 false if rhs.is_empty() => return Ordering::Less,
62 false => {}
63 }
64
65 let lhs = self.as_str().split('.');
66 let mut rhs = rhs.as_str().split('.');
67
68 for lhs in lhs {
69 let rhs = match rhs.next() {
70 None => return Ordering::Greater,
74 Some(rhs) => rhs,
75 };
76
77 let string_cmp = || Ord::cmp(lhs, rhs);
78 let is_ascii_digit = |b: u8| b.is_ascii_digit();
79 let ordering = match (
80 lhs.bytes().all(is_ascii_digit),
81 rhs.bytes().all(is_ascii_digit),
82 ) {
83 (true, true) => Ord::cmp(&lhs.len(), &rhs.len()).then_with(string_cmp),
87 (true, false) => return Ordering::Less,
90 (false, true) => return Ordering::Greater,
91 (false, false) => string_cmp(),
94 };
95
96 if ordering != Ordering::Equal {
97 return ordering;
98 }
99 }
100
101 if rhs.next().is_none() {
102 Ordering::Equal
103 } else {
104 Ordering::Less
105 }
106 }
107}
108
109impl Ord for BuildMetadata {
110 fn cmp(&self, rhs: &Self) -> Ordering {
111 if self.identifier.ptr_eq(&rhs.identifier) {
112 return Ordering::Equal;
113 }
114
115 let lhs = self.as_str().split('.');
116 let mut rhs = rhs.as_str().split('.');
117
118 for lhs in lhs {
119 let rhs = match rhs.next() {
120 None => return Ordering::Greater,
121 Some(rhs) => rhs,
122 };
123
124 let is_ascii_digit = |b: u8| b.is_ascii_digit();
125 let ordering = match (
126 lhs.bytes().all(is_ascii_digit),
127 rhs.bytes().all(is_ascii_digit),
128 ) {
129 (true, true) => {
130 let lhval = lhs.trim_start_matches('0');
132 let rhval = rhs.trim_start_matches('0');
133 Ord::cmp(&lhval.len(), &rhval.len())
134 .then_with(|| Ord::cmp(lhval, rhval))
135 .then_with(|| Ord::cmp(&lhs.len(), &rhs.len()))
136 }
137 (true, false) => return Ordering::Less,
138 (false, true) => return Ordering::Greater,
139 (false, false) => Ord::cmp(lhs, rhs),
140 };
141
142 if ordering != Ordering::Equal {
143 return ordering;
144 }
145 }
146
147 if rhs.next().is_none() {
148 Ordering::Equal
149 } else {
150 Ordering::Less
151 }
152 }
153}
154
155impl FromIterator<Comparator> for VersionReq {
156 fn from_iter<I>(iter: I) -> Self
157 where
158 I: IntoIterator<Item = Comparator>,
159 {
160 let comparators = Vec::from_iter(iter);
161 VersionReq { comparators }
162 }
163}