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() }