diff options
Diffstat (limited to 'third_party/rust/semver/src/impls.rs')
-rw-r--r-- | third_party/rust/semver/src/impls.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/third_party/rust/semver/src/impls.rs b/third_party/rust/semver/src/impls.rs new file mode 100644 index 0000000000..c3b6c60133 --- /dev/null +++ b/third_party/rust/semver/src/impls.rs @@ -0,0 +1,156 @@ +use crate::backport::*; +use crate::identifier::Identifier; +use crate::{BuildMetadata, Comparator, Prerelease, VersionReq}; +use core::cmp::Ordering; +use core::hash::{Hash, Hasher}; +use core::iter::FromIterator; +use core::ops::Deref; + +impl Default for Identifier { + fn default() -> Self { + Identifier::empty() + } +} + +impl Eq for Identifier {} + +impl Hash for Identifier { + fn hash<H: Hasher>(&self, hasher: &mut H) { + self.as_str().hash(hasher); + } +} + +impl Deref for Prerelease { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.identifier.as_str() + } +} + +impl Deref for BuildMetadata { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.identifier.as_str() + } +} + +impl PartialOrd for Prerelease { + fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { + Some(Ord::cmp(self, rhs)) + } +} + +impl PartialOrd for BuildMetadata { + fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { + Some(Ord::cmp(self, rhs)) + } +} + +impl Ord for Prerelease { + fn cmp(&self, rhs: &Self) -> Ordering { + match self.is_empty() { + true if rhs.is_empty() => return Ordering::Equal, + // A real release compares greater than prerelease. + true => return Ordering::Greater, + // Prerelease compares less than the real release. + false if rhs.is_empty() => return Ordering::Less, + false => {} + } + + let lhs = self.as_str().split('.'); + let mut rhs = rhs.as_str().split('.'); + + for lhs in lhs { + let rhs = match rhs.next() { + // Spec: "A larger set of pre-release fields has a higher + // precedence than a smaller set, if all of the preceding + // identifiers are equal." + None => return Ordering::Greater, + Some(rhs) => rhs, + }; + + let string_cmp = || Ord::cmp(lhs, rhs); + let is_ascii_digit = |b: u8| b.is_ascii_digit(); + let ordering = match ( + lhs.bytes().all(is_ascii_digit), + rhs.bytes().all(is_ascii_digit), + ) { + // Respect numeric ordering, for example 99 < 100. Spec says: + // "Identifiers consisting of only digits are compared + // numerically." + (true, true) => Ord::cmp(&lhs.len(), &rhs.len()).then_with(string_cmp), + // Spec: "Numeric identifiers always have lower precedence than + // non-numeric identifiers." + (true, false) => return Ordering::Less, + (false, true) => return Ordering::Greater, + // Spec: "Identifiers with letters or hyphens are compared + // lexically in ASCII sort order." + (false, false) => string_cmp(), + }; + + if ordering != Ordering::Equal { + return ordering; + } + } + + if rhs.next().is_none() { + Ordering::Equal + } else { + Ordering::Less + } + } +} + +impl Ord for BuildMetadata { + fn cmp(&self, rhs: &Self) -> Ordering { + let lhs = self.as_str().split('.'); + let mut rhs = rhs.as_str().split('.'); + + for lhs in lhs { + let rhs = match rhs.next() { + None => return Ordering::Greater, + Some(rhs) => rhs, + }; + + let is_ascii_digit = |b: u8| b.is_ascii_digit(); + let ordering = match ( + lhs.bytes().all(is_ascii_digit), + rhs.bytes().all(is_ascii_digit), + ) { + (true, true) => { + // 0 < 00 < 1 < 01 < 001 < 2 < 02 < 002 < 10 + let lhval = lhs.trim_start_matches('0'); + let rhval = rhs.trim_start_matches('0'); + Ord::cmp(&lhval.len(), &rhval.len()) + .then_with(|| Ord::cmp(lhval, rhval)) + .then_with(|| Ord::cmp(&lhs.len(), &rhs.len())) + } + (true, false) => return Ordering::Less, + (false, true) => return Ordering::Greater, + (false, false) => Ord::cmp(lhs, rhs), + }; + + if ordering != Ordering::Equal { + return ordering; + } + } + + if rhs.next().is_none() { + Ordering::Equal + } else { + Ordering::Less + } + } +} + +impl FromIterator<Comparator> for VersionReq { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = Comparator>, + { + let comparators = Vec::from_iter(iter); + VersionReq { comparators } + } +} |