summaryrefslogtreecommitdiffstats
path: root/vendor/semver/src/eval.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/semver/src/eval.rs')
-rw-r--r--vendor/semver/src/eval.rs181
1 files changed, 181 insertions, 0 deletions
diff --git a/vendor/semver/src/eval.rs b/vendor/semver/src/eval.rs
new file mode 100644
index 000000000..e6e38949a
--- /dev/null
+++ b/vendor/semver/src/eval.rs
@@ -0,0 +1,181 @@
+use crate::{Comparator, Op, Version, VersionReq};
+
+pub(crate) fn matches_req(req: &VersionReq, ver: &Version) -> bool {
+ for cmp in &req.comparators {
+ if !matches_impl(cmp, ver) {
+ return false;
+ }
+ }
+
+ if ver.pre.is_empty() {
+ return true;
+ }
+
+ // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it
+ // will only be allowed to satisfy req if at least one comparator with the
+ // same major.minor.patch also has a prerelease tag.
+ for cmp in &req.comparators {
+ if pre_is_compatible(cmp, ver) {
+ return true;
+ }
+ }
+
+ false
+}
+
+pub(crate) fn matches_comparator(cmp: &Comparator, ver: &Version) -> bool {
+ matches_impl(cmp, ver) && (ver.pre.is_empty() || pre_is_compatible(cmp, ver))
+}
+
+fn matches_impl(cmp: &Comparator, ver: &Version) -> bool {
+ match cmp.op {
+ Op::Exact | Op::Wildcard => matches_exact(cmp, ver),
+ Op::Greater => matches_greater(cmp, ver),
+ Op::GreaterEq => matches_exact(cmp, ver) || matches_greater(cmp, ver),
+ Op::Less => matches_less(cmp, ver),
+ Op::LessEq => matches_exact(cmp, ver) || matches_less(cmp, ver),
+ Op::Tilde => matches_tilde(cmp, ver),
+ Op::Caret => matches_caret(cmp, ver),
+ #[cfg(no_non_exhaustive)]
+ Op::__NonExhaustive => unreachable!(),
+ }
+}
+
+fn matches_exact(cmp: &Comparator, ver: &Version) -> bool {
+ if ver.major != cmp.major {
+ return false;
+ }
+
+ if let Some(minor) = cmp.minor {
+ if ver.minor != minor {
+ return false;
+ }
+ }
+
+ if let Some(patch) = cmp.patch {
+ if ver.patch != patch {
+ return false;
+ }
+ }
+
+ ver.pre == cmp.pre
+}
+
+fn matches_greater(cmp: &Comparator, ver: &Version) -> bool {
+ if ver.major != cmp.major {
+ return ver.major > cmp.major;
+ }
+
+ match cmp.minor {
+ None => return false,
+ Some(minor) => {
+ if ver.minor != minor {
+ return ver.minor > minor;
+ }
+ }
+ }
+
+ match cmp.patch {
+ None => return false,
+ Some(patch) => {
+ if ver.patch != patch {
+ return ver.patch > patch;
+ }
+ }
+ }
+
+ ver.pre > cmp.pre
+}
+
+fn matches_less(cmp: &Comparator, ver: &Version) -> bool {
+ if ver.major != cmp.major {
+ return ver.major < cmp.major;
+ }
+
+ match cmp.minor {
+ None => return false,
+ Some(minor) => {
+ if ver.minor != minor {
+ return ver.minor < minor;
+ }
+ }
+ }
+
+ match cmp.patch {
+ None => return false,
+ Some(patch) => {
+ if ver.patch != patch {
+ return ver.patch < patch;
+ }
+ }
+ }
+
+ ver.pre < cmp.pre
+}
+
+fn matches_tilde(cmp: &Comparator, ver: &Version) -> bool {
+ if ver.major != cmp.major {
+ return false;
+ }
+
+ if let Some(minor) = cmp.minor {
+ if ver.minor != minor {
+ return false;
+ }
+ }
+
+ if let Some(patch) = cmp.patch {
+ if ver.patch != patch {
+ return ver.patch > patch;
+ }
+ }
+
+ ver.pre >= cmp.pre
+}
+
+fn matches_caret(cmp: &Comparator, ver: &Version) -> bool {
+ if ver.major != cmp.major {
+ return false;
+ }
+
+ let minor = match cmp.minor {
+ None => return true,
+ Some(minor) => minor,
+ };
+
+ let patch = match cmp.patch {
+ None => {
+ if cmp.major > 0 {
+ return ver.minor >= minor;
+ } else {
+ return ver.minor == minor;
+ }
+ }
+ Some(patch) => patch,
+ };
+
+ if cmp.major > 0 {
+ if ver.minor != minor {
+ return ver.minor > minor;
+ } else if ver.patch != patch {
+ return ver.patch > patch;
+ }
+ } else if minor > 0 {
+ if ver.minor != minor {
+ return false;
+ } else if ver.patch != patch {
+ return ver.patch > patch;
+ }
+ } else if ver.minor != minor || ver.patch != patch {
+ return false;
+ }
+
+ ver.pre >= cmp.pre
+}
+
+fn pre_is_compatible(cmp: &Comparator, ver: &Version) -> bool {
+ cmp.major == ver.major
+ && cmp.minor == Some(ver.minor)
+ && cmp.patch == Some(ver.patch)
+ && !cmp.pre.is_empty()
+}