Skip to main content

nodejs_semver/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(clippy::needless_doctest_main)]
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
6
7use std::cmp::{self, Ordering};
8use std::fmt;
9use std::num::ParseIntError;
10
11use miette::{Diagnostic, SourceSpan};
12use thiserror::Error;
13
14use winnow::ascii::{digit1, space0};
15use winnow::combinator::{alt, opt, preceded, separated};
16use winnow::error::{AddContext, ErrMode, FromExternalError, ParserError};
17use winnow::stream::{AsChar, Stream};
18use winnow::token::{literal, take_while};
19use winnow::{ModalResult, Parser};
20
21pub use range::*;
22
23mod range;
24mod version_fast;
25
26/// JavaScript's
27/// [MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER).
28/// This is used to determine the maximum value for integer components in a
29/// JS-compatible way.
30pub const MAX_SAFE_INTEGER: u64 = 900_719_925_474_099;
31
32/// Maximum length of a semver string.
33pub const MAX_LENGTH: usize = 256;
34
35/**
36Semver version or range parsing error wrapper.
37
38This wrapper is used to hold some parsing-related metadata, as well as
39a more specific [SemverErrorKind].
40*/
41#[derive(Debug, Clone, Error, Eq, PartialEq)]
42#[error("{kind}")]
43pub struct SemverError {
44    input: String,
45    span: SourceSpan,
46    kind: SemverErrorKind,
47}
48
49impl Diagnostic for SemverError {
50    fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
51        self.kind().code()
52    }
53
54    fn severity(&self) -> Option<miette::Severity> {
55        self.kind().severity()
56    }
57
58    fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
59        self.kind().help()
60    }
61
62    fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
63        self.kind().url()
64    }
65
66    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
67        Some(&self.input)
68    }
69
70    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
71        Some(Box::new(std::iter::once(
72            miette::LabeledSpan::new_with_span(Some("here".into()), *self.span()),
73        )))
74    }
75}
76
77impl SemverError {
78    /// Returns the input that was given to the parser.
79    pub fn input(&self) -> &str {
80        &self.input
81    }
82
83    /// Returns the SourceSpan of the error.
84    pub fn span(&self) -> &SourceSpan {
85        &self.span
86    }
87
88    /// Returns the (0-based) byte offset where the parsing error happened.
89    pub fn offset(&self) -> usize {
90        self.span.offset()
91    }
92
93    /// Returns the more specific [SemverErrorKind] for this error.
94    ///
95    /// This value can also be fetched through [std::error::Error::source],
96    /// but that would require downcasting to match types.
97    pub fn kind(&self) -> &SemverErrorKind {
98        &self.kind
99    }
100
101    /// Returns the (0-indexed) line and column number where the parsing error
102    /// happened.
103    pub fn location(&self) -> (usize, usize) {
104        // Taken partially from winnow.
105        let prefix = &self.input.as_bytes()[..self.offset()];
106
107        // Count the number of newlines in the first `offset` bytes of input
108        let line_number = bytecount::count(prefix, b'\n');
109
110        // Find the line that includes the subslice:
111        // Find the *last* newline before the substring starts
112        let line_begin = prefix
113            .iter()
114            .rev()
115            .position(|&b| b == b'\n')
116            .map(|pos| self.offset() - pos)
117            .unwrap_or(0);
118
119        // Find the full line after that newline
120        let line = self.input[line_begin..]
121            .lines()
122            .next()
123            .unwrap_or(&self.input[line_begin..])
124            .trim_end();
125
126        // The (0-indexed) column number is the offset of our substring into that line
127        let column_number = self.input[self.offset()..].as_ptr() as usize - line.as_ptr() as usize;
128
129        (line_number, column_number)
130    }
131}
132
133/**
134The specific kind of error that occurred. Usually wrapped in a [SemverError].
135*/
136#[derive(Debug, Clone, Error, Eq, PartialEq, Diagnostic)]
137pub enum SemverErrorKind {
138    /**
139    Semver strings overall can't be longer than [MAX_LENGTH]. This is a
140    restriction coming from the JavaScript `nodejs-semver`.
141    */
142    #[error("Semver string can't be longer than {} characters.", MAX_LENGTH)]
143    #[diagnostic(code(nodejs_semver::too_long), url(docsrs))]
144    MaxLengthError,
145
146    /**
147    Input to `nodejs-semver` must be "complete". That is, a version must be
148    composed of major, minor, and patch segments, with optional prerelease
149    and build metadata. If you're looking for alternative syntaxes, like `1.2`,
150    that are meant for defining semver ranges, use [Range] instead.
151    */
152    #[error("Incomplete input to semver parser.")]
153    #[diagnostic(code(nodejs_semver::incomplete_input), url(docsrs))]
154    IncompleteInput,
155
156    /**
157    Components of a semver string (major, minor, patch, integer sections of
158    build and prerelease) must all be valid, parseable integers. This error
159    occurs when Rust's own integer parsing failed.
160    */
161    #[error("Failed to parse an integer component of a semver string: {0}")]
162    #[diagnostic(code(nodejs_semver::parse_int_error), url(docsrs))]
163    ParseIntError(ParseIntError),
164
165    /**
166    `nodejs-semver` inherits the JavaScript implementation's limitation on
167    limiting integer component sizes to [MAX_SAFE_INTEGER].
168    */
169    #[error(
170        "Integer component of semver string is larger than JavaScript's Number.MAX_SAFE_INTEGER: {0}"
171    )]
172    #[diagnostic(code(nodejs_semver::integer_too_large), url(docsrs))]
173    MaxIntError(u64),
174
175    /**
176    This is a generic error that a certain component of the semver string
177    failed to parse.
178    */
179    #[error("Failed to parse {0}.")]
180    #[diagnostic(code(nodejs_semver::parse_component_error), url(docsrs))]
181    Context(&'static str),
182
183    #[error("No valid ranges could be parsed")]
184    #[diagnostic(
185        code(nodejs_semver::no_valid_ranges),
186        url(docsrs),
187        help(
188            "nodejs-semver parses in so-called 'loose' mode. This means that if you have a slightly incorrect semver operator (`>=1.y`, for ex.), it will get thrown away. This error only happens if _all_ your input ranges were invalid semver in this way."
189        )
190    )]
191    NoValidRanges,
192
193    /**
194    This error is mostly nondescript. Feel free to file an issue if you run
195    into it.
196    */
197    #[error("An unspecified error occurred.")]
198    #[diagnostic(code(nodejs_semver::other), url(docsrs))]
199    Other,
200}
201
202#[derive(Debug)]
203struct SemverParseError<I> {
204    pub(crate) input: I,
205    pub(crate) context: Option<&'static str>,
206    pub(crate) kind: Option<SemverErrorKind>,
207}
208
209impl<I: Clone + Stream> ParserError<I> for SemverParseError<I> {
210    type Inner = Self;
211
212    fn from_input(input: &I) -> Self {
213        Self {
214            input: input.clone(),
215            context: None,
216            kind: None,
217        }
218    }
219
220    fn append(self, input: &I, _token_start: &<I as Stream>::Checkpoint) -> Self {
221        Self {
222            input: input.clone(),
223            context: self.context,
224            kind: self.kind,
225        }
226    }
227
228    fn into_inner(self) -> Result<Self::Inner, Self> {
229        Ok(self)
230    }
231}
232
233impl<I: Stream> AddContext<I> for SemverParseError<I> {
234    fn add_context(
235        self,
236        _input: &I,
237        _token_start: &<I as Stream>::Checkpoint,
238        ctx: &'static str,
239    ) -> Self {
240        Self {
241            input: self.input,
242            context: Some(ctx),
243            kind: self.kind,
244        }
245    }
246}
247
248impl<'a> FromExternalError<&'a str, SemverParseError<&'a str>> for SemverParseError<&'a str> {
249    fn from_external_error(_input: &&'a str, e: SemverParseError<&'a str>) -> Self {
250        e
251    }
252}
253
254#[cold]
255#[inline(never)]
256fn max_length_error(input: &str) -> SemverError {
257    SemverError {
258        input: input.into(),
259        span: (input.len() - 1, 0).into(),
260        kind: SemverErrorKind::MaxLengthError,
261    }
262}
263
264#[cold]
265#[inline(never)]
266pub(crate) fn semver_error_from_parse(
267    input: &str,
268    err: ErrMode<SemverParseError<&str>>,
269) -> SemverError {
270    match err {
271        ErrMode::Backtrack(e) | ErrMode::Cut(e) => SemverError {
272            input: input.into(),
273            span: (e.input.as_ptr() as usize - input.as_ptr() as usize, 0).into(),
274            kind: if let Some(kind) = e.kind {
275                kind
276            } else if let Some(ctx) = e.context {
277                SemverErrorKind::Context(ctx)
278            } else {
279                SemverErrorKind::Other
280            },
281        },
282        ErrMode::Incomplete(_) => SemverError {
283            input: input.into(),
284            span: (input.len() - 1, 0).into(),
285            kind: SemverErrorKind::IncompleteInput,
286        },
287    }
288}
289
290/**
291An Identifier type for build and prerelease metadata.
292*/
293#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
294pub enum Identifier {
295    /// An identifier that's solely numbers.
296    Numeric(u64),
297    /// An identifier with letters and numbers.
298    AlphaNumeric(String),
299}
300
301impl fmt::Display for Identifier {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        match self {
304            Identifier::Numeric(n) => write!(f, "{}", n),
305            Identifier::AlphaNumeric(s) => write!(f, "{}", s),
306        }
307    }
308}
309
310/// difference between two versions by the release type
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
312pub enum VersionDiff {
313    Major,
314    Minor,
315    Patch,
316    PreMajor,
317    PreMinor,
318    PrePatch,
319    PreRelease,
320}
321
322/// difference between two versions
323pub type ReleaseType = VersionDiff;
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq)]
326pub enum IdentifierBase {
327    /// Mirrors `identifierBase === false` in node-semver.
328    False,
329    /// Any other truthy/falsy value. Only the zero/non-zero nature matters.
330    Value(u64),
331}
332
333impl Default for IdentifierBase {
334    fn default() -> Self {
335        IdentifierBase::Value(0)
336    }
337}
338
339impl IdentifierBase {
340    fn base_value(self) -> u64 {
341        match self {
342            IdentifierBase::False => 0,
343            IdentifierBase::Value(v) => {
344                if v == 0 {
345                    0
346                } else {
347                    1
348                }
349            }
350        }
351    }
352}
353
354impl From<bool> for IdentifierBase {
355    fn from(value: bool) -> Self {
356        if value {
357            IdentifierBase::Value(1)
358        } else {
359            IdentifierBase::False
360        }
361    }
362}
363
364impl From<u64> for IdentifierBase {
365    fn from(value: u64) -> Self {
366        IdentifierBase::Value(value)
367    }
368}
369
370impl From<usize> for IdentifierBase {
371    fn from(value: usize) -> Self {
372        IdentifierBase::Value(value as u64)
373    }
374}
375
376#[derive(Debug, Clone, PartialEq, Eq, Error)]
377pub enum IncrementError {
378    #[error("invalid identifier: {0}")]
379    InvalidIdentifier(String),
380    #[error("invalid increment argument: {0}")]
381    InvalidIncrementArgument(String),
382    #[error("version {0} is not a prerelease")]
383    NotAPrerelease(String),
384    #[error("increment would overflow a version component")]
385    Overflow,
386}
387
388impl fmt::Display for VersionDiff {
389    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390        match self {
391            VersionDiff::Major => write!(f, "major"),
392            VersionDiff::Minor => write!(f, "minor"),
393            VersionDiff::Patch => write!(f, "patch"),
394            VersionDiff::PreMajor => write!(f, "premajor"),
395            VersionDiff::PreMinor => write!(f, "preminor"),
396            VersionDiff::PrePatch => write!(f, "prepatch"),
397            VersionDiff::PreRelease => write!(f, "prerelease"),
398        }
399    }
400}
401
402/**
403A semantic version, conformant to the [semver spec](https://semver.org/spec/v2.0.0.html).
404*/
405#[derive(Clone, Debug)]
406pub struct Version {
407    major: u64,
408    minor: u64,
409    patch: u64,
410    meta: Option<Box<VersionMeta>>,
411}
412
413/// Owned components of a [`Version`].
414#[derive(Clone, Debug, Eq, PartialEq)]
415pub struct VersionParts {
416    pub major: u64,
417    pub minor: u64,
418    pub patch: u64,
419    pub pre_release: Vec<Identifier>,
420    pub build: Vec<Identifier>,
421}
422
423#[derive(Clone, Debug)]
424struct VersionMeta {
425    build: Identifiers,
426    pre_release: Identifiers,
427}
428
429#[derive(Clone, Debug)]
430pub(crate) enum Identifiers {
431    Empty,
432    One(Identifier),
433    Two([Identifier; 2]),
434    Many(Vec<Identifier>),
435}
436
437impl Identifiers {
438    pub(crate) fn from_vec(mut identifiers: Vec<Identifier>) -> Self {
439        match identifiers.len() {
440            0 => Self::Empty,
441            1 => Self::One(identifiers.pop().unwrap()),
442            2 => {
443                let second = identifiers.pop().unwrap();
444                let first = identifiers.pop().unwrap();
445                Self::Two([first, second])
446            }
447            _ => Self::Many(identifiers),
448        }
449    }
450
451    fn into_vec(self) -> Vec<Identifier> {
452        match self {
453            Self::Empty => Vec::new(),
454            Self::One(identifier) => vec![identifier],
455            Self::Two(identifiers) => Vec::from(identifiers),
456            Self::Many(identifiers) => identifiers,
457        }
458    }
459
460    fn as_slice(&self) -> &[Identifier] {
461        match self {
462            Self::Empty => &[],
463            Self::One(identifier) => std::slice::from_ref(identifier),
464            Self::Two(identifiers) => identifiers.as_slice(),
465            Self::Many(identifiers) => identifiers.as_slice(),
466        }
467    }
468
469    fn as_mut_slice(&mut self) -> &mut [Identifier] {
470        match self {
471            Self::Empty => &mut [],
472            Self::One(identifier) => std::slice::from_mut(identifier),
473            Self::Two(identifiers) => identifiers.as_mut_slice(),
474            Self::Many(identifiers) => identifiers.as_mut_slice(),
475        }
476    }
477
478    fn is_empty(&self) -> bool {
479        matches!(self, Self::Empty)
480    }
481
482    fn clear(&mut self) {
483        *self = Self::Empty;
484    }
485
486    pub(crate) fn push(&mut self, identifier: Identifier) {
487        match std::mem::replace(self, Self::Empty) {
488            Self::Empty => *self = Self::One(identifier),
489            Self::One(existing) => *self = Self::Two([existing, identifier]),
490            Self::Two([first, second]) => *self = Self::Many(vec![first, second, identifier]),
491            Self::Many(mut identifiers) => {
492                identifiers.push(identifier);
493                *self = Self::Many(identifiers);
494            }
495        }
496    }
497}
498
499#[cfg(feature = "serde")]
500impl Serialize for Version {
501    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
502        s.collect_str(self)
503    }
504}
505
506#[cfg(feature = "serde")]
507impl<'de> Deserialize<'de> for Version {
508    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
509        let s = String::deserialize(d)?;
510        s.parse().map_err(serde::de::Error::custom)
511    }
512}
513
514impl Version {
515    /// Returns the major version.
516    pub fn major(&self) -> u64 {
517        self.major
518    }
519
520    /// Returns the minor version.
521    pub fn minor(&self) -> u64 {
522        self.minor
523    }
524
525    /// Returns the patch version.
526    pub fn patch(&self) -> u64 {
527        self.patch
528    }
529
530    pub fn new(
531        major: u64,
532        minor: u64,
533        patch: u64,
534        pre_release: Vec<Identifier>,
535        build: Vec<Identifier>,
536    ) -> Self {
537        let meta = if pre_release.is_empty() && build.is_empty() {
538            return Self::new_empty(major, minor, patch);
539        } else {
540            Some(Box::new(VersionMeta {
541                build: Identifiers::from_vec(build),
542                pre_release: Identifiers::from_vec(pre_release),
543            }))
544        };
545
546        Self {
547            major,
548            minor,
549            patch,
550            meta,
551        }
552    }
553
554    pub(crate) fn new_empty(major: u64, minor: u64, patch: u64) -> Self {
555        Self {
556            major,
557            minor,
558            patch,
559            meta: None,
560        }
561    }
562
563    fn new_with_pre_release_identifier(
564        major: u64,
565        minor: u64,
566        patch: u64,
567        pre_release: Identifier,
568    ) -> Self {
569        Self {
570            major,
571            minor,
572            patch,
573            meta: Some(Box::new(VersionMeta {
574                build: Identifiers::Empty,
575                pre_release: Identifiers::One(pre_release),
576            })),
577        }
578    }
579
580    pub(crate) fn new_with_identifiers(
581        major: u64,
582        minor: u64,
583        patch: u64,
584        pre_release: Identifiers,
585        build: Identifiers,
586    ) -> Self {
587        if pre_release.is_empty() && build.is_empty() {
588            return Self::new_empty(major, minor, patch);
589        }
590
591        Self {
592            major,
593            minor,
594            patch,
595            meta: Some(Box::new(VersionMeta { build, pre_release })),
596        }
597    }
598
599    pub fn build(&self) -> &[Identifier] {
600        self.meta.as_ref().map_or(&[], |meta| meta.build.as_slice())
601    }
602
603    pub fn pre_release(&self) -> &[Identifier] {
604        self.meta
605            .as_ref()
606            .map_or(&[], |meta| meta.pre_release.as_slice())
607    }
608
609    /// Consumes this version and returns owned components.
610    ///
611    /// This moves build and prerelease identifiers out without cloning them.
612    ///
613    /// ```rust
614    /// use nodejs_semver::{Identifier, Version, VersionParts};
615    ///
616    /// let version = Version::parse("1.2.3-alpha.1+build.7").unwrap();
617    /// let VersionParts {
618    ///     major,
619    ///     minor,
620    ///     patch,
621    ///     pre_release,
622    ///     build,
623    /// } = version.into_parts();
624    ///
625    /// assert_eq!((major, minor, patch), (1, 2, 3));
626    /// assert_eq!(
627    ///     pre_release,
628    ///     vec![Identifier::AlphaNumeric("alpha".into()), Identifier::Numeric(1)]
629    /// );
630    /// assert_eq!(
631    ///     build,
632    ///     vec![
633    ///         Identifier::AlphaNumeric("build".into()),
634    ///         Identifier::Numeric(7)
635    ///     ]
636    /// );
637    /// ```
638    pub fn into_parts(self) -> VersionParts {
639        let Version {
640            major,
641            minor,
642            patch,
643            meta,
644        } = self;
645
646        let (pre_release, build) = match meta {
647            Some(meta) => {
648                let VersionMeta { build, pre_release } = *meta;
649                (pre_release.into_vec(), build.into_vec())
650            }
651            None => (Vec::new(), Vec::new()),
652        };
653
654        VersionParts {
655            major,
656            minor,
657            patch,
658            pre_release,
659            build,
660        }
661    }
662
663    fn metadata_mut(&mut self) -> &mut VersionMeta {
664        self.meta.get_or_insert_with(|| {
665            Box::new(VersionMeta {
666                build: Identifiers::Empty,
667                pre_release: Identifiers::Empty,
668            })
669        })
670    }
671
672    fn clear_pre_release(&mut self) {
673        if let Some(meta) = &mut self.meta {
674            meta.pre_release.clear();
675            if meta.build.is_empty() {
676                self.meta = None;
677            }
678        }
679    }
680
681    pub(crate) fn push_pre_release(&mut self, identifier: Identifier) {
682        self.metadata_mut().pre_release.push(identifier);
683    }
684
685    fn set_pre_release(&mut self, pre_release: Vec<Identifier>) {
686        if pre_release.is_empty() {
687            self.clear_pre_release();
688        } else {
689            self.metadata_mut().pre_release = Identifiers::from_vec(pre_release);
690        }
691    }
692
693    fn pre_release_mut(&mut self) -> &mut Identifiers {
694        &mut self.metadata_mut().pre_release
695    }
696
697    /// True if this [Version] satisfies the given [Range].
698    pub fn satisfies(&self, range: &Range) -> bool {
699        range.satisfies(self)
700    }
701
702    /// True if this [Version] satisfies the given [Range], treating prerelease
703    /// versions as valid matches even when the range does not explicitly
704    /// mention one.
705    pub fn satisfies_with_prerelease(&self, range: &Range, include_prerelease: bool) -> bool {
706        range.satisfies_with_prerelease(self, include_prerelease)
707    }
708
709    /// True is this [Version] has a prerelease component.
710    pub fn is_prerelease(&self) -> bool {
711        !self.pre_release().is_empty()
712    }
713
714    /// Increment this [Version] according to the given release type, returning a new [Version].
715    ///
716    /// Mirrors the behavior of the `SemVer.inc` method in node-semver.
717    pub fn inc(
718        &self,
719        release: &str,
720        identifier: Option<&str>,
721        identifier_base: Option<IdentifierBase>,
722    ) -> Result<Version, IncrementError> {
723        let mut cloned = self.clone();
724        cloned.inc_mut(release, identifier, identifier_base)?;
725        Ok(cloned)
726    }
727
728    fn inc_mut(
729        &mut self,
730        release: &str,
731        identifier: Option<&str>,
732        identifier_base: Option<IdentifierBase>,
733    ) -> Result<&mut Self, IncrementError> {
734        let identifier_base = identifier_base.unwrap_or_default();
735        let identifier_base_is_false = identifier_base == IdentifierBase::False;
736        let identifier = identifier.and_then(|id| {
737            if id.is_empty() {
738                None
739            } else {
740                Some(id.to_string())
741            }
742        });
743
744        if release.starts_with("pre") {
745            if identifier.is_none() && identifier_base_is_false {
746                return Err(IncrementError::InvalidIncrementArgument(
747                    "identifier is empty".into(),
748                ));
749            }
750            if let Some(id) = identifier.as_deref() {
751                if !is_valid_prerelease_identifier(id) {
752                    return Err(IncrementError::InvalidIdentifier(id.to_string()));
753                }
754            }
755        }
756
757        match release {
758            "premajor" => {
759                self.clear_pre_release();
760                self.patch = 0;
761                self.minor = 0;
762                self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
763                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
764            }
765            "preminor" => {
766                self.clear_pre_release();
767                self.patch = 0;
768                self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
769                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
770            }
771            "prepatch" => {
772                self.clear_pre_release();
773                self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
774                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
775            }
776            "prerelease" => {
777                if self.pre_release().is_empty() {
778                    self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
779                }
780                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
781            }
782            "release" => {
783                if self.pre_release().is_empty() {
784                    return Err(IncrementError::NotAPrerelease(self.to_string()));
785                }
786                self.clear_pre_release();
787            }
788            "major" => {
789                if self.minor != 0 || self.patch != 0 || self.pre_release().is_empty() {
790                    self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
791                }
792                self.minor = 0;
793                self.patch = 0;
794                self.clear_pre_release();
795            }
796            "minor" => {
797                if self.patch != 0 || self.pre_release().is_empty() {
798                    self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
799                }
800                self.patch = 0;
801                self.clear_pre_release();
802            }
803            "patch" => {
804                if self.pre_release().is_empty() {
805                    self.patch = self.patch.checked_add(1).ok_or(IncrementError::Overflow)?;
806                }
807                self.clear_pre_release();
808            }
809            "pre" => {
810                self.apply_pre_increment(identifier.as_deref(), identifier_base)?;
811            }
812            _ => {
813                return Err(IncrementError::InvalidIncrementArgument(
814                    release.to_string(),
815                ));
816            }
817        }
818
819        Ok(self)
820    }
821
822    fn apply_pre_increment(
823        &mut self,
824        identifier: Option<&str>,
825        identifier_base: IdentifierBase,
826    ) -> Result<(), IncrementError> {
827        let base = identifier_base.base_value();
828        let identifier_base_is_false = identifier_base == IdentifierBase::False;
829        let identifier = identifier.map(|id| id.to_string());
830
831        if self.pre_release().is_empty() {
832            self.push_pre_release(Identifier::Numeric(base));
833        } else {
834            let mut incremented = false;
835            for ident in self.pre_release_mut().as_mut_slice().iter_mut().rev() {
836                if let Identifier::Numeric(num) = ident {
837                    *num = num.checked_add(1).ok_or(IncrementError::Overflow)?;
838                    incremented = true;
839                    break;
840                }
841            }
842
843            if !incremented {
844                if identifier_base_is_false {
845                    if let Some(id) = identifier.as_deref() {
846                        if id == join_prerelease_components(self.pre_release()) {
847                            return Err(IncrementError::InvalidIncrementArgument(
848                                "identifier already exists".into(),
849                            ));
850                        }
851                    }
852                }
853                self.push_pre_release(Identifier::Numeric(base));
854            }
855        }
856
857        if let Some(id) = identifier {
858            let prerelease = if identifier_base_is_false {
859                vec![Identifier::AlphaNumeric(id.clone())]
860            } else {
861                vec![
862                    Identifier::AlphaNumeric(id.clone()),
863                    Identifier::Numeric(base),
864                ]
865            };
866
867            if let Some(first) = self.pre_release().first() {
868                if compare_identifier_and_str(first, &id) == Ordering::Equal {
869                    if !matches!(self.pre_release().get(1), Some(Identifier::Numeric(_))) {
870                        self.set_pre_release(prerelease);
871                    }
872                } else {
873                    self.set_pre_release(prerelease);
874                }
875            } else {
876                self.set_pre_release(prerelease);
877            }
878        }
879
880        Ok(())
881    }
882
883    /// Parse a semver string into a [Version].
884    ///
885    /// ```rust
886    #[doc = include_str!("../examples/parse.rs")]
887    /// ```
888    pub fn parse<S: AsRef<str>>(input: S) -> Result<Version, SemverError> {
889        let mut input = input.as_ref();
890
891        if input.len() > MAX_LENGTH {
892            return Err(max_length_error(input));
893        }
894
895        if let Some(version) = version_fast::parse(input) {
896            return Ok(version);
897        }
898
899        match version.parse_next(&mut input) {
900            Ok(version) => Ok(version),
901            Err(err) => Err(semver_error_from_parse(input, err)),
902        }
903    }
904
905    /// difference between two [Version]s by the release type,
906    /// or `None` if the [Version]s are the same.
907    ///
908    /// ```rust
909    #[doc = include_str!("../examples/diff.rs")]
910    /// ```
911    pub fn diff(&self, other: &Self) -> Option<VersionDiff> {
912        let cmp_result = self.cmp(other);
913
914        if cmp_result == Ordering::Equal {
915            return None;
916        }
917
918        let self_higher = cmp_result == Ordering::Greater;
919        let high_version = if self_higher { self } else { other };
920        let low_version = if self_higher { other } else { self };
921        let high_has_pre = high_version.is_prerelease();
922        let low_has_pre = low_version.is_prerelease();
923
924        if low_has_pre && !high_has_pre {
925            // Going from prerelease -> no prerelease requires some special casing
926
927            // If the low version has only a major, then it will always be a major
928            // Some examples:
929            // 1.0.0-1 -> 1.0.0
930            // 1.0.0-1 -> 1.1.1
931            // 1.0.0-1 -> 2.0.0
932            if low_version.patch == 0 && low_version.minor == 0 {
933                return Some(VersionDiff::Major);
934            }
935
936            // Otherwise it can be determined by checking the high version
937            if high_version.patch != 0 {
938                // anything higher than a patch bump would result in the wrong version
939                return Some(VersionDiff::Patch);
940            }
941
942            if high_version.minor != 0 {
943                // anything higher than a minor bump would result in the wrong version
944                return Some(VersionDiff::Minor);
945            }
946
947            // bumping major/minor/patch all have same result
948            return Some(VersionDiff::Major);
949        }
950
951        if self.major != other.major {
952            if high_has_pre {
953                return Some(VersionDiff::PreMajor);
954            }
955
956            return Some(VersionDiff::Major);
957        }
958
959        if self.minor != other.minor {
960            if high_has_pre {
961                return Some(VersionDiff::PreMinor);
962            }
963
964            return Some(VersionDiff::Minor);
965        }
966
967        if self.patch != other.patch {
968            if high_has_pre {
969                return Some(VersionDiff::PrePatch);
970            }
971
972            return Some(VersionDiff::Patch);
973        }
974
975        // high and low are preleases
976        Some(VersionDiff::PreRelease)
977    }
978}
979
980impl PartialEq for Version {
981    fn eq(&self, other: &Self) -> bool {
982        self.major == other.major
983            && self.minor == other.minor
984            && self.patch == other.patch
985            && self.pre_release() == other.pre_release()
986    }
987}
988
989impl Eq for Version {}
990
991impl std::hash::Hash for Version {
992    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
993        self.major.hash(state);
994        self.minor.hash(state);
995        self.patch.hash(state);
996        self.pre_release().hash(state);
997    }
998}
999
1000impl fmt::Display for Version {
1001    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1002        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
1003
1004        for (i, ident) in self.pre_release().iter().enumerate() {
1005            if i == 0 {
1006                write!(f, "-")?;
1007            } else {
1008                write!(f, ".")?;
1009            }
1010            write!(f, "{}", ident)?;
1011        }
1012
1013        for (i, ident) in self.build().iter().enumerate() {
1014            if i == 0 {
1015                write!(f, "+")?;
1016            } else {
1017                write!(f, ".")?;
1018            }
1019            write!(f, "{}", ident)?;
1020        }
1021
1022        Ok(())
1023    }
1024}
1025
1026macro_rules! impl_from_unsigned_for_version {
1027    ($($t:ident),+) => {
1028        $(
1029            impl ::std::convert::From<($t, $t, $t)> for Version {
1030                fn from((major, minor, patch): ($t, $t, $t)) -> Self {
1031                    Version::new_empty(major as u64, minor as u64, patch as u64)
1032                }
1033            }
1034
1035            impl ::std::convert::From<($t, $t, $t, $t)> for Version {
1036                fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
1037                    Version::new_with_pre_release_identifier(
1038                        major as u64,
1039                        minor as u64,
1040                        patch as u64,
1041                        Identifier::Numeric(pre_release as u64),
1042                    )
1043                }
1044            }
1045        )+
1046    }
1047}
1048
1049macro_rules! impl_from_signed_for_version {
1050    ($($t:ident),+) => {
1051        $(
1052            impl ::std::convert::From<($t, $t, $t)> for Version {
1053                fn from((major, minor, patch): ($t, $t, $t)) -> Self {
1054                    debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
1055                    debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
1056                    debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
1057
1058                    Version::new_empty(major as u64, minor as u64, patch as u64)
1059                }
1060            }
1061
1062            impl ::std::convert::From<($t, $t, $t, $t)> for Version {
1063                fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
1064                    debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
1065                    debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
1066                    debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
1067                    debug_assert!(pre_release >= 0, "Version pre-release must be non-negative, got {}", pre_release);
1068
1069                    Version::new_with_pre_release_identifier(
1070                        major as u64,
1071                        minor as u64,
1072                        patch as u64,
1073                        Identifier::Numeric(pre_release as u64),
1074                    )
1075                }
1076            }
1077        )+
1078    }
1079}
1080
1081impl_from_unsigned_for_version!(u8, u16, u32, u64, usize);
1082impl_from_signed_for_version!(i8, i16, i32, i64, isize);
1083
1084impl std::str::FromStr for Version {
1085    type Err = SemverError;
1086    fn from_str(s: &str) -> Result<Self, Self::Err> {
1087        Version::parse(s)
1088    }
1089}
1090
1091impl cmp::PartialOrd for Version {
1092    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
1093        Some(self.cmp(other))
1094    }
1095}
1096
1097impl cmp::Ord for Version {
1098    fn cmp(&self, other: &Version) -> cmp::Ordering {
1099        match self.major.cmp(&other.major) {
1100            Ordering::Equal => {}
1101            //if difference in major version, just return result
1102            order_result => return order_result,
1103        }
1104
1105        match self.minor.cmp(&other.minor) {
1106            Ordering::Equal => {}
1107            //if difference in minor version, just return result
1108            order_result => return order_result,
1109        }
1110
1111        match self.patch.cmp(&other.patch) {
1112            Ordering::Equal => {}
1113            //if difference in patch version, just return result
1114            order_result => return order_result,
1115        }
1116
1117        match (self.pre_release().len(), other.pre_release().len()) {
1118            //if no pre_release string, they're equal
1119            (0, 0) => Ordering::Equal,
1120            //if other has a pre-release string, but this doesn't, this one is greater
1121            (0, _) => Ordering::Greater,
1122            //if this one has a pre-release string, but other doesn't this one is less than
1123            (_, 0) => Ordering::Less,
1124            // if both have pre_release strings, compare the strings and return the result
1125            (_, _) => self.pre_release().cmp(other.pre_release()),
1126        }
1127    }
1128}
1129
1130enum Extras {
1131    Build(Vec<Identifier>),
1132    Release(Vec<Identifier>),
1133    ReleaseAndBuild((Vec<Identifier>, Vec<Identifier>)),
1134}
1135
1136impl Extras {
1137    fn values(self) -> (Vec<Identifier>, Vec<Identifier>) {
1138        use Extras::*;
1139        match self {
1140            Release(ident) => (ident, Vec::new()),
1141            Build(ident) => (Vec::new(), ident),
1142            ReleaseAndBuild(ident) => ident,
1143        }
1144    }
1145}
1146
1147/// <valid semver> ::= <version core>
1148///                 | <version core> "-" <pre-release>
1149///                 | <version core> "+" <build>
1150///                 | <version core> "-" <pre-release> "+" <build>
1151fn version<'s>(input: &mut &'s str) -> ModalResult<Version, SemverParseError<&'s str>> {
1152    (
1153        opt(alt((literal("v"), literal("V")))),
1154        space0,
1155        version_core,
1156        extras,
1157    )
1158        .map(|(_, _, (major, minor, patch), (pre_release, build))| {
1159            Version::new(major, minor, patch, pre_release, build)
1160        })
1161        .context("version")
1162        .parse_next(input)
1163}
1164
1165fn extras<'s>(
1166    input: &mut &'s str,
1167) -> ModalResult<(Vec<Identifier>, Vec<Identifier>), SemverParseError<&'s str>> {
1168    Parser::map(
1169        opt(alt((
1170            Parser::map((pre_release, build), Extras::ReleaseAndBuild),
1171            Parser::map(pre_release, Extras::Release),
1172            Parser::map(build, Extras::Build),
1173        ))),
1174        |extras| match extras {
1175            Some(extras) => extras.values(),
1176            _ => Default::default(),
1177        },
1178    )
1179    .parse_next(input)
1180}
1181
1182/// <version core> ::= <major> "." <minor> "." <patch>
1183fn version_core<'s>(
1184    input: &mut &'s str,
1185) -> ModalResult<(u64, u64, u64), SemverParseError<&'s str>> {
1186    (number, literal("."), number, literal("."), number)
1187        .map(|(major, _, minor, _, patch)| (major, minor, patch))
1188        .context("version core")
1189        .parse_next(input)
1190}
1191
1192// I believe build, pre_release, and identifier are not 100% spec compliant.
1193fn build<'s>(input: &mut &'s str) -> ModalResult<Vec<Identifier>, SemverParseError<&'s str>> {
1194    preceded(literal("+"), separated(1.., identifier, literal(".")))
1195        .context("build version")
1196        .parse_next(input)
1197}
1198
1199fn pre_release<'s>(input: &mut &'s str) -> ModalResult<Vec<Identifier>, SemverParseError<&'s str>> {
1200    preceded(opt(literal("-")), separated(1.., identifier, literal(".")))
1201        .context("pre_release version")
1202        .parse_next(input)
1203}
1204
1205fn identifier<'s>(input: &mut &'s str) -> ModalResult<Identifier, SemverParseError<&'s str>> {
1206    Parser::map(
1207        take_while(1.., |x: char| AsChar::is_alphanum(x as u8) || x == '-'),
1208        |s: &str| {
1209            str::parse::<u64>(s)
1210                .map(Identifier::Numeric)
1211                .unwrap_or_else(|_err| Identifier::AlphaNumeric(s.to_string()))
1212        },
1213    )
1214    .context("identifier")
1215    .parse_next(input)
1216}
1217
1218fn is_valid_prerelease_identifier(identifier: &str) -> bool {
1219    !identifier.is_empty()
1220        && identifier.split('.').all(|segment| {
1221            !segment.is_empty()
1222                && segment
1223                    .chars()
1224                    .all(|ch| ch.is_ascii_alphanumeric() || ch == '-')
1225        })
1226}
1227
1228fn join_prerelease_components(pre_release: &[Identifier]) -> String {
1229    pre_release
1230        .iter()
1231        .map(|ident| ident.to_string())
1232        .collect::<Vec<_>>()
1233        .join(".")
1234}
1235
1236fn compare_identifier_and_str(existing: &Identifier, other: &str) -> Ordering {
1237    match existing {
1238        Identifier::Numeric(value) => {
1239            if other.chars().all(|c| c.is_ascii_digit()) {
1240                match other.parse::<u128>() {
1241                    Ok(other_num) => (*value as u128).cmp(&other_num),
1242                    Err(_) => Ordering::Less,
1243                }
1244            } else {
1245                Ordering::Less
1246            }
1247        }
1248        Identifier::AlphaNumeric(value) => {
1249            if other.chars().all(|c| c.is_ascii_digit()) {
1250                Ordering::Greater
1251            } else {
1252                value.as_str().cmp(other)
1253            }
1254        }
1255    }
1256}
1257
1258pub(crate) fn number<'s>(input: &mut &'s str) -> ModalResult<u64, SemverParseError<&'s str>> {
1259    #[allow(suspicious_double_ref_op)]
1260    let copied = input.clone();
1261
1262    Parser::try_map(Parser::take(digit1), |raw| {
1263        let value = parse_u64_digits(raw).map_err(|e| SemverParseError {
1264            input: copied,
1265            context: None,
1266            kind: Some(SemverErrorKind::ParseIntError(e)),
1267        })?;
1268
1269        if value > MAX_SAFE_INTEGER {
1270            return Err(SemverParseError {
1271                input: copied,
1272                context: None,
1273                kind: Some(SemverErrorKind::MaxIntError(value)),
1274            });
1275        }
1276
1277        Ok(value)
1278    })
1279    .context("number component")
1280    .parse_next(input)
1281}
1282
1283fn parse_u64_digits(raw: &str) -> Result<u64, ParseIntError> {
1284    let mut value = 0u64;
1285
1286    for ch in raw.bytes() {
1287        let digit = u64::from(ch - b'0');
1288        let Some(next) = value
1289            .checked_mul(10)
1290            .and_then(|value| value.checked_add(digit))
1291        else {
1292            return raw.parse::<u64>();
1293        };
1294        value = next;
1295    }
1296
1297    Ok(value)
1298}
1299
1300#[cfg(test)]
1301mod tests {
1302    use super::Identifier::*;
1303    use super::*;
1304
1305    use pretty_assertions::assert_eq;
1306
1307    #[derive(Debug)]
1308    struct IncrementCase {
1309        version: String,
1310        release: String,
1311        expected: Option<String>,
1312        identifier: Option<String>,
1313        identifier_base: Option<IdentifierBase>,
1314    }
1315
1316    #[derive(Debug)]
1317    struct IncrementCaseRaw {
1318        version: &'static str,
1319        release: &'static str,
1320        expected: Option<&'static str>,
1321        identifier: Option<&'static str>,
1322        identifier_base: Option<IdentifierBase>,
1323    }
1324
1325    macro_rules! ic {
1326        ($v:literal, $r:literal, $e:literal) => {
1327            IncrementCaseRaw {
1328                version: $v,
1329                release: $r,
1330                expected: Some($e),
1331                identifier: None,
1332                identifier_base: None,
1333            }
1334        };
1335        ($v:literal, $r:literal, None) => {
1336            IncrementCaseRaw {
1337                version: $v,
1338                release: $r,
1339                expected: None,
1340                identifier: None,
1341                identifier_base: None,
1342            }
1343        };
1344        ($v:literal, $r:literal, $e:literal, $id:literal) => {
1345            IncrementCaseRaw {
1346                version: $v,
1347                release: $r,
1348                expected: Some($e),
1349                identifier: Some($id),
1350                identifier_base: None,
1351            }
1352        };
1353        ($v:literal, $r:literal, None, $id:literal) => {
1354            IncrementCaseRaw {
1355                version: $v,
1356                release: $r,
1357                expected: None,
1358                identifier: Some($id),
1359                identifier_base: None,
1360            }
1361        };
1362        ($v:literal, $r:literal, $e:literal, $id:literal, $base:expr) => {
1363            IncrementCaseRaw {
1364                version: $v,
1365                release: $r,
1366                expected: Some($e),
1367                identifier: Some($id),
1368                identifier_base: Some($base),
1369            }
1370        };
1371        ($v:literal, $r:literal, None, $id:literal, $base:expr) => {
1372            IncrementCaseRaw {
1373                version: $v,
1374                release: $r,
1375                expected: None,
1376                identifier: Some($id),
1377                identifier_base: Some($base),
1378            }
1379        };
1380    }
1381
1382    // Generated from node-semver/test/fixtures/increments.js so tests don't rely on external JS fixtures.
1383    static INCREMENT_CASES: &[IncrementCaseRaw] = &[
1384        ic!("1.2.3", "major", "2.0.0"),
1385        ic!("1.2.3", "minor", "1.3.0"),
1386        ic!("1.2.3", "patch", "1.2.4"),
1387        ic!("1.2.3tag", "major", "2.0.0"),
1388        ic!("1.2.3-tag", "major", "2.0.0"),
1389        ic!("1.2.3", "fake", None),
1390        ic!("1.2.0-0", "patch", "1.2.0"),
1391        ic!("fake", "major", None),
1392        ic!("1.2.3-4", "major", "2.0.0"),
1393        ic!("1.2.3-4", "minor", "1.3.0"),
1394        ic!("1.2.3-4", "patch", "1.2.3"),
1395        ic!("1.2.3-alpha.0.beta", "major", "2.0.0"),
1396        ic!("1.2.3-alpha.0.beta", "minor", "1.3.0"),
1397        ic!("1.2.3-alpha.0.beta", "patch", "1.2.3"),
1398        ic!("1.2.4", "prerelease", "1.2.5-0"),
1399        ic!("1.2.3-0", "prerelease", "1.2.3-1"),
1400        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1"),
1401        ic!("1.2.3-alpha.1", "prerelease", "1.2.3-alpha.2"),
1402        ic!("1.2.3-alpha.2", "prerelease", "1.2.3-alpha.3"),
1403        ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-alpha.1.beta"),
1404        ic!("1.2.3-alpha.1.beta", "prerelease", "1.2.3-alpha.2.beta"),
1405        ic!("1.2.3-alpha.2.beta", "prerelease", "1.2.3-alpha.3.beta"),
1406        ic!(
1407            "1.2.3-alpha.10.0.beta",
1408            "prerelease",
1409            "1.2.3-alpha.10.1.beta"
1410        ),
1411        ic!(
1412            "1.2.3-alpha.10.1.beta",
1413            "prerelease",
1414            "1.2.3-alpha.10.2.beta"
1415        ),
1416        ic!(
1417            "1.2.3-alpha.10.2.beta",
1418            "prerelease",
1419            "1.2.3-alpha.10.3.beta"
1420        ),
1421        ic!(
1422            "1.2.3-alpha.10.beta.0",
1423            "prerelease",
1424            "1.2.3-alpha.10.beta.1"
1425        ),
1426        ic!(
1427            "1.2.3-alpha.10.beta.1",
1428            "prerelease",
1429            "1.2.3-alpha.10.beta.2"
1430        ),
1431        ic!(
1432            "1.2.3-alpha.10.beta.2",
1433            "prerelease",
1434            "1.2.3-alpha.10.beta.3"
1435        ),
1436        ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-alpha.10.beta"),
1437        ic!("1.2.3-alpha.10.beta", "prerelease", "1.2.3-alpha.11.beta"),
1438        ic!("1.2.3-alpha.11.beta", "prerelease", "1.2.3-alpha.12.beta"),
1439        ic!("1.0.0", "prepatch", "1.0.1-alpha.1.1a.0", "alpha.1.1a"),
1440        ic!("1.2.0", "prepatch", "1.2.1-0"),
1441        ic!("1.2.0-1", "prepatch", "1.2.1-0"),
1442        ic!("1.2.0", "preminor", "1.3.0-0"),
1443        ic!("1.2.3-1", "preminor", "1.3.0-0"),
1444        ic!("1.2.0", "premajor", "2.0.0-0"),
1445        ic!("1.2.3-1", "premajor", "2.0.0-0"),
1446        ic!("1.2.0-1", "minor", "1.2.0"),
1447        ic!("1.0.0-1", "major", "1.0.0"),
1448        ic!("1.0.0-1", "release", "1.0.0"),
1449        ic!("1.2.0-1", "release", "1.2.0"),
1450        ic!("1.2.3-1", "release", "1.2.3"),
1451        ic!("1.2.3", "release", None),
1452        ic!("1.2.3", "major", "2.0.0", "dev"),
1453        ic!("1.2.3", "minor", "1.3.0", "dev"),
1454        ic!("1.2.3", "patch", "1.2.4", "dev"),
1455        ic!("1.2.3tag", "major", "2.0.0", "dev"),
1456        ic!("1.2.3-tag", "major", "2.0.0", "dev"),
1457        ic!("1.2.3", "fake", None, "dev"),
1458        ic!("1.2.0-0", "patch", "1.2.0", "dev"),
1459        ic!("fake", "major", None, "dev"),
1460        ic!("1.2.3-4", "major", "2.0.0", "dev"),
1461        ic!("1.2.3-4", "minor", "1.3.0", "dev"),
1462        ic!("1.2.3-4", "patch", "1.2.3", "dev"),
1463        ic!("1.2.3-alpha.0.beta", "major", "2.0.0", "dev"),
1464        ic!("1.2.3-alpha.0.beta", "minor", "1.3.0", "dev"),
1465        ic!("1.2.3-alpha.0.beta", "patch", "1.2.3", "dev"),
1466        ic!("1.2.4", "prerelease", "1.2.5-dev.0", "dev"),
1467        ic!("1.2.3-0", "prerelease", "1.2.3-dev.0", "dev"),
1468        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-dev.0", "dev"),
1469        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1", "alpha"),
1470        ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1471        ic!(
1472            "1.2.3-alpha.0.beta",
1473            "prerelease",
1474            "1.2.3-alpha.1.beta",
1475            "alpha"
1476        ),
1477        ic!("1.2.3-alpha.10.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1478        ic!(
1479            "1.2.3-alpha.10.0.beta",
1480            "prerelease",
1481            "1.2.3-alpha.10.1.beta",
1482            "alpha"
1483        ),
1484        ic!(
1485            "1.2.3-alpha.10.1.beta",
1486            "prerelease",
1487            "1.2.3-alpha.10.2.beta",
1488            "alpha"
1489        ),
1490        ic!(
1491            "1.2.3-alpha.10.2.beta",
1492            "prerelease",
1493            "1.2.3-alpha.10.3.beta",
1494            "alpha"
1495        ),
1496        ic!("1.2.3-alpha.10.beta.0", "prerelease", "1.2.3-dev.0", "dev"),
1497        ic!(
1498            "1.2.3-alpha.10.beta.0",
1499            "prerelease",
1500            "1.2.3-alpha.10.beta.1",
1501            "alpha"
1502        ),
1503        ic!(
1504            "1.2.3-alpha.10.beta.1",
1505            "prerelease",
1506            "1.2.3-alpha.10.beta.2",
1507            "alpha"
1508        ),
1509        ic!(
1510            "1.2.3-alpha.10.beta.2",
1511            "prerelease",
1512            "1.2.3-alpha.10.beta.3",
1513            "alpha"
1514        ),
1515        ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-dev.0", "dev"),
1516        ic!(
1517            "1.2.3-alpha.9.beta",
1518            "prerelease",
1519            "1.2.3-alpha.10.beta",
1520            "alpha"
1521        ),
1522        ic!(
1523            "1.2.3-alpha.10.beta",
1524            "prerelease",
1525            "1.2.3-alpha.11.beta",
1526            "alpha"
1527        ),
1528        ic!(
1529            "1.2.3-alpha.11.beta",
1530            "prerelease",
1531            "1.2.3-alpha.12.beta",
1532            "alpha"
1533        ),
1534        ic!("1.2.0", "prepatch", "1.2.1-dev.0", "dev"),
1535        ic!("1.2.0-1", "prepatch", "1.2.1-dev.0", "dev"),
1536        ic!("1.2.0", "preminor", "1.3.0-dev.0", "dev"),
1537        ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1538        ic!("1.2.0", "premajor", "2.0.0-dev.0", "dev"),
1539        ic!("1.2.3-1", "premajor", "2.0.0-dev.0", "dev"),
1540        ic!(
1541            "1.2.3-1",
1542            "premajor",
1543            "2.0.0-dev.1",
1544            "dev",
1545            IdentifierBase::Value(1)
1546        ),
1547        ic!("1.2.0-1", "minor", "1.2.0", "dev"),
1548        ic!("1.0.0-1", "major", "1.0.0", "dev"),
1549        ic!("1.2.3-dev.bar", "prerelease", "1.2.3-dev.0", "dev"),
1550        ic!("1.2.3-0", "prerelease", "1.2.3-1.0", "1"),
1551        ic!("1.2.3-1.0", "prerelease", "1.2.3-1.1", "1"),
1552        ic!("1.2.3-1.1", "prerelease", "1.2.3-1.2", "1"),
1553        ic!("1.2.3-1.1", "prerelease", "1.2.3-2.0", "2"),
1554        ic!(
1555            "1.2.0-1",
1556            "prerelease",
1557            "1.2.0-alpha.0",
1558            "alpha",
1559            IdentifierBase::Value(0)
1560        ),
1561        ic!(
1562            "1.2.1",
1563            "prerelease",
1564            "1.2.2-alpha.0",
1565            "alpha",
1566            IdentifierBase::Value(0)
1567        ),
1568        ic!(
1569            "0.2.0",
1570            "prerelease",
1571            "0.2.1-alpha.0",
1572            "alpha",
1573            IdentifierBase::Value(0)
1574        ),
1575        ic!(
1576            "1.2.2",
1577            "prerelease",
1578            "1.2.3-alpha.1",
1579            "alpha",
1580            IdentifierBase::Value(1)
1581        ),
1582        ic!(
1583            "1.2.3",
1584            "prerelease",
1585            "1.2.4-alpha.1",
1586            "alpha",
1587            IdentifierBase::Value(1)
1588        ),
1589        ic!(
1590            "1.2.4",
1591            "prerelease",
1592            "1.2.5-alpha.1",
1593            "alpha",
1594            IdentifierBase::Value(1)
1595        ),
1596        ic!(
1597            "1.2.0",
1598            "prepatch",
1599            "1.2.1-dev.1",
1600            "dev",
1601            IdentifierBase::Value(1)
1602        ),
1603        ic!(
1604            "1.2.0-1",
1605            "prepatch",
1606            "1.2.1-dev.1",
1607            "dev",
1608            IdentifierBase::Value(1)
1609        ),
1610        ic!(
1611            "1.2.0",
1612            "premajor",
1613            "2.0.0-dev.0",
1614            "dev",
1615            IdentifierBase::Value(0)
1616        ),
1617        ic!(
1618            "1.2.3-1",
1619            "premajor",
1620            "2.0.0-dev.0",
1621            "dev",
1622            IdentifierBase::Value(0)
1623        ),
1624        ic!(
1625            "1.2.3-dev.bar",
1626            "prerelease",
1627            "1.2.3-dev.0",
1628            "dev",
1629            IdentifierBase::Value(0)
1630        ),
1631        ic!(
1632            "1.2.3-dev.bar",
1633            "prerelease",
1634            "1.2.3-dev.1",
1635            "dev",
1636            IdentifierBase::Value(1)
1637        ),
1638        ic!(
1639            "1.2.3-dev.bar",
1640            "prerelease",
1641            "1.2.3-dev.bar.0",
1642            "",
1643            IdentifierBase::Value(0)
1644        ),
1645        ic!(
1646            "1.2.3-dev.bar",
1647            "prerelease",
1648            "1.2.3-dev.bar.1",
1649            "",
1650            IdentifierBase::Value(1)
1651        ),
1652        ic!(
1653            "1.2.0",
1654            "preminor",
1655            "1.3.0-dev.1",
1656            "dev",
1657            IdentifierBase::Value(1)
1658        ),
1659        ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1660        ic!(
1661            "1.2.0",
1662            "prerelease",
1663            "1.2.1-1",
1664            "",
1665            IdentifierBase::Value(1)
1666        ),
1667        ic!(
1668            "1.2.0-1",
1669            "prerelease",
1670            "1.2.0-alpha",
1671            "alpha",
1672            IdentifierBase::False
1673        ),
1674        ic!(
1675            "1.2.1",
1676            "prerelease",
1677            "1.2.2-alpha",
1678            "alpha",
1679            IdentifierBase::False
1680        ),
1681        ic!(
1682            "1.2.2",
1683            "prerelease",
1684            "1.2.3-alpha",
1685            "alpha",
1686            IdentifierBase::False
1687        ),
1688        ic!(
1689            "1.2.0",
1690            "prepatch",
1691            "1.2.1-dev",
1692            "dev",
1693            IdentifierBase::False
1694        ),
1695        ic!(
1696            "1.2.0-1",
1697            "prepatch",
1698            "1.2.1-dev",
1699            "dev",
1700            IdentifierBase::False
1701        ),
1702        ic!(
1703            "1.2.0",
1704            "premajor",
1705            "2.0.0-dev",
1706            "dev",
1707            IdentifierBase::False
1708        ),
1709        ic!(
1710            "1.2.3-1",
1711            "premajor",
1712            "2.0.0-dev",
1713            "dev",
1714            IdentifierBase::False
1715        ),
1716        ic!(
1717            "1.2.3-dev.bar",
1718            "prerelease",
1719            "1.2.3-dev",
1720            "dev",
1721            IdentifierBase::False
1722        ),
1723        ic!(
1724            "1.2.3-dev.bar",
1725            "prerelease",
1726            "1.2.3-dev.baz",
1727            "dev.baz",
1728            IdentifierBase::False
1729        ),
1730        ic!(
1731            "1.2.0",
1732            "preminor",
1733            "1.3.0-dev",
1734            "dev",
1735            IdentifierBase::False
1736        ),
1737        ic!(
1738            "1.2.3-1",
1739            "preminor",
1740            "1.3.0-dev",
1741            "dev",
1742            IdentifierBase::False
1743        ),
1744        ic!(
1745            "1.2.3-dev",
1746            "prerelease",
1747            None,
1748            "dev",
1749            IdentifierBase::False
1750        ),
1751        ic!(
1752            "1.2.0-dev",
1753            "premajor",
1754            "2.0.0-dev",
1755            "dev",
1756            IdentifierBase::False
1757        ),
1758        ic!(
1759            "1.2.0-dev",
1760            "preminor",
1761            "1.3.0-beta",
1762            "beta",
1763            IdentifierBase::False
1764        ),
1765        ic!(
1766            "1.2.0-dev",
1767            "prepatch",
1768            "1.2.1-dev",
1769            "dev",
1770            IdentifierBase::False
1771        ),
1772        ic!("1.2.0", "prerelease", None, "", IdentifierBase::False),
1773        ic!(
1774            "1.0.0-rc.1+build.4",
1775            "prerelease",
1776            "1.0.0-rc.2",
1777            "rc",
1778            IdentifierBase::False
1779        ),
1780        ic!("1.2.0", "prerelease", None, "invalid/preid"),
1781        ic!("1.2.0", "prerelease", None, "invalid+build"),
1782        ic!("1.2.0beta", "prerelease", None, "invalid/preid"),
1783    ];
1784
1785    fn version_without_build(version: &Version) -> String {
1786        let mut output = format!("{}.{}.{}", version.major, version.minor, version.patch);
1787        if !version.pre_release().is_empty() {
1788            output.push('-');
1789            output.push_str(&join_prerelease_components(version.pre_release()));
1790        }
1791        output
1792    }
1793
1794    fn load_increment_cases() -> Vec<IncrementCase> {
1795        INCREMENT_CASES
1796            .iter()
1797            .map(|raw| IncrementCase {
1798                version: raw.version.to_string(),
1799                release: raw.release.to_string(),
1800                expected: raw.expected.map(str::to_string),
1801                identifier: raw.identifier.map(str::to_string),
1802                identifier_base: raw.identifier_base,
1803            })
1804            .collect()
1805    }
1806
1807    #[test]
1808    fn trivial_version_number() {
1809        let v = Version::parse("1.2.34").unwrap();
1810
1811        assert_eq!((v.major(), v.minor(), v.patch()), (1, 2, 34));
1812        assert_eq!(
1813            v,
1814            Version::new(1, 2, 34, Vec::with_capacity(2), Vec::with_capacity(2))
1815        );
1816    }
1817
1818    #[test]
1819    fn version_with_build() {
1820        let v = Version::parse("1.2.34+123.456").unwrap();
1821
1822        assert_eq!(
1823            v,
1824            Version::new(
1825                1,
1826                2,
1827                34,
1828                Vec::with_capacity(2),
1829                vec![Numeric(123), Numeric(456)]
1830            )
1831        );
1832    }
1833
1834    #[test]
1835    fn version_with_pre_release() {
1836        let v = Version::parse("1.2.34-abc.123").unwrap();
1837
1838        assert_eq!(
1839            v,
1840            Version::new(
1841                1,
1842                2,
1843                34,
1844                vec![AlphaNumeric("abc".into()), Numeric(123)],
1845                Vec::with_capacity(2),
1846            )
1847        );
1848    }
1849
1850    #[test]
1851    fn version_with_pre_release_and_build() {
1852        let v = Version::parse("1.2.34-abc.123+1").unwrap();
1853
1854        assert_eq!(
1855            v,
1856            Version::new(
1857                1,
1858                2,
1859                34,
1860                vec![AlphaNumeric("abc".into()), Numeric(123)],
1861                vec![Numeric(1)],
1862            )
1863        );
1864    }
1865
1866    #[test]
1867    fn into_parts_with_metadata() {
1868        let parts = Version::parse("1.2.34-abc.123+1").unwrap().into_parts();
1869
1870        assert_eq!(
1871            parts,
1872            VersionParts {
1873                major: 1,
1874                minor: 2,
1875                patch: 34,
1876                pre_release: vec![AlphaNumeric("abc".into()), Numeric(123)],
1877                build: vec![Numeric(1)],
1878            }
1879        );
1880    }
1881
1882    #[test]
1883    fn into_parts_without_metadata() {
1884        let parts = Version::parse("1.2.34").unwrap().into_parts();
1885
1886        assert_eq!(
1887            parts,
1888            VersionParts {
1889                major: 1,
1890                minor: 2,
1891                patch: 34,
1892                pre_release: Vec::new(),
1893                build: Vec::new(),
1894            }
1895        );
1896    }
1897
1898    #[test]
1899    fn pre_release_that_could_look_numeric_at_first() {
1900        let v = Version::parse("1.0.0-rc.2-migration").unwrap();
1901
1902        assert_eq!(
1903            v,
1904            Version::new(
1905                1,
1906                0,
1907                0,
1908                vec![
1909                    Identifier::AlphaNumeric("rc".into()),
1910                    Identifier::AlphaNumeric("2-migration".into())
1911                ],
1912                vec![],
1913            )
1914        );
1915    }
1916
1917    #[test]
1918    fn comparison_with_different_major_version() {
1919        let lesser_version = Version::new(
1920            1,
1921            2,
1922            34,
1923            vec![AlphaNumeric("abc".into()), Numeric(123)],
1924            vec![],
1925        );
1926        let greater_version = Version::new(
1927            2,
1928            2,
1929            34,
1930            vec![AlphaNumeric("abc".into()), Numeric(123)],
1931            vec![],
1932        );
1933        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1934        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1935    }
1936    #[test]
1937    fn comparison_with_different_minor_version() {
1938        let lesser_version = Version::new(
1939            1,
1940            2,
1941            34,
1942            vec![AlphaNumeric("abc".into()), Numeric(123)],
1943            vec![],
1944        );
1945        let greater_version = Version::new(
1946            1,
1947            3,
1948            34,
1949            vec![AlphaNumeric("abc".into()), Numeric(123)],
1950            vec![],
1951        );
1952        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1953        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1954    }
1955
1956    #[test]
1957    fn comparison_with_different_patch_version() {
1958        let lesser_version = Version::new(
1959            1,
1960            2,
1961            34,
1962            vec![AlphaNumeric("abc".into()), Numeric(123)],
1963            vec![],
1964        );
1965        let greater_version = Version::new(
1966            1,
1967            2,
1968            56,
1969            vec![AlphaNumeric("abc".into()), Numeric(123)],
1970            vec![],
1971        );
1972        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1973        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1974    }
1975
1976    #[test]
1977    //confirms the comparison matches the pre-release comparison example in the SemVer spec.
1978    //ie checks that 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.
1979    //for simplicity just checks them in order. Assumes that the transitive property holds. So if a < b & b < c then a < c.
1980    fn comparison_with_different_pre_release_version() {
1981        let v1_alpha = Version::new(1, 0, 0, vec![AlphaNumeric("alpha".into())], vec![]);
1982        let v1_alpha1 = Version::new(
1983            1,
1984            0,
1985            0,
1986            vec![AlphaNumeric("alpha".into()), Numeric(1)],
1987            vec![],
1988        );
1989        assert_eq!(v1_alpha.cmp(&v1_alpha1), Ordering::Less);
1990        let v1_alpha_beta = Version::new(
1991            1,
1992            0,
1993            0,
1994            vec![AlphaNumeric("alpha".into()), AlphaNumeric("beta".into())],
1995            vec![],
1996        );
1997        assert_eq!(v1_alpha1.cmp(&v1_alpha_beta), Ordering::Less);
1998        let v1_beta = Version::new(1, 0, 0, vec![AlphaNumeric("beta".into())], vec![]);
1999        assert_eq!(v1_alpha_beta.cmp(&v1_beta), Ordering::Less);
2000        let v1_beta2 = Version::new(
2001            1,
2002            0,
2003            0,
2004            vec![AlphaNumeric("beta".into()), Numeric(2)],
2005            vec![],
2006        );
2007        assert_eq!(v1_beta.cmp(&v1_beta2), Ordering::Less);
2008        let v1_beta11 = Version::new(
2009            1,
2010            0,
2011            0,
2012            vec![AlphaNumeric("beta".into()), Numeric(11)],
2013            vec![],
2014        );
2015        assert_eq!(v1_beta2.cmp(&v1_beta11), Ordering::Less);
2016        let v1_rc1 = Version::new(1, 0, 0, vec![AlphaNumeric("rc".into()), Numeric(1)], vec![]);
2017        assert_eq!(v1_beta11.cmp(&v1_rc1), Ordering::Less);
2018        let v1 = Version::new(1, 0, 0, vec![], vec![]);
2019        assert_eq!(v1_rc1.cmp(&v1), Ordering::Less);
2020    }
2021
2022    #[test]
2023    fn individual_version_component_has_an_upper_bound() {
2024        let out_of_range = MAX_SAFE_INTEGER + 1;
2025        let v = Version::parse(format!("1.2.{}", out_of_range));
2026        assert_eq!(
2027            v.expect_err("Parse should have failed.").to_string(),
2028            "Integer component of semver string is larger than JavaScript's Number.MAX_SAFE_INTEGER: 900719925474100"
2029        );
2030    }
2031
2032    #[test]
2033    fn version_string_limited_to_256_characters() {
2034        let prebuild = (0..257).map(|_| "X").collect::<Vec<_>>().join("");
2035        let version_string = format!("1.1.1-{}", prebuild);
2036        let v = Version::parse(version_string.clone());
2037
2038        assert_eq!(
2039            v.expect_err("Parse should have failed").to_string(),
2040            "Semver string can't be longer than 256 characters."
2041        );
2042
2043        let ok_version = version_string[0..255].to_string();
2044        let v = Version::parse(ok_version);
2045        assert!(v.is_ok());
2046    }
2047
2048    #[test]
2049    fn version_prefixed_with_v() {
2050        // TODO: This is part of strict parsing for nodejs-semver!
2051        let v = Version::parse("v1.2.3").unwrap();
2052        assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
2053    }
2054
2055    #[test]
2056    fn version_prefixed_with_v_space() {
2057        // TODO: Loose parsing supports this, so
2058        let v = Version::parse("v 1.2.3").unwrap();
2059        assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
2060    }
2061
2062    fn asset_version_diff(left: &str, right: &str, expected: &str) {
2063        let left = Version::parse(left).unwrap();
2064        let right = Version::parse(right).unwrap();
2065        let expected_diff = match expected {
2066            "major" => Some(VersionDiff::Major),
2067            "minor" => Some(VersionDiff::Minor),
2068            "patch" => Some(VersionDiff::Patch),
2069            "premajor" => Some(VersionDiff::PreMajor),
2070            "preminor" => Some(VersionDiff::PreMinor),
2071            "prepatch" => Some(VersionDiff::PrePatch),
2072            "null" => None,
2073            _ => unreachable!("unexpected version diff"),
2074        };
2075
2076        assert_eq!(
2077            left.diff(&right),
2078            expected_diff,
2079            "left: {}, right: {}",
2080            left,
2081            right
2082        );
2083    }
2084
2085    #[test]
2086    fn version_diffs() {
2087        let cases = vec![
2088            ("1.2.3", "0.2.3", "major"),
2089            ("0.2.3", "1.2.3", "major"),
2090            ("1.4.5", "0.2.3", "major"),
2091            ("1.2.3", "2.0.0-pre", "premajor"),
2092            ("2.0.0-pre", "1.2.3", "premajor"),
2093            ("1.2.3", "1.3.3", "minor"),
2094            ("1.0.1", "1.1.0-pre", "preminor"),
2095            ("1.2.3", "1.2.4", "patch"),
2096            ("1.2.3", "1.2.4-pre", "prepatch"),
2097            ("1.0.0", "1.0.0", "null"),
2098            ("1.0.0-1", "1.0.0-1", "null"),
2099            ("0.0.2-1", "0.0.2", "patch"),
2100            ("0.0.2-1", "0.0.3", "patch"),
2101            ("0.0.2-1", "0.1.0", "minor"),
2102            ("0.0.2-1", "1.0.0", "major"),
2103            ("0.1.0-1", "0.1.0", "minor"),
2104            ("1.0.0-1", "2.0.0-1", "premajor"),
2105            ("1.0.0-1", "1.1.0-1", "preminor"),
2106            ("1.0.0-1", "1.0.1-1", "prepatch"),
2107        ];
2108
2109        for case in cases {
2110            asset_version_diff(case.0, case.1, case.2);
2111        }
2112    }
2113
2114    #[test]
2115    fn increments_match_node_semver_fixture() {
2116        for case in load_increment_cases() {
2117            if let Some(expected) = &case.expected {
2118                let version = Version::parse(&case.version).unwrap_or_else(|e| {
2119                    panic!(
2120                        "expected to parse {} but failed: {}",
2121                        case.version,
2122                        e.to_string()
2123                    )
2124                });
2125                let before = version.to_string();
2126                let build = version.build().to_vec();
2127                let incremented = version
2128                    .inc(
2129                        &case.release,
2130                        case.identifier.as_deref(),
2131                        case.identifier_base,
2132                    )
2133                    .unwrap_or_else(|e| {
2134                        panic!(
2135                            "expected {} {} to succeed but errored: {}",
2136                            case.version, case.release, e
2137                        )
2138                    });
2139
2140                assert_eq!(
2141                    version_without_build(&incremented),
2142                    expected.as_str(),
2143                    "incrementing {} {} {:?} {:?}",
2144                    case.version,
2145                    case.release,
2146                    case.identifier,
2147                    case.identifier_base
2148                );
2149                assert_eq!(
2150                    incremented.build(),
2151                    build.as_slice(),
2152                    "build metadata should remain unchanged after increment"
2153                );
2154                assert_eq!(
2155                    version.to_string(),
2156                    before,
2157                    "original version should remain unchanged"
2158                );
2159            } else if let Ok(version) = Version::parse(&case.version) {
2160                let before = version.to_string();
2161                assert!(
2162                    version
2163                        .inc(
2164                            &case.release,
2165                            case.identifier.as_deref(),
2166                            case.identifier_base
2167                        )
2168                        .is_err(),
2169                    "expected {} {} to fail",
2170                    case.version,
2171                    case.release
2172                );
2173                assert_eq!(
2174                    version.to_string(),
2175                    before,
2176                    "version should stay unchanged on error"
2177                );
2178            }
2179        }
2180    }
2181
2182    #[test]
2183    fn invalid_increment_errors_match_node_semver() {
2184        let version = Version::parse("1.2.3").unwrap();
2185        let err = version
2186            .inc("prerelease", Some(""), Some(IdentifierBase::False))
2187            .unwrap_err();
2188        assert_eq!(
2189            err.to_string(),
2190            "invalid increment argument: identifier is empty"
2191        );
2192        assert_eq!(version.to_string(), "1.2.3");
2193
2194        let version = Version::parse("1.2.3-dev").unwrap();
2195        let err = version
2196            .inc("prerelease", Some("dev"), Some(IdentifierBase::False))
2197            .unwrap_err();
2198        assert_eq!(
2199            err.to_string(),
2200            "invalid increment argument: identifier already exists"
2201        );
2202        assert_eq!(version.to_string(), "1.2.3-dev");
2203
2204        let version = Version::parse("1.2.3").unwrap();
2205        let err = version
2206            .inc("prerelease", Some("invalid/preid"), None)
2207            .unwrap_err();
2208        assert_eq!(err.to_string(), "invalid identifier: invalid/preid");
2209        assert_eq!(version.to_string(), "1.2.3");
2210    }
2211}
2212
2213#[cfg(feature = "serde")]
2214#[cfg(test)]
2215mod serde_tests {
2216    use super::Identifier::*;
2217    use super::*;
2218
2219    #[test]
2220    fn version_serde() {
2221        let v = Version::new(
2222            1,
2223            2,
2224            3,
2225            vec![AlphaNumeric("abc".into()), Numeric(123)],
2226            vec![AlphaNumeric("build".into())],
2227        );
2228
2229        let serialized = serde_json::to_string(&v).unwrap();
2230        let deserialized: Version = serde_json::from_str(&serialized).unwrap();
2231
2232        assert_eq!(v, deserialized);
2233    }
2234}