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