mod version

module version

Simple version comparison for EasyBuild-style versions (X.Y.Z or year.Z).

This targets EasyBuild-style version strings, not full PEP 440 / semver. A version decomposes into an ordered run of tokens: maximal digit runs parse as Num, maximal alphabetic runs parse as Alpha (case-folded to lowercase), and any other character (dot, hyphen, underscore, …) is a separator that is dropped. Example: 1.0rc1 tokenizes to Num(1), Num(0), Alpha(rc), Num(1); 2025a tokenizes to Num(2025), Alpha(a).

Comparison walks both token sequences position by position. Two Num tokens compare numerically; two Alpha tokens compare lexicographically (so 2025a is before 2025b). A Num against a missing token pads the missing side with zero. An Alpha against a missing token is treated as a pre-release suffix (rc, alpha, beta, or a bare trailing letter) that sorts before the side with nothing more. Mixed Num versus Alpha at the same position is rare for EasyBuild; Num sorts before Alpha there for a total deterministic order.

Functions

fn cmp_version(a: &str, b: &str) -> Ordering

Order two version strings by their tokenized parts, digits before letters.

fn matches_req(version: &str, req: &str) -> bool

Version requirements accept exact equality, ordered comparisons, bare exact versions, and comma-separated conjunctions of those clauses.

A compound requirement matches only if every non-empty clause matches.

fn parse_requirement(req: &str) -> Result<Requirement, UnsupportedRequirement>

Parse a requirement, or say which clause is not expressible.

fn parse_version_parts(v: &str) -> Vec<Part>

Tokenize a version string into an ordered run of numeric and alphabetic parts, dropping separator characters. See the module docs for the exact tokenization and comparison rules.

Enums

enum Part

One tokenized piece of a version string: a numeric run or an alphabetic run (lowercased). Separator characters are dropped during tokenization and never produce a Part.

Num(u64)

A run of digits, compared numerically.

Alpha(String)

A run of letters, lowercased and compared lexically.

enum RequirementOp

One comparison in a requirement.

Exact

==X or a bare X.

NotEqual

!=X.

AtLeast

>=X.

Above

>X.

AtMost

<=X.

Below

<X.

Compatible

~=X, PEP 440 compatible release.

Caret

^X, Cargo caret.

Tilde

~X, Cargo tilde.

Implementations

impl RequirementOp

Structs and Unions

struct Requirement

A parsed requirement: a conjunction of clauses.

This is the single interpretation of a constraint string. The solver asks it what a candidate satisfies and the emitter asks it for a version, so the two cannot drift apart the way two hand-rolled readers of the same syntax did.

clauses: Vec<RequirementClause>

Every clause, all of which must hold.

Implementations

impl Requirement

Functions

fn exact(&self) -> Option<&str>

The exact version this requirement names, when it names one.

fn lower_bound(&self) -> Option<&str>

The lowest version this requirement admits, when it has a floor.

An extension entry needs one concrete version, and for a lower-bounded requirement the floor is the honest choice: it is the version the foreign metadata actually named.

fn matches(&self, version: &str) -> bool

Whether a version satisfies every clause.

struct RequirementClause

One parsed clause: an operator and the version it names.

op: RequirementOp

The comparison.

version: String

The version on the right-hand side.

struct UnsupportedRequirement

A clause no operator in the language covers.

Returned rather than silently answering “matches nothing”, which is what an unknown operator used to do: it fell through to a bare-exact comparison against a string starting with punctuation, so the version set came back empty and the dependency looked unsatisfiable.

clause: String

The clause that could not be parsed.

reason: String

Why, in one line.

Traits implemented

impl std::fmt::Display for UnsupportedRequirement
impl std::error::Error for UnsupportedRequirement