version-rs/README.md

91 lines
3.8 KiB
Markdown
Raw Permalink Normal View History

Contents
========
- [Introduction](#introduction)
- [Usage](#usage)
- [Internals](#internals)
## Introduction
This crate aims to provide methods for parsing, formatting, comparing and ordering
version numbers in most of the common formats in use today. In a perfect world, all
software be it free or non-free would use semantic versioning and strictly stick to
the rules governing semver. In the real world version numbers may be given using 1,
2, 3 or 4 digits and may or may not be consistent between releases. One release may
take the form "2.4" and be followed by a "2.4.1" release. A robust library for parsing
and comparing versions must be able to compare the two for ordering purposes in
order to determine that "2.4.1" is a newer patch release in the "2.4" series. In
addition, Pre-release numbering must be accounted for and the library must be able to
determine that an alpha is older than a beta, a full release newer than a release
candidate.
This library provides a `Version` struct which can handle 1 to 4 numerical fields for
semver-like versioning plus alpha, beta or rc prereleases, plus git revisions. It also
tracks machine architecture, and will return -ne if the version numbers match but not
the arch when doing comparisons.
## Usage
For the time being, this crate is not yet release on crates.io. It can be used from
git in your Cargo.toml file like so:
```Toml
version = { git = "https://codeberg.org/jeang3nie/version-rs" }
```
### Parsing and formatting
`Version` implements `Display` and `FromStr`.
```
use version::{prelude::VersionError, Version};
fn main() -> Result::<(), VersionError> {
let vstr = "2.0.3_alpha1-aarch64";
let v: Version = vstr.parse()?;
assert_eq!(v.to_string(), vstr);
Ok(())
}
```
### Comparison
`Version` implements `PartialOrd` and `PartialEq`
```
use version::{prelude::VersionError, Version};
fn main() -> Result<(), VersionError> {
let va: Version = "1.0-x86_64".parse()?;
let vb: Version = "1.0.0-x86_64".parse()?;
let vc: Version = "1.0_rc4-x86_64".parse()?;
let vd: Version = "1.0-riscv64".parse()?;
assert_eq!(va, vb);
assert!(vb > vc);
assert_ne!(va, vd);
Ok(())
}
```
## Internals
When comparing version numbers for equality or ordering, the semver-like versions
are first encoded into a single `u64`, allowing for an easy comparison using the
`==`, `<` and `>` operators. This is done using some simple bit shifting logic.
The twelve least significant bits, or LSB, are given for any numerical component to
the prerelease number. The next four bits are used as bitflags representing the
type of prerelease, which may be `PreRelease::None` (which gets the highest bit in
the set).
2024-01-31 22:59:31 -05:00
| bits | 15 | 14 | 13 | 12 | 11 | 0-10 |
| ---- | --- | --- | --- | --- | --- | ---- |
| use | PreRelease::None | PreRelease::Rc | PreRelease::Beta | PreRelease::Alpha | PreRelease::Git | Numerical component |
2024-01-31 22:59:31 -05:00
This gives an upper limit of 2^11 or 2048 for the numerical component of the prerelease,
and 2^12 or 4096 for each SemVer field, which is more
than adequate. By placing the flags in this way, alpha releases will always be lower
than beta, which will be lower than release candidates, which will be lower than no
pre-release versions.
The fields major, minor, patch and build each get 12 of the remaining bits, arranged
so that major is the most significant followed by minor, patch and build.
| bits | 52-63 | 40-51 | 28-39 | 16-27 |
| ---- | ----- | ----- | ----- | ----- |
| use | major | minor | patch | build |
In this way, version "1.0" will be equal to "1.0.0" and less than "1.0.1" in a simple
comparison operation, without requiring complex match statements.
In this way the traits PartialEq, Eq, PartialOrd and Ord can be implemented in a
straightforward and concise manner for the various versioning schemes.