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