summaryrefslogtreecommitdiffstats
path: root/third_party/rust/semver/src/impls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/semver/src/impls.rs')
-rw-r--r--third_party/rust/semver/src/impls.rs156
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 }
+ }
+}