semver

repository·master·Indexed 20 days ago

https://github.com/dtolnay/semver

A parser and evaluator for Semantic Versioning (SemVer) specifically designed to implement Cargo's interpretation of the specification. It provides tools to parse and compare versions using the Version struct, evaluate version requirements via VersionReq, and manage pre-release identifiers and build metadata.

Tokens
2.8K
Snippets
10
Records
12
Agent score
69%

What's inside semver

  1. Understand the scope of the semver crate

    master

    The semver crate is specifically designed to implement Cargo's interpretation of Semantic Versioning.

    While many ecosystems (npm, RubyGems, Composer, etc.) follow SemVer, they often differ in implementation details. This crate follows the specific implementation choices made by Cargo. If you are working with version numbers from a different ecosystem, you should use a library tailored to that ecosystem instead.

    For details on how Cargo interprets versioning, refer to the [Specifying Dependencies] chapter of the Cargo reference.

  2. Parse and match Semantic Version requirements

    master

    You can use VersionReq to parse version requirement strings (e.g., ">=1.2.3, <1.8.0") and then use the .matches(&Version) method to check if a specific Version satisfies that requirement.

    Note that pre-release versions (like alpha.1) are handled via the Prerelease type and may affect matching logic depending on the requirement string.

    use semver::{BuildMetadata, Prerelease, Version, VersionReq};
    
    fn main() {
        let req = VersionReq::parse(">=1.2.3, <1.8.0").unwrap();
    
        // Check whether this requirement matches version 1.2.3-alpha.1 (no)
        let version = Version {
            major: 1,
            minor: 2,
            patch: 3,
            pre: Prerelease::new("alpha.1").unwrap(),
            build: BuildMetadata::EMPTY,
        };
        assert!(!req.matches(&version));
    
        // Check whether it matches 1.3.0 (yes it does)
        let version = Version::parse("1.3.0").unwrap();
        assert!(req.matches(&version));
    }
  3. Handle parsing errors in semver

    master

    When parsing versions, requirements, or comparators, the library returns a semver::Error. This error can be printed to provide human-readable feedback about where and why the parsing failed.

    Common error scenarios include:

    • Empty strings
    • Unexpected characters in specific positions (Major, Minor, Patch, Pre, or Build)
    • Leading zeros in numeric identifiers
    • Integer overflows
    • Illegal characters in identifiers
    • Excessive number of comparators in a requirement
    use semver::Version;
    
    fn main() {
        // Example of an error due to an invalid character in the minor version
        let err = Version::parse("1.q.r").unwrap_err();
    
        // Output: "unexpected character 'q' while parsing minor version number"
        eprintln!("{}", err);
    }
  4. Manage build metadata with `BuildMetadata`

    master

    The BuildMetadata struct represents the optional part of a SemVer version following the plus sign (e.g., +build.123).

    Key Operations

    • Creation: BuildMetadata::new("text") parses build metadata.
    • Empty State: BuildMetadata::EMPTY represents no build metadata.
    • Inspection: is_empty() checks if metadata is present; as_str() returns the string representation.

    Important Behavior

    • Ignored in Matching: Build metadata is completely ignored when evaluating VersionReq or checking if a version matches a Comparator.
    • Precedence: While ignored for version matching, build metadata is included in the total ordering of Version (via Ord). It is compared lexicographically by dot-separated components, where numeric components are compared numerically and others via ASCII sort order.
    use semver::BuildMetadata;
    
    let meta = BuildMetadata::new("20230101").unwrap();
    assert_eq!(meta.as_str(), "20230101");
  5. Parse a comparator string

    master

    A Comparator represents a single constraint within a version requirement (e.g., >=1.0.0). You can parse these strings using Comparator::parse (via FromStr).

    use semver::Comparator;
    use std::str::FromStr;
    
    fn main() {
        let comp = Comparator::parse(">=1.2.3").unwrap();
    }
  6. Manage pre-release identifiers with `Prerelease`

    master

    The Prerelease struct represents the optional part of a SemVer version following the hyphen (e.g., -alpha.1).

    Key Operations

    • Creation: Prerelease::new("text") parses a pre-release string.
    • Empty State: Prerelease::EMPTY represents no pre-release.
    • Inspection: is_empty() checks if a pre-release is present; as_str() returns the string representation.

    Precedence Rules

    Pre-releases have a total order based on dot-separated components:

    1. Numeric identifiers (only digits) are compared numerically (alpha.2 < alpha.11).
    2. Non-numeric identifiers (letters/hyphens) are compared via ASCII sort order (alpha.beta < alpha.rc).
    3. Numeric vs Non-numeric: Any numeric identifier is always less than any non-numeric identifier (alpha.1 < alpha.x).
    4. Release vs Pre-release: A version with a pre-release is always less than the same version without one (1.0.0-alpha < 1.0.0).
    use semver::Prerelease;
    
    let pre = Prerelease::new("alpha.1").unwrap();
    assert!(!pre.is_empty());
    assert_eq!(pre.as_str(), "alpha.1");
  7. Parse and compare SemVer versions with `Version`

    master

    The Version struct represents a Semantic Version (e.g., 1.2.3-alpha.1+build.100). It follows Cargo's interpretation of the SemVer spec.

    Key Operations

    • Creation: Use Version::new(major, minor, patch) for a basic version or Version::parse("text") to parse from a string.
    • Precedence Comparison: Use Version::cmp_precedence(&self, other: &Self) to compare versions based on major, minor, patch, and pre-release identifiers, while ignoring build metadata. This is the standard way to determine version precedence.
    • Total Ordering: Implementing Ord on Version performs a total ordering that includes comparing build metadata.

    Syntax Rules

    • Major, minor, and patch must be u64 integers.
    • Leading zeros are forbidden in numeric components.
    • Whitespace is not allowed.
    use semver::Version;
    
    // Parsing from string
    let v = Version::parse("1.2.3-alpha.1+build.100").unwrap();
    
    // Comparing precedence (ignores build metadata)
    let v1 = Version::parse("1.2.0+abc").unwrap();
    let v2 = Version::parse("1.2.0+xyz").unwrap();
    assert_eq!(v1.cmp_precedence(&v2), std::cmp::Ordering::Equal);
    
    // Total ordering (includes build metadata)
    assert!(v1 < v2); // Depending on lexicographical order of metadata
  8. Parse a version requirement string

    master

    Use VersionReq::parse (via FromStr) to convert a semantic version requirement string (like ^1.2.3 or >=2.0.0) into a VersionReq struct.

    Version requirements can include wildcards (e.g., *, x, X) and comma-separated lists of comparators (e.g., >1.0.0, <2.0.0).

    use semver::VersionReq;
    use std::str::FromStr;
    
    fn main() {
        let req = VersionReq::parse("^1.2.3").unwrap();
        let version = semver::Version::parse("1.2.3").unwrap();
        assert!(req.matches(&version));
    }
  9. Evaluate version requirements with `VersionReq`

    master

    A VersionReq describes a set of constraints (e.g., >=1.2.3, <1.8.0) that a Version must satisfy. It is the mechanism used by Cargo to specify dependency ranges.

    Key Operations

    • Creation: Use VersionReq::parse("text") to parse a requirement string.
    • Matching: Use req.matches(&version) to check if a specific Version satisfies the requirement.
    • Wildcard: VersionReq::STAR (or VersionReq::default()) represents *, which matches any version except pre-release versions (unless the requirement explicitly includes a pre-release component).

    Syntax Rules

    • Requirements are comma-separated comparators.
    • Build metadata in the requirement string is ignored.
    • Whitespace is allowed around commas and operators, but not within the version numbers themselves.
    use semver::{Version, VersionReq};
    
    let req = VersionReq::parse(">=1.2.3, <1.8.0").unwrap();
    let version = Version::parse("1.3.0").unwrap();
    
    assert!(req.matches(&version));
  10. Parse a SemVer version string

    master

    You can parse a semantic version string into a Version struct by implementing the FromStr trait. This is useful for converting raw strings into structured version data.

    If parsing fails, it returns a semver::Error which provides details about what went wrong (e.g., unexpected characters or invalid segments).

    use semver::Version;
    use std::str::FromStr;
    
    fn main() {
        let version = Version::parse("1.2.3").unwrap();
        assert_eq!(version.major(), 1);
        assert_eq!(version.minor(), 2);
        assert_eq!(version.patch(), 3);
    }
  11. Understand SemVer comparison operators (`Op`)

    master

    The Op enum defines the comparison operators used within VersionReq and Comparator.

    OperatorDescription
    Exact (=)Exactly the version specified. =I.J is equivalent to >=I.J.0, <I.(J+1).0
    Greater (>)Greater than the version. >I.J is equivalent to >=I.(J+1).0
    GreaterEq (>=)Greater than or equal to the version. >I.J is equivalent to >=I.J.0
    Less (<)Less than the version. <I.J is equivalent to <I.J.0
    LessEq (<=)Less than or equal to the version. <=I.J is equivalent to <I.(J+1).0
    Tilde (~)Patch updates. ~I.J.K is equivalent to >=I.J.K, <I.(J+1).0
    Caret (^)Compatible updates. Allows parts right of the first non-zero part to increase. For I > 0, ^I.J.K is >=I.J.K, <(I+1).0.0
    Wildcard (*)I.J.* is equivalent to =I.J. I.* is equivalent to =I