1//! [![github]](https://github.com/dtolnay/semver) [![crates-io]](https://crates.io/crates/semver) [![docs-rs]](https://docs.rs/semver)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6//!
7//! <br>
8//!
9//! A parser and evaluator for Cargo's flavor of Semantic Versioning.
10//!
11//! Semantic Versioning (see <https://semver.org>) is a guideline for how
12//! version numbers are assigned and incremented. It is widely followed within
13//! the Cargo/crates.io ecosystem for Rust.
14//!
15//! <br>
16//!
17//! # Example
18//!
19//! ```
20//! use semver::{BuildMetadata, Prerelease, Version, VersionReq};
21//!
22//! fn main() {
23//! let req = VersionReq::parse(">=1.2.3, <1.8.0").unwrap();
24//!
25//! // Check whether this requirement matches version 1.2.3-alpha.1 (no)
26//! let version = Version {
27//! major: 1,
28//! minor: 2,
29//! patch: 3,
30//! pre: Prerelease::new("alpha.1").unwrap(),
31//! build: BuildMetadata::EMPTY,
32//! };
33//! assert!(!req.matches(&version));
34//!
35//! // Check whether it matches 1.3.0 (yes it does)
36//! let version = Version::parse("1.3.0").unwrap();
37//! assert!(req.matches(&version));
38//! }
39//! ```
40//!
41//! <br><br>
42//!
43//! # Scope of this crate
44//!
45//! Besides Cargo, several other package ecosystems and package managers for
46//! other languages also use SemVer:&ensp;RubyGems/Bundler for Ruby, npm for
47//! JavaScript, Composer for PHP, CocoaPods for Objective-C...
48//!
49//! The `semver` crate is specifically intended to implement Cargo's
50//! interpretation of Semantic Versioning.
51//!
52//! Where the various tools differ in their interpretation or implementation of
53//! the spec, this crate follows the implementation choices made by Cargo. If
54//! you are operating on version numbers from some other package ecosystem, you
55//! will want to use a different semver library which is appropriate to that
56//! ecosystem.
57//!
58//! The extent of Cargo's SemVer support is documented in the *[Specifying
59//! Dependencies]* chapter of the Cargo reference.
60//!
61//! [Specifying Dependencies]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
62
63#![doc(html_root_url = "https://docs.rs/semver/1.0.17")]
64#![cfg_attr(doc_cfg, feature(doc_cfg))]
65#![cfg_attr(all(not(feature = "std"), not(no_alloc_crate)), no_std)]
66#![cfg_attr(not(no_unsafe_op_in_unsafe_fn_lint), deny(unsafe_op_in_unsafe_fn))]
67#![cfg_attr(no_unsafe_op_in_unsafe_fn_lint, allow(unused_unsafe))]
68#![cfg_attr(no_str_strip_prefix, allow(unstable_name_collisions))]
69#![allow(
70 clippy::cast_lossless,
71 clippy::cast_possible_truncation,
72 clippy::doc_markdown,
73 clippy::items_after_statements,
74 clippy::manual_map,
75 clippy::match_bool,
76 clippy::missing_errors_doc,
77 clippy::must_use_candidate,
78 clippy::needless_doctest_main,
79 clippy::option_if_let_else,
80 clippy::ptr_as_ptr,
81 clippy::redundant_else,
82 clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7324
83 clippy::similar_names,
84 clippy::unnested_or_patterns,
85 clippy::unseparated_literal_suffix,
86 clippy::wildcard_imports
87)]
88
89#[cfg(not(no_alloc_crate))]
90extern crate alloc;
91
92mod backport;
93mod display;
94mod error;
95mod eval;
96mod identifier;
97mod impls;
98mod parse;
99
100#[cfg(feature = "serde")]
101mod serde;
102
103use crate::alloc::vec::Vec;
104use crate::identifier::Identifier;
105use core::str::FromStr;
106
107#[allow(unused_imports)]
108use crate::backport::*;
109
110pub use crate::parse::Error;
111
112/// **SemVer version** as defined by <https://semver.org>.
113///
114/// # Syntax
115///
116/// - The major, minor, and patch numbers may be any integer 0 through u64::MAX.
117/// When representing a SemVer version as a string, each number is written as
118/// a base 10 integer. For example, `1.0.119`.
119///
120/// - Leading zeros are forbidden in those positions. For example `1.01.00` is
121/// invalid as a SemVer version.
122///
123/// - The pre-release identifier, if present, must conform to the syntax
124/// documented for [`Prerelease`].
125///
126/// - The build metadata, if present, must conform to the syntax documented for
127/// [`BuildMetadata`].
128///
129/// - Whitespace is not allowed anywhere in the version.
130///
131/// # Total ordering
132///
133/// Given any two SemVer versions, one is less than, greater than, or equal to
134/// the other. Versions may be compared against one another using Rust's usual
135/// comparison operators.
136///
137/// - The major, minor, and patch number are compared numerically from left to
138/// right, lexicographically ordered as a 3-tuple of integers. So for example
139/// version `1.5.0` is less than version `1.19.0`, despite the fact that
140/// "1.19.0" &lt; "1.5.0" as ASCIIbetically compared strings and 1.19 &lt; 1.5
141/// as real numbers.
142///
143/// - When major, minor, and patch are equal, a pre-release version is
144/// considered less than the ordinary release:&ensp;version `1.0.0-alpha.1` is
145/// less than version `1.0.0`.
146///
147/// - Two pre-releases of the same major, minor, patch are compared by
148/// lexicographic ordering of dot-separated components of the pre-release
149/// string.
150///
151/// - Identifiers consisting of only digits are compared
152/// numerically:&ensp;`1.0.0-pre.8` is less than `1.0.0-pre.12`.
153///
154/// - Identifiers that contain a letter or hyphen are compared in ASCII sort
155/// order:&ensp;`1.0.0-pre12` is less than `1.0.0-pre8`.
156///
157/// - Any numeric identifier is always less than any non-numeric
158/// identifier:&ensp;`1.0.0-pre.1` is less than `1.0.0-pre.x`.
159///
160/// Example:&ensp;`1.0.0-alpha`&ensp;&lt;&ensp;`1.0.0-alpha.1`&ensp;&lt;&ensp;`1.0.0-alpha.beta`&ensp;&lt;&ensp;`1.0.0-beta`&ensp;&lt;&ensp;`1.0.0-beta.2`&ensp;&lt;&ensp;`1.0.0-beta.11`&ensp;&lt;&ensp;`1.0.0-rc.1`&ensp;&lt;&ensp;`1.0.0`
161#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
162pub struct Version {
163 pub major: u64,
164 pub minor: u64,
165 pub patch: u64,
166 pub pre: Prerelease,
167 pub build: BuildMetadata,
168}
169
170/// **SemVer version requirement** describing the intersection of some version
171/// comparators, such as `>=1.2.3, <1.8`.
172///
173/// # Syntax
174///
175/// - Either `*` (meaning "any"), or one or more comma-separated comparators.
176///
177/// - A [`Comparator`] is an operator ([`Op`]) and a partial version, separated
178/// by optional whitespace. For example `>=1.0.0` or `>=1.0`.
179///
180/// - Build metadata is syntactically permitted on the partial versions, but is
181/// completely ignored, as it's never relevant to whether any comparator
182/// matches a particular version.
183///
184/// - Whitespace is permitted around commas and around operators. Whitespace is
185/// not permitted within a partial version, i.e. anywhere between the major
186/// version number and its minor, patch, pre-release, or build metadata.
187#[derive(Clone, Eq, PartialEq, Hash, Debug)]
188#[cfg_attr(no_const_vec_new, derive(Default))]
189pub struct VersionReq {
190 pub comparators: Vec<Comparator>,
191}
192
193/// A pair of comparison operator and partial version, such as `>=1.2`. Forms
194/// one piece of a VersionReq.
195#[derive(Clone, Eq, PartialEq, Hash, Debug)]
196pub struct Comparator {
197 pub op: Op,
198 pub major: u64,
199 pub minor: Option<u64>,
200 /// Patch is only allowed if minor is Some.
201 pub patch: Option<u64>,
202 /// Non-empty pre-release is only allowed if patch is Some.
203 pub pre: Prerelease,
204}
205
206/// SemVer comparison operator: `=`, `>`, `>=`, `<`, `<=`, `~`, `^`, `*`.
207///
208/// # Op::Exact
209/// - &ensp;**`=I.J.K`**&emsp;&mdash;&emsp;exactly the version I.J.K
210/// - &ensp;**`=I.J`**&emsp;&mdash;&emsp;equivalent to `>=I.J.0, <I.(J+1).0`
211/// - &ensp;**`=I`**&emsp;&mdash;&emsp;equivalent to `>=I.0.0, <(I+1).0.0`
212///
213/// # Op::Greater
214/// - &ensp;**`>I.J.K`**
215/// - &ensp;**`>I.J`**&emsp;&mdash;&emsp;equivalent to `>=I.(J+1).0`
216/// - &ensp;**`>I`**&emsp;&mdash;&emsp;equivalent to `>=(I+1).0.0`
217///
218/// # Op::GreaterEq
219/// - &ensp;**`>=I.J.K`**
220/// - &ensp;**`>=I.J`**&emsp;&mdash;&emsp;equivalent to `>=I.J.0`
221/// - &ensp;**`>=I`**&emsp;&mdash;&emsp;equivalent to `>=I.0.0`
222///
223/// # Op::Less
224/// - &ensp;**`<I.J.K`**
225/// - &ensp;**`<I.J`**&emsp;&mdash;&emsp;equivalent to `<I.J.0`
226/// - &ensp;**`<I`**&emsp;&mdash;&emsp;equivalent to `<I.0.0`
227///
228/// # Op::LessEq
229/// - &ensp;**`<=I.J.K`**
230/// - &ensp;**`<=I.J`**&emsp;&mdash;&emsp;equivalent to `<I.(J+1).0`
231/// - &ensp;**`<=I`**&emsp;&mdash;&emsp;equivalent to `<(I+1).0.0`
232///
233/// # Op::Tilde&emsp;("patch" updates)
234/// *Tilde requirements allow the **patch** part of the semver version (the third number) to increase.*
235/// - &ensp;**`~I.J.K`**&emsp;&mdash;&emsp;equivalent to `>=I.J.K, <I.(J+1).0`
236/// - &ensp;**`~I.J`**&emsp;&mdash;&emsp;equivalent to `=I.J`
237/// - &ensp;**`~I`**&emsp;&mdash;&emsp;equivalent to `=I`
238///
239/// # Op::Caret&emsp;("compatible" updates)
240/// *Caret requirements allow parts that are **right of the first nonzero** part of the semver version to increase.*
241/// - &ensp;**`^I.J.K`**&ensp;(for I\>0)&emsp;&mdash;&emsp;equivalent to `>=I.J.K, <(I+1).0.0`
242/// - &ensp;**`^0.J.K`**&ensp;(for J\>0)&emsp;&mdash;&emsp;equivalent to `>=0.J.K, <0.(J+1).0`
243/// - &ensp;**`^0.0.K`**&emsp;&mdash;&emsp;equivalent to `=0.0.K`
244/// - &ensp;**`^I.J`**&ensp;(for I\>0 or J\>0)&emsp;&mdash;&emsp;equivalent to `^I.J.0`
245/// - &ensp;**`^0.0`**&emsp;&mdash;&emsp;equivalent to `=0.0`
246/// - &ensp;**`^I`**&emsp;&mdash;&emsp;equivalent to `=I`
247///
248/// # Op::Wildcard
249/// - &ensp;**`I.J.*`**&emsp;&mdash;&emsp;equivalent to `=I.J`
250/// - &ensp;**`I.*`**&ensp;or&ensp;**`I.*.*`**&emsp;&mdash;&emsp;equivalent to `=I`
251#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
252#[cfg_attr(not(no_non_exhaustive), non_exhaustive)]
253pub enum Op {
254 Exact,
255 Greater,
256 GreaterEq,
257 Less,
258 LessEq,
259 Tilde,
260 Caret,
261 Wildcard,
262
263 #[cfg(no_non_exhaustive)] // rustc <1.40
264 #[doc(hidden)]
265 __NonExhaustive,
266}
267
268/// Optional pre-release identifier on a version string. This comes after `-` in
269/// a SemVer version, like `1.0.0-alpha.1`
270///
271/// # Examples
272///
273/// Some real world pre-release idioms drawn from crates.io:
274///
275/// - **[mio]** <code>0.7.0-<b>alpha.1</b></code> &mdash; the most common style
276/// for numbering pre-releases.
277///
278/// - **[pest]** <code>1.0.0-<b>beta.8</b></code>,&ensp;<code>1.0.0-<b>rc.0</b></code>
279/// &mdash; this crate makes a distinction between betas and release
280/// candidates.
281///
282/// - **[sassers]** <code>0.11.0-<b>shitshow</b></code> &mdash; ???.
283///
284/// - **[atomic-utils]** <code>0.0.0-<b>reserved</b></code> &mdash; a squatted
285/// crate name.
286///
287/// [mio]: https://crates.io/crates/mio
288/// [pest]: https://crates.io/crates/pest
289/// [atomic-utils]: https://crates.io/crates/atomic-utils
290/// [sassers]: https://crates.io/crates/sassers
291///
292/// *Tip:* Be aware that if you are planning to number your own pre-releases,
293/// you should prefer to separate the numeric part from any non-numeric
294/// identifiers by using a dot in between. That is, prefer pre-releases
295/// `alpha.1`, `alpha.2`, etc rather than `alpha1`, `alpha2` etc. The SemVer
296/// spec's rule for pre-release precedence has special treatment of numeric
297/// components in the pre-release string, but only if there are no non-digit
298/// characters in the same dot-separated component. So you'd have `alpha.2` &lt;
299/// `alpha.11` as intended, but `alpha11` &lt; `alpha2`.
300///
301/// # Syntax
302///
303/// Pre-release strings are a series of dot separated identifiers immediately
304/// following the patch version. Identifiers must comprise only ASCII
305/// alphanumerics and hyphens: `0-9`, `A-Z`, `a-z`, `-`. Identifiers must not be
306/// empty. Numeric identifiers must not include leading zeros.
307///
308/// # Total ordering
309///
310/// Pre-releases have a total order defined by the SemVer spec. It uses
311/// lexicographic ordering of dot-separated components. Identifiers consisting
312/// of only digits are compared numerically. Otherwise, identifiers are compared
313/// in ASCII sort order. Any numeric identifier is always less than any
314/// non-numeric identifier.
315///
316/// Example:&ensp;`alpha`&ensp;&lt;&ensp;`alpha.85`&ensp;&lt;&ensp;`alpha.90`&ensp;&lt;&ensp;`alpha.200`&ensp;&lt;&ensp;`alpha.0a`&ensp;&lt;&ensp;`alpha.1a0`&ensp;&lt;&ensp;`alpha.a`&ensp;&lt;&ensp;`beta`
317#[derive(Default, Clone, Eq, PartialEq, Hash)]
318pub struct Prerelease {
319 identifier: Identifier,
320}
321
322/// Optional build metadata identifier. This comes after `+` in a SemVer
323/// version, as in `0.8.1+zstd.1.5.0`.
324///
325/// # Examples
326///
327/// Some real world build metadata idioms drawn from crates.io:
328///
329/// - **[libgit2-sys]** <code>0.12.20+<b>1.1.0</b></code> &mdash; for this
330/// crate, the build metadata indicates the version of the C libgit2 library
331/// that the Rust crate is built against.
332///
333/// - **[mashup]** <code>0.1.13+<b>deprecated</b></code> &mdash; just the word
334/// "deprecated" for a crate that has been superseded by another. Eventually
335/// people will take notice of this in Cargo's build output where it lists the
336/// crates being compiled.
337///
338/// - **[google-bigquery2]** <code>2.0.4+<b>20210327</b></code> &mdash; this
339/// library is automatically generated from an official API schema, and the
340/// build metadata indicates the date on which that schema was last captured.
341///
342/// - **[fbthrift-git]** <code>0.0.6+<b>c7fcc0e</b></code> &mdash; this crate is
343/// published from snapshots of a big company monorepo. In monorepo
344/// development, there is no concept of versions, and all downstream code is
345/// just updated atomically in the same commit that breaking changes to a
346/// library are landed. Therefore for crates.io purposes, every published
347/// version must be assumed to be incompatible with the previous. The build
348/// metadata provides the source control hash of the snapshotted code.
349///
350/// [libgit2-sys]: https://crates.io/crates/libgit2-sys
351/// [mashup]: https://crates.io/crates/mashup
352/// [google-bigquery2]: https://crates.io/crates/google-bigquery2
353/// [fbthrift-git]: https://crates.io/crates/fbthrift-git
354///
355/// # Syntax
356///
357/// Build metadata is a series of dot separated identifiers immediately
358/// following the patch or pre-release version. Identifiers must comprise only
359/// ASCII alphanumerics and hyphens: `0-9`, `A-Z`, `a-z`, `-`. Identifiers must
360/// not be empty. Leading zeros *are* allowed, unlike any other place in the
361/// SemVer grammar.
362///
363/// # Total ordering
364///
365/// Build metadata is ignored in evaluating `VersionReq`; it plays no role in
366/// whether a `Version` matches any one of the comparison operators.
367///
368/// However for comparing build metadatas among one another, they do have a
369/// total order which is determined by lexicographic ordering of dot-separated
370/// components. Identifiers consisting of only digits are compared numerically.
371/// Otherwise, identifiers are compared in ASCII sort order. Any numeric
372/// identifier is always less than any non-numeric identifier.
373///
374/// Example:&ensp;`demo`&ensp;&lt;&ensp;`demo.85`&ensp;&lt;&ensp;`demo.90`&ensp;&lt;&ensp;`demo.090`&ensp;&lt;&ensp;`demo.200`&ensp;&lt;&ensp;`demo.1a0`&ensp;&lt;&ensp;`demo.a`&ensp;&lt;&ensp;`memo`
375#[derive(Default, Clone, Eq, PartialEq, Hash)]
376pub struct BuildMetadata {
377 identifier: Identifier,
378}
379
380impl Version {
381 /// Create `Version` with an empty pre-release and build metadata.
382 ///
383 /// Equivalent to:
384 ///
385 /// ```
386 /// # use semver::{BuildMetadata, Prerelease, Version};
387 /// #
388 /// # const fn new(major: u64, minor: u64, patch: u64) -> Version {
389 /// Version {
390 /// major,
391 /// minor,
392 /// patch,
393 /// pre: Prerelease::EMPTY,
394 /// build: BuildMetadata::EMPTY,
395 /// }
396 /// # }
397 /// ```
398 pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
399 Version {
400 major,
401 minor,
402 patch,
403 pre: Prerelease::EMPTY,
404 build: BuildMetadata::EMPTY,
405 }
406 }
407
408 /// Create `Version` by parsing from string representation.
409 ///
410 /// # Errors
411 ///
412 /// Possible reasons for the parse to fail include:
413 ///
414 /// - `1.0` &mdash; too few numeric components. A SemVer version must have
415 /// exactly three. If you are looking at something that has fewer than
416 /// three numbers in it, it's possible it is a `VersionReq` instead (with
417 /// an implicit default `^` comparison operator).
418 ///
419 /// - `1.0.01` &mdash; a numeric component has a leading zero.
420 ///
421 /// - `1.0.unknown` &mdash; unexpected character in one of the components.
422 ///
423 /// - `1.0.0-` or `1.0.0+` &mdash; the pre-release or build metadata are
424 /// indicated present but empty.
425 ///
426 /// - `1.0.0-alpha_123` &mdash; pre-release or build metadata have something
427 /// outside the allowed characters, which are `0-9`, `A-Z`, `a-z`, `-`,
428 /// and `.` (dot).
429 ///
430 /// - `23456789999999999999.0.0` &mdash; overflow of a u64.
431 pub fn parse(text: &str) -> Result<Self, Error> {
432 Version::from_str(text)
433 }
434}
435
436impl VersionReq {
437 /// A `VersionReq` with no constraint on the version numbers it matches.
438 /// Equivalent to `VersionReq::parse("*").unwrap()`.
439 ///
440 /// In terms of comparators this is equivalent to `>=0.0.0`.
441 ///
442 /// Counterintuitively a `*` VersionReq does not match every possible
443 /// version number. In particular, in order for *any* `VersionReq` to match
444 /// a pre-release version, the `VersionReq` must contain at least one
445 /// `Comparator` that has an explicit major, minor, and patch version
446 /// identical to the pre-release being matched, and that has a nonempty
447 /// pre-release component. Since `*` is not written with an explicit major,
448 /// minor, and patch version, and does not contain a nonempty pre-release
449 /// component, it does not match any pre-release versions.
450 #[cfg(not(no_const_vec_new))] // rustc <1.39
451 pub const STAR: Self = VersionReq {
452 comparators: Vec::new(),
453 };
454
455 /// Create `VersionReq` by parsing from string representation.
456 ///
457 /// # Errors
458 ///
459 /// Possible reasons for the parse to fail include:
460 ///
461 /// - `>a.b` &mdash; unexpected characters in the partial version.
462 ///
463 /// - `@1.0.0` &mdash; unrecognized comparison operator.
464 ///
465 /// - `^1.0.0, ` &mdash; unexpected end of input.
466 ///
467 /// - `>=1.0 <2.0` &mdash; missing comma between comparators.
468 ///
469 /// - `*.*` &mdash; unsupported wildcard syntax.
470 pub fn parse(text: &str) -> Result<Self, Error> {
471 VersionReq::from_str(text)
472 }
473
474 /// Evaluate whether the given `Version` satisfies the version requirement
475 /// described by `self`.
476 pub fn matches(&self, version: &Version) -> bool {
477 eval::matches_req(self, version)
478 }
479}
480
481/// The default VersionReq is the same as [`VersionReq::STAR`].
482#[cfg(not(no_const_vec_new))]
483impl Default for VersionReq {
484 fn default() -> Self {
485 VersionReq::STAR
486 }
487}
488
489impl Comparator {
490 pub fn parse(text: &str) -> Result<Self, Error> {
491 Comparator::from_str(text)
492 }
493
494 pub fn matches(&self, version: &Version) -> bool {
495 eval::matches_comparator(self, ver:version)
496 }
497}
498
499impl Prerelease {
500 pub const EMPTY: Self = Prerelease {
501 identifier: Identifier::empty(),
502 };
503
504 pub fn new(text: &str) -> Result<Self, Error> {
505 Prerelease::from_str(text)
506 }
507
508 pub fn as_str(&self) -> &str {
509 self.identifier.as_str()
510 }
511
512 pub fn is_empty(&self) -> bool {
513 self.identifier.is_empty()
514 }
515}
516
517impl BuildMetadata {
518 pub const EMPTY: Self = BuildMetadata {
519 identifier: Identifier::empty(),
520 };
521
522 pub fn new(text: &str) -> Result<Self, Error> {
523 BuildMetadata::from_str(text)
524 }
525
526 pub fn as_str(&self) -> &str {
527 self.identifier.as_str()
528 }
529
530 pub fn is_empty(&self) -> bool {
531 self.identifier.is_empty()
532 }
533}
534