diff options
Diffstat (limited to 'third_party/rust/semver/src/lib.rs')
-rw-r--r-- | third_party/rust/semver/src/lib.rs | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/third_party/rust/semver/src/lib.rs b/third_party/rust/semver/src/lib.rs new file mode 100644 index 0000000000..32ed96d1ca --- /dev/null +++ b/third_party/rust/semver/src/lib.rs @@ -0,0 +1,533 @@ +//! [![github]](https://github.com/dtolnay/semver) [![crates-io]](https://crates.io/crates/semver) [![docs-rs]](https://docs.rs/semver) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//! <br> +//! +//! A parser and evaluator for Cargo's flavor of Semantic Versioning. +//! +//! Semantic Versioning (see <https://semver.org>) is a guideline for how +//! version numbers are assigned and incremented. It is widely followed within +//! the Cargo/crates.io ecosystem for Rust. +//! +//! <br> +//! +//! # Example +//! +//! ``` +//! 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)); +//! } +//! ``` +//! +//! <br><br> +//! +//! # Scope of this crate +//! +//! Besides Cargo, several other package ecosystems and package managers for +//! other languages also use SemVer: RubyGems/Bundler for Ruby, npm for +//! JavaScript, Composer for PHP, CocoaPods for Objective-C... +//! +//! The `semver` crate is specifically intended to implement Cargo's +//! interpretation of Semantic Versioning. +//! +//! Where the various tools differ in their interpretation or implementation of +//! the spec, this crate follows the implementation choices made by Cargo. If +//! you are operating on version numbers from some other package ecosystem, you +//! will want to use a different semver library which is appropriate to that +//! ecosystem. +//! +//! The extent of Cargo's SemVer support is documented in the *[Specifying +//! Dependencies]* chapter of the Cargo reference. +//! +//! [Specifying Dependencies]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html + +#![doc(html_root_url = "https://docs.rs/semver/1.0.16")] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![cfg_attr(all(not(feature = "std"), not(no_alloc_crate)), no_std)] +#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))] +#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))] +#![cfg_attr(no_str_strip_prefix, allow(unstable_name_collisions))] +#![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::doc_markdown, + clippy::items_after_statements, + clippy::manual_map, + clippy::match_bool, + clippy::missing_errors_doc, + clippy::must_use_candidate, + clippy::needless_doctest_main, + clippy::option_if_let_else, + clippy::ptr_as_ptr, + clippy::redundant_else, + clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7324 + clippy::similar_names, + clippy::unnested_or_patterns, + clippy::unseparated_literal_suffix, + clippy::wildcard_imports +)] + +#[cfg(not(no_alloc_crate))] +extern crate alloc; + +mod backport; +mod display; +mod error; +mod eval; +mod identifier; +mod impls; +mod parse; + +#[cfg(feature = "serde")] +mod serde; + +use crate::alloc::vec::Vec; +use crate::identifier::Identifier; +use core::str::FromStr; + +#[allow(unused_imports)] +use crate::backport::*; + +pub use crate::parse::Error; + +/// **SemVer version** as defined by <https://semver.org>. +/// +/// # Syntax +/// +/// - The major, minor, and patch numbers may be any integer 0 through u64::MAX. +/// When representing a SemVer version as a string, each number is written as +/// a base 10 integer. For example, `1.0.119`. +/// +/// - Leading zeros are forbidden in those positions. For example `1.01.00` is +/// invalid as a SemVer version. +/// +/// - The pre-release identifier, if present, must conform to the syntax +/// documented for [`Prerelease`]. +/// +/// - The build metadata, if present, must conform to the syntax documented for +/// [`BuildMetadata`]. +/// +/// - Whitespace is not allowed anywhere in the version. +/// +/// # Total ordering +/// +/// Given any two SemVer versions, one is less than, greater than, or equal to +/// the other. Versions may be compared against one another using Rust's usual +/// comparison operators. +/// +/// - The major, minor, and patch number are compared numerically from left to +/// right, lexicographically ordered as a 3-tuple of integers. So for example +/// version `1.5.0` is less than version `1.19.0`, despite the fact that +/// "1.19.0" < "1.5.0" as ASCIIbetically compared strings and 1.19 < 1.5 +/// as real numbers. +/// +/// - When major, minor, and patch are equal, a pre-release version is +/// considered less than the ordinary release: version `1.0.0-alpha.1` is +/// less than version `1.0.0`. +/// +/// - Two pre-releases of the same major, minor, patch are compared by +/// lexicographic ordering of dot-separated components of the pre-release +/// string. +/// +/// - Identifiers consisting of only digits are compared +/// numerically: `1.0.0-pre.8` is less than `1.0.0-pre.12`. +/// +/// - Identifiers that contain a letter or hyphen are compared in ASCII sort +/// order: `1.0.0-pre12` is less than `1.0.0-pre8`. +/// +/// - Any numeric identifier is always less than any non-numeric +/// identifier: `1.0.0-pre.1` is less than `1.0.0-pre.x`. +/// +/// Example: `1.0.0-alpha` < `1.0.0-alpha.1` < `1.0.0-alpha.beta` < `1.0.0-beta` < `1.0.0-beta.2` < `1.0.0-beta.11` < `1.0.0-rc.1` < `1.0.0` +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Version { + pub major: u64, + pub minor: u64, + pub patch: u64, + pub pre: Prerelease, + pub build: BuildMetadata, +} + +/// **SemVer version requirement** describing the intersection of some version +/// comparators, such as `>=1.2.3, <1.8`. +/// +/// # Syntax +/// +/// - Either `*` (meaning "any"), or one or more comma-separated comparators. +/// +/// - A [`Comparator`] is an operator ([`Op`]) and a partial version, separated +/// by optional whitespace. For example `>=1.0.0` or `>=1.0`. +/// +/// - Build metadata is syntactically permitted on the partial versions, but is +/// completely ignored, as it's never relevant to whether any comparator +/// matches a particular version. +/// +/// - Whitespace is permitted around commas and around operators. Whitespace is +/// not permitted within a partial version, i.e. anywhere between the major +/// version number and its minor, patch, pre-release, or build metadata. +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[cfg_attr(no_const_vec_new, derive(Default))] +pub struct VersionReq { + pub comparators: Vec<Comparator>, +} + +/// A pair of comparison operator and partial version, such as `>=1.2`. Forms +/// one piece of a VersionReq. +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub struct Comparator { + pub op: Op, + pub major: u64, + pub minor: Option<u64>, + /// Patch is only allowed if minor is Some. + pub patch: Option<u64>, + /// Non-empty pre-release is only allowed if patch is Some. + pub pre: Prerelease, +} + +/// SemVer comparison operator: `=`, `>`, `>=`, `<`, `<=`, `~`, `^`, `*`. +/// +/// # Op::Exact +/// -  **`=I.J.K`** — exactly the version I.J.K +/// -  **`=I.J`** — equivalent to `>=I.J.0, <I.(J+1).0` +/// -  **`=I`** — equivalent to `>=I.0.0, <(I+1).0.0` +/// +/// # Op::Greater +/// -  **`>I.J.K`** +/// -  **`>I.J`** — equivalent to `>=I.(J+1).0` +/// -  **`>I`** — equivalent to `>=(I+1).0.0` +/// +/// # Op::GreaterEq +/// -  **`>=I.J.K`** +/// -  **`>=I.J`** — equivalent to `>=I.J.0` +/// -  **`>=I`** — equivalent to `>=I.0.0` +/// +/// # Op::Less +/// -  **`<I.J.K`** +/// -  **`<I.J`** — equivalent to `<I.J.0` +/// -  **`<I`** — equivalent to `<I.0.0` +/// +/// # Op::LessEq +/// -  **`<=I.J.K`** +/// -  **`<=I.J`** — equivalent to `<I.(J+1).0` +/// -  **`<=I`** — equivalent to `<(I+1).0.0` +/// +/// # Op::Tilde ("patch" updates) +/// *Tilde requirements allow the **patch** part of the semver version (the third number) to increase.* +/// -  **`~I.J.K`** — equivalent to `>=I.J.K, <I.(J+1).0` +/// -  **`~I.J`** — equivalent to `=I.J` +/// -  **`~I`** — equivalent to `=I` +/// +/// # Op::Caret ("compatible" updates) +/// *Caret requirements allow parts that are **right of the first nonzero** part of the semver version to increase.* +/// -  **`^I.J.K`** (for I\>0) — equivalent to `>=I.J.K, <(I+1).0.0` +/// -  **`^0.J.K`** (for J\>0) — equivalent to `>=0.J.K, <0.(J+1).0` +/// -  **`^0.0.K`** — equivalent to `=0.0.K` +/// -  **`^I.J`** (for I\>0 or J\>0) — equivalent to `^I.J.0` +/// -  **`^0.0`** — equivalent to `=0.0` +/// -  **`^I`** — equivalent to `=I` +/// +/// # Op::Wildcard +/// -  **`I.J.*`** — equivalent to `=I.J` +/// -  **`I.*`** or **`I.*.*`** — equivalent to `=I` +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[cfg_attr(not(no_non_exhaustive), non_exhaustive)] +pub enum Op { + Exact, + Greater, + GreaterEq, + Less, + LessEq, + Tilde, + Caret, + Wildcard, + + #[cfg(no_non_exhaustive)] // rustc <1.40 + #[doc(hidden)] + __NonExhaustive, +} + +/// Optional pre-release identifier on a version string. This comes after `-` in +/// a SemVer version, like `1.0.0-alpha.1` +/// +/// # Examples +/// +/// Some real world pre-release idioms drawn from crates.io: +/// +/// - **[mio]** <code>0.7.0-<b>alpha.1</b></code> — the most common style +/// for numbering pre-releases. +/// +/// - **[pest]** <code>1.0.0-<b>beta.8</b></code>, <code>1.0.0-<b>rc.0</b></code> +/// — this crate makes a distinction between betas and release +/// candidates. +/// +/// - **[sassers]** <code>0.11.0-<b>shitshow</b></code> — ???. +/// +/// - **[atomic-utils]** <code>0.0.0-<b>reserved</b></code> — a squatted +/// crate name. +/// +/// [mio]: https://crates.io/crates/mio +/// [pest]: https://crates.io/crates/pest +/// [atomic-utils]: https://crates.io/crates/atomic-utils +/// [sassers]: https://crates.io/crates/sassers +/// +/// *Tip:* Be aware that if you are planning to number your own pre-releases, +/// you should prefer to separate the numeric part from any non-numeric +/// identifiers by using a dot in between. That is, prefer pre-releases +/// `alpha.1`, `alpha.2`, etc rather than `alpha1`, `alpha2` etc. The SemVer +/// spec's rule for pre-release precedence has special treatment of numeric +/// components in the pre-release string, but only if there are no non-digit +/// characters in the same dot-separated component. So you'd have `alpha.2` < +/// `alpha.11` as intended, but `alpha11` < `alpha2`. +/// +/// # Syntax +/// +/// Pre-release strings are a series of dot separated identifiers immediately +/// following the patch version. Identifiers must comprise only ASCII +/// alphanumerics and hyphens: `0-9`, `A-Z`, `a-z`, `-`. Identifiers must not be +/// empty. Numeric identifiers must not include leading zeros. +/// +/// # Total ordering +/// +/// Pre-releases have a total order defined by the SemVer spec. It uses +/// lexicographic ordering of dot-separated components. Identifiers consisting +/// of only digits are compared numerically. Otherwise, identifiers are compared +/// in ASCII sort order. Any numeric identifier is always less than any +/// non-numeric identifier. +/// +/// Example: `alpha` < `alpha.85` < `alpha.90` < `alpha.200` < `alpha.0a` < `alpha.1a0` < `alpha.a` < `beta` +#[derive(Default, Clone, Eq, PartialEq, Hash)] +pub struct Prerelease { + identifier: Identifier, +} + +/// Optional build metadata identifier. This comes after `+` in a SemVer +/// version, as in `0.8.1+zstd.1.5.0`. +/// +/// # Examples +/// +/// Some real world build metadata idioms drawn from crates.io: +/// +/// - **[libgit2-sys]** <code>0.12.20+<b>1.1.0</b></code> — for this +/// crate, the build metadata indicates the version of the C libgit2 library +/// that the Rust crate is built against. +/// +/// - **[mashup]** <code>0.1.13+<b>deprecated</b></code> — just the word +/// "deprecated" for a crate that has been superseded by another. Eventually +/// people will take notice of this in Cargo's build output where it lists the +/// crates being compiled. +/// +/// - **[google-bigquery2]** <code>2.0.4+<b>20210327</b></code> — this +/// library is automatically generated from an official API schema, and the +/// build metadata indicates the date on which that schema was last captured. +/// +/// - **[fbthrift-git]** <code>0.0.6+<b>c7fcc0e</b></code> — this crate is +/// published from snapshots of a big company monorepo. In monorepo +/// development, there is no concept of versions, and all downstream code is +/// just updated atomically in the same commit that breaking changes to a +/// library are landed. Therefore for crates.io purposes, every published +/// version must be assumed to be incompatible with the previous. The build +/// metadata provides the source control hash of the snapshotted code. +/// +/// [libgit2-sys]: https://crates.io/crates/libgit2-sys +/// [mashup]: https://crates.io/crates/mashup +/// [google-bigquery2]: https://crates.io/crates/google-bigquery2 +/// [fbthrift-git]: https://crates.io/crates/fbthrift-git +/// +/// # Syntax +/// +/// Build metadata is a series of dot separated identifiers immediately +/// following the patch or pre-release version. Identifiers must comprise only +/// ASCII alphanumerics and hyphens: `0-9`, `A-Z`, `a-z`, `-`. Identifiers must +/// not be empty. Leading zeros *are* allowed, unlike any other place in the +/// SemVer grammar. +/// +/// # Total ordering +/// +/// Build metadata is ignored in evaluating `VersionReq`; it plays no role in +/// whether a `Version` matches any one of the comparison operators. +/// +/// However for comparing build metadatas among one another, they do have a +/// total order which is determined by lexicographic ordering of dot-separated +/// components. Identifiers consisting of only digits are compared numerically. +/// Otherwise, identifiers are compared in ASCII sort order. Any numeric +/// identifier is always less than any non-numeric identifier. +/// +/// Example: `demo` < `demo.85` < `demo.90` < `demo.090` < `demo.200` < `demo.1a0` < `demo.a` < `memo` +#[derive(Default, Clone, Eq, PartialEq, Hash)] +pub struct BuildMetadata { + identifier: Identifier, +} + +impl Version { + /// Create `Version` with an empty pre-release and build metadata. + /// + /// Equivalent to: + /// + /// ``` + /// # use semver::{BuildMetadata, Prerelease, Version}; + /// # + /// # const fn new(major: u64, minor: u64, patch: u64) -> Version { + /// Version { + /// major, + /// minor, + /// patch, + /// pre: Prerelease::EMPTY, + /// build: BuildMetadata::EMPTY, + /// } + /// # } + /// ``` + pub const fn new(major: u64, minor: u64, patch: u64) -> Self { + Version { + major, + minor, + patch, + pre: Prerelease::EMPTY, + build: BuildMetadata::EMPTY, + } + } + + /// Create `Version` by parsing from string representation. + /// + /// # Errors + /// + /// Possible reasons for the parse to fail include: + /// + /// - `1.0` — too few numeric components. A SemVer version must have + /// exactly three. If you are looking at something that has fewer than + /// three numbers in it, it's possible it is a `VersionReq` instead (with + /// an implicit default `^` comparison operator). + /// + /// - `1.0.01` — a numeric component has a leading zero. + /// + /// - `1.0.unknown` — unexpected character in one of the components. + /// + /// - `1.0.0-` or `1.0.0+` — the pre-release or build metadata are + /// indicated present but empty. + /// + /// - `1.0.0-alpha_123` — pre-release or build metadata have something + /// outside the allowed characters, which are `0-9`, `A-Z`, `a-z`, `-`, + /// and `.` (dot). + /// + /// - `23456789999999999999.0.0` — overflow of a u64. + pub fn parse(text: &str) -> Result<Self, Error> { + Version::from_str(text) + } +} + +impl VersionReq { + /// A `VersionReq` with no constraint on the version numbers it matches. + /// Equivalent to `VersionReq::parse("*").unwrap()`. + /// + /// In terms of comparators this is equivalent to `>=0.0.0`. + /// + /// Counterintuitively a `*` VersionReq does not match every possible + /// version number. In particular, in order for *any* `VersionReq` to match + /// a pre-release version, the `VersionReq` must contain at least one + /// `Comparator` that has an explicit major, minor, and patch version + /// identical to the pre-release being matched, and that has a nonempty + /// pre-release component. Since `*` is not written with an explicit major, + /// minor, and patch version, and does not contain a nonempty pre-release + /// component, it does not match any pre-release versions. + #[cfg(not(no_const_vec_new))] // rustc <1.39 + pub const STAR: Self = VersionReq { + comparators: Vec::new(), + }; + + /// Create `VersionReq` by parsing from string representation. + /// + /// # Errors + /// + /// Possible reasons for the parse to fail include: + /// + /// - `>a.b` — unexpected characters in the partial version. + /// + /// - `@1.0.0` — unrecognized comparison operator. + /// + /// - `^1.0.0, ` — unexpected end of input. + /// + /// - `>=1.0 <2.0` — missing comma between comparators. + /// + /// - `*.*` — unsupported wildcard syntax. + pub fn parse(text: &str) -> Result<Self, Error> { + VersionReq::from_str(text) + } + + /// Evaluate whether the given `Version` satisfies the version requirement + /// described by `self`. + pub fn matches(&self, version: &Version) -> bool { + eval::matches_req(self, version) + } +} + +/// The default VersionReq is the same as [`VersionReq::STAR`]. +#[cfg(not(no_const_vec_new))] +impl Default for VersionReq { + fn default() -> Self { + VersionReq::STAR + } +} + +impl Comparator { + pub fn parse(text: &str) -> Result<Self, Error> { + Comparator::from_str(text) + } + + pub fn matches(&self, version: &Version) -> bool { + eval::matches_comparator(self, version) + } +} + +impl Prerelease { + pub const EMPTY: Self = Prerelease { + identifier: Identifier::empty(), + }; + + pub fn new(text: &str) -> Result<Self, Error> { + Prerelease::from_str(text) + } + + pub fn as_str(&self) -> &str { + self.identifier.as_str() + } + + pub fn is_empty(&self) -> bool { + self.identifier.is_empty() + } +} + +impl BuildMetadata { + pub const EMPTY: Self = BuildMetadata { + identifier: Identifier::empty(), + }; + + pub fn new(text: &str) -> Result<Self, Error> { + BuildMetadata::from_str(text) + } + + pub fn as_str(&self) -> &str { + self.identifier.as_str() + } + + pub fn is_empty(&self) -> bool { + self.identifier.is_empty() + } +} |