Semver Requirement Matching

Parse semantic versions and requirement ranges, test whether a release satisfies a range, and pick the highest matching version.

RustData Integrity

Code

snippet
use semver::{Version, VersionReq};

fn matches(version: &str, requirement: &str) -> Result<bool, semver::Error> {
    let parsed = Version::parse(version)?;
    let requirement = VersionReq::parse(requirement)?;
    Ok(requirement.matches(&parsed))
}

fn best_match(versions: &[&str], requirement: &str) -> Result<Option<Version>, semver::Error> {
    let requirement = VersionReq::parse(requirement)?;
    let mut best: Option<Version> = None;
    for raw in versions {
        let version = Version::parse(raw)?;
        if !requirement.matches(&version) {
            continue;
        }
        if best.as_ref().map_or(true, |current| version > *current) {
            best = Some(version);
        }
    }
    Ok(best)
}

fn main() {
    let versions = ["1.2.0", "1.4.3", "2.0.0", "2.1.0-rc.1"];

    println!("1.9.0 in ^1.2: {:?}", matches("1.9.0", "^1.2"));
    println!("2.0.0 in ^1.2: {:?}", matches("2.0.0", "^1.2"));
    println!("rc.1 in ^2.1: {:?}", matches("2.1.0-rc.1", "^2.1"));
    println!("best in ~1.2: {:?}", best_match(&versions, "~1.2"));
    println!("invalid range: {}", matches("1.0.0", "not-a-version").is_err());
}