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;
9
10use thiserror::Error;
11
12pub use range::*;
13
14mod parse;
15mod range;
16mod scan;
17mod version_fast;
18
19/// JavaScript's
20/// [MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER).
21/// This is used to determine the maximum value for integer components in a
22/// JS-compatible way.
23pub const MAX_SAFE_INTEGER: u64 = 900_719_925_474_099;
24
25/// Maximum length of a semver string.
26pub const MAX_LENGTH: usize = 256;
27
28/// A version or range could not be parsed.
29///
30/// This error does not retain the input or provide detailed diagnostics.
31#[derive(Debug, Clone, Copy, Error, Eq, PartialEq)]
32#[error("Invalid semantic version or range")]
33pub struct SemverError;
34
35/**
36An Identifier type for build and prerelease metadata.
37*/
38#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
39pub enum Identifier {
40    /// An identifier that's solely numbers.
41    Numeric(u64),
42    /// An identifier with letters and numbers.
43    AlphaNumeric(String),
44}
45
46impl fmt::Display for Identifier {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        match self {
49            Identifier::Numeric(n) => write!(f, "{}", n),
50            Identifier::AlphaNumeric(s) => write!(f, "{}", s),
51        }
52    }
53}
54
55/// difference between two versions by the release type
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub enum VersionDiff {
58    Major,
59    Minor,
60    Patch,
61    PreMajor,
62    PreMinor,
63    PrePatch,
64    PreRelease,
65}
66
67/// difference between two versions
68pub type ReleaseType = VersionDiff;
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum IdentifierBase {
72    /// Mirrors `identifierBase === false` in node-semver.
73    False,
74    /// Any other truthy/falsy value. Only the zero/non-zero nature matters.
75    Value(u64),
76}
77
78impl Default for IdentifierBase {
79    fn default() -> Self {
80        IdentifierBase::Value(0)
81    }
82}
83
84impl IdentifierBase {
85    fn base_value(self) -> u64 {
86        match self {
87            IdentifierBase::False => 0,
88            IdentifierBase::Value(v) => {
89                if v == 0 {
90                    0
91                } else {
92                    1
93                }
94            }
95        }
96    }
97}
98
99impl From<bool> for IdentifierBase {
100    fn from(value: bool) -> Self {
101        if value {
102            IdentifierBase::Value(1)
103        } else {
104            IdentifierBase::False
105        }
106    }
107}
108
109impl From<u64> for IdentifierBase {
110    fn from(value: u64) -> Self {
111        IdentifierBase::Value(value)
112    }
113}
114
115impl From<usize> for IdentifierBase {
116    fn from(value: usize) -> Self {
117        IdentifierBase::Value(value as u64)
118    }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Error)]
122pub enum IncrementError {
123    #[error("invalid identifier: {0}")]
124    InvalidIdentifier(String),
125    #[error("invalid increment argument: {0}")]
126    InvalidIncrementArgument(String),
127    #[error("version {0} is not a prerelease")]
128    NotAPrerelease(String),
129    #[error("increment would overflow a version component")]
130    Overflow,
131}
132
133impl fmt::Display for VersionDiff {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        match self {
136            VersionDiff::Major => write!(f, "major"),
137            VersionDiff::Minor => write!(f, "minor"),
138            VersionDiff::Patch => write!(f, "patch"),
139            VersionDiff::PreMajor => write!(f, "premajor"),
140            VersionDiff::PreMinor => write!(f, "preminor"),
141            VersionDiff::PrePatch => write!(f, "prepatch"),
142            VersionDiff::PreRelease => write!(f, "prerelease"),
143        }
144    }
145}
146
147/**
148A semantic version, conformant to the [semver spec](https://semver.org/spec/v2.0.0.html).
149*/
150#[derive(Clone, Debug)]
151pub struct Version {
152    major: u64,
153    minor: u64,
154    patch: u64,
155    meta: Option<Box<VersionMeta>>,
156}
157
158/// Owned components of a [`Version`].
159#[derive(Clone, Debug, Eq, PartialEq)]
160pub struct VersionParts {
161    pub major: u64,
162    pub minor: u64,
163    pub patch: u64,
164    pub pre_release: Vec<Identifier>,
165    pub build: Vec<Identifier>,
166}
167
168#[derive(Clone, Debug)]
169struct VersionMeta {
170    build: Identifiers,
171    pre_release: Identifiers,
172}
173
174#[derive(Clone, Debug)]
175pub(crate) enum Identifiers {
176    Empty,
177    One(Identifier),
178    Two([Identifier; 2]),
179    Many(Vec<Identifier>),
180}
181
182impl Identifiers {
183    pub(crate) fn from_vec(mut identifiers: Vec<Identifier>) -> Self {
184        match identifiers.len() {
185            0 => Self::Empty,
186            1 => Self::One(identifiers.pop().unwrap()),
187            2 => {
188                let second = identifiers.pop().unwrap();
189                let first = identifiers.pop().unwrap();
190                Self::Two([first, second])
191            }
192            _ => Self::Many(identifiers),
193        }
194    }
195
196    fn into_vec(self) -> Vec<Identifier> {
197        match self {
198            Self::Empty => Vec::new(),
199            Self::One(identifier) => vec![identifier],
200            Self::Two(identifiers) => Vec::from(identifiers),
201            Self::Many(identifiers) => identifiers,
202        }
203    }
204
205    fn as_slice(&self) -> &[Identifier] {
206        match self {
207            Self::Empty => &[],
208            Self::One(identifier) => std::slice::from_ref(identifier),
209            Self::Two(identifiers) => identifiers.as_slice(),
210            Self::Many(identifiers) => identifiers.as_slice(),
211        }
212    }
213
214    fn as_mut_slice(&mut self) -> &mut [Identifier] {
215        match self {
216            Self::Empty => &mut [],
217            Self::One(identifier) => std::slice::from_mut(identifier),
218            Self::Two(identifiers) => identifiers.as_mut_slice(),
219            Self::Many(identifiers) => identifiers.as_mut_slice(),
220        }
221    }
222
223    fn is_empty(&self) -> bool {
224        matches!(self, Self::Empty)
225    }
226
227    fn clear(&mut self) {
228        *self = Self::Empty;
229    }
230
231    pub(crate) fn push(&mut self, identifier: Identifier) {
232        match std::mem::replace(self, Self::Empty) {
233            Self::Empty => *self = Self::One(identifier),
234            Self::One(existing) => *self = Self::Two([existing, identifier]),
235            Self::Two([first, second]) => *self = Self::Many(vec![first, second, identifier]),
236            Self::Many(mut identifiers) => {
237                identifiers.push(identifier);
238                *self = Self::Many(identifiers);
239            }
240        }
241    }
242}
243
244#[cfg(feature = "serde")]
245impl Serialize for Version {
246    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
247        s.collect_str(self)
248    }
249}
250
251#[cfg(feature = "serde")]
252impl<'de> Deserialize<'de> for Version {
253    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
254        let s = String::deserialize(d)?;
255        s.parse().map_err(serde::de::Error::custom)
256    }
257}
258
259impl Version {
260    /// Returns the major version.
261    pub fn major(&self) -> u64 {
262        self.major
263    }
264
265    /// Returns the minor version.
266    pub fn minor(&self) -> u64 {
267        self.minor
268    }
269
270    /// Returns the patch version.
271    pub fn patch(&self) -> u64 {
272        self.patch
273    }
274
275    pub fn new(
276        major: u64,
277        minor: u64,
278        patch: u64,
279        pre_release: Vec<Identifier>,
280        build: Vec<Identifier>,
281    ) -> Self {
282        let meta = if pre_release.is_empty() && build.is_empty() {
283            return Self::new_empty(major, minor, patch);
284        } else {
285            Some(Box::new(VersionMeta {
286                build: Identifiers::from_vec(build),
287                pre_release: Identifiers::from_vec(pre_release),
288            }))
289        };
290
291        Self {
292            major,
293            minor,
294            patch,
295            meta,
296        }
297    }
298
299    pub(crate) fn new_empty(major: u64, minor: u64, patch: u64) -> Self {
300        Self {
301            major,
302            minor,
303            patch,
304            meta: None,
305        }
306    }
307
308    fn new_with_pre_release_identifier(
309        major: u64,
310        minor: u64,
311        patch: u64,
312        pre_release: Identifier,
313    ) -> Self {
314        Self {
315            major,
316            minor,
317            patch,
318            meta: Some(Box::new(VersionMeta {
319                build: Identifiers::Empty,
320                pre_release: Identifiers::One(pre_release),
321            })),
322        }
323    }
324
325    pub(crate) fn new_with_identifiers(
326        major: u64,
327        minor: u64,
328        patch: u64,
329        pre_release: Identifiers,
330        build: Identifiers,
331    ) -> Self {
332        if pre_release.is_empty() && build.is_empty() {
333            return Self::new_empty(major, minor, patch);
334        }
335
336        Self {
337            major,
338            minor,
339            patch,
340            meta: Some(Box::new(VersionMeta { build, pre_release })),
341        }
342    }
343
344    pub fn build(&self) -> &[Identifier] {
345        self.meta.as_ref().map_or(&[], |meta| meta.build.as_slice())
346    }
347
348    pub fn pre_release(&self) -> &[Identifier] {
349        self.meta
350            .as_ref()
351            .map_or(&[], |meta| meta.pre_release.as_slice())
352    }
353
354    /// Consumes this version and returns owned components.
355    ///
356    /// This moves build and prerelease identifiers out without cloning them.
357    ///
358    /// ```rust
359    /// use nodejs_semver::{Identifier, Version, VersionParts};
360    ///
361    /// let version = Version::parse("1.2.3-alpha.1+build.7").unwrap();
362    /// let VersionParts {
363    ///     major,
364    ///     minor,
365    ///     patch,
366    ///     pre_release,
367    ///     build,
368    /// } = version.into_parts();
369    ///
370    /// assert_eq!((major, minor, patch), (1, 2, 3));
371    /// assert_eq!(
372    ///     pre_release,
373    ///     vec![Identifier::AlphaNumeric("alpha".into()), Identifier::Numeric(1)]
374    /// );
375    /// assert_eq!(
376    ///     build,
377    ///     vec![
378    ///         Identifier::AlphaNumeric("build".into()),
379    ///         Identifier::Numeric(7)
380    ///     ]
381    /// );
382    /// ```
383    pub fn into_parts(self) -> VersionParts {
384        let Version {
385            major,
386            minor,
387            patch,
388            meta,
389        } = self;
390
391        let (pre_release, build) = match meta {
392            Some(meta) => {
393                let VersionMeta { build, pre_release } = *meta;
394                (pre_release.into_vec(), build.into_vec())
395            }
396            None => (Vec::new(), Vec::new()),
397        };
398
399        VersionParts {
400            major,
401            minor,
402            patch,
403            pre_release,
404            build,
405        }
406    }
407
408    fn metadata_mut(&mut self) -> &mut VersionMeta {
409        self.meta.get_or_insert_with(|| {
410            Box::new(VersionMeta {
411                build: Identifiers::Empty,
412                pre_release: Identifiers::Empty,
413            })
414        })
415    }
416
417    fn clear_pre_release(&mut self) {
418        if let Some(meta) = &mut self.meta {
419            meta.pre_release.clear();
420            if meta.build.is_empty() {
421                self.meta = None;
422            }
423        }
424    }
425
426    pub(crate) fn push_pre_release(&mut self, identifier: Identifier) {
427        self.metadata_mut().pre_release.push(identifier);
428    }
429
430    fn set_pre_release(&mut self, pre_release: Vec<Identifier>) {
431        if pre_release.is_empty() {
432            self.clear_pre_release();
433        } else {
434            self.metadata_mut().pre_release = Identifiers::from_vec(pre_release);
435        }
436    }
437
438    fn pre_release_mut(&mut self) -> &mut Identifiers {
439        &mut self.metadata_mut().pre_release
440    }
441
442    /// True if this [Version] satisfies the given [Range].
443    pub fn satisfies(&self, range: &Range) -> bool {
444        range.satisfies(self)
445    }
446
447    /// True if this [Version] satisfies the given [Range], treating prerelease
448    /// versions as valid matches even when the range does not explicitly
449    /// mention one.
450    pub fn satisfies_with_prerelease(&self, range: &Range, include_prerelease: bool) -> bool {
451        range.satisfies_with_prerelease(self, include_prerelease)
452    }
453
454    /// True is this [Version] has a prerelease component.
455    pub fn is_prerelease(&self) -> bool {
456        !self.pre_release().is_empty()
457    }
458
459    /// Increment this [Version] according to the given release type, returning a new [Version].
460    ///
461    /// Mirrors the behavior of the `SemVer.inc` method in node-semver.
462    pub fn inc(
463        &self,
464        release: &str,
465        identifier: Option<&str>,
466        identifier_base: Option<IdentifierBase>,
467    ) -> Result<Version, IncrementError> {
468        let mut cloned = self.clone();
469        cloned.inc_mut(release, identifier, identifier_base)?;
470        Ok(cloned)
471    }
472
473    fn inc_mut(
474        &mut self,
475        release: &str,
476        identifier: Option<&str>,
477        identifier_base: Option<IdentifierBase>,
478    ) -> Result<&mut Self, IncrementError> {
479        let identifier_base = identifier_base.unwrap_or_default();
480        let identifier_base_is_false = identifier_base == IdentifierBase::False;
481        let identifier = identifier.and_then(|id| {
482            if id.is_empty() {
483                None
484            } else {
485                Some(id.to_string())
486            }
487        });
488
489        if release.starts_with("pre") {
490            if identifier.is_none() && identifier_base_is_false {
491                return Err(IncrementError::InvalidIncrementArgument(
492                    "identifier is empty".into(),
493                ));
494            }
495            if let Some(id) = identifier.as_deref() {
496                if !is_valid_prerelease_identifier(id) {
497                    return Err(IncrementError::InvalidIdentifier(id.to_string()));
498                }
499            }
500        }
501
502        match release {
503            "premajor" => {
504                self.clear_pre_release();
505                self.patch = 0;
506                self.minor = 0;
507                self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
508                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
509            }
510            "preminor" => {
511                self.clear_pre_release();
512                self.patch = 0;
513                self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
514                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
515            }
516            "prepatch" => {
517                self.clear_pre_release();
518                self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
519                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
520            }
521            "prerelease" => {
522                if self.pre_release().is_empty() {
523                    self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
524                }
525                self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
526            }
527            "release" => {
528                if self.pre_release().is_empty() {
529                    return Err(IncrementError::NotAPrerelease(self.to_string()));
530                }
531                self.clear_pre_release();
532            }
533            "major" => {
534                if self.minor != 0 || self.patch != 0 || self.pre_release().is_empty() {
535                    self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
536                }
537                self.minor = 0;
538                self.patch = 0;
539                self.clear_pre_release();
540            }
541            "minor" => {
542                if self.patch != 0 || self.pre_release().is_empty() {
543                    self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
544                }
545                self.patch = 0;
546                self.clear_pre_release();
547            }
548            "patch" => {
549                if self.pre_release().is_empty() {
550                    self.patch = self.patch.checked_add(1).ok_or(IncrementError::Overflow)?;
551                }
552                self.clear_pre_release();
553            }
554            "pre" => {
555                self.apply_pre_increment(identifier.as_deref(), identifier_base)?;
556            }
557            _ => {
558                return Err(IncrementError::InvalidIncrementArgument(
559                    release.to_string(),
560                ));
561            }
562        }
563
564        Ok(self)
565    }
566
567    fn apply_pre_increment(
568        &mut self,
569        identifier: Option<&str>,
570        identifier_base: IdentifierBase,
571    ) -> Result<(), IncrementError> {
572        let base = identifier_base.base_value();
573        let identifier_base_is_false = identifier_base == IdentifierBase::False;
574        let identifier = identifier.map(|id| id.to_string());
575
576        if self.pre_release().is_empty() {
577            self.push_pre_release(Identifier::Numeric(base));
578        } else {
579            let mut incremented = false;
580            for ident in self.pre_release_mut().as_mut_slice().iter_mut().rev() {
581                if let Identifier::Numeric(num) = ident {
582                    *num = num.checked_add(1).ok_or(IncrementError::Overflow)?;
583                    incremented = true;
584                    break;
585                }
586            }
587
588            if !incremented {
589                if identifier_base_is_false {
590                    if let Some(id) = identifier.as_deref() {
591                        if id == join_prerelease_components(self.pre_release()) {
592                            return Err(IncrementError::InvalidIncrementArgument(
593                                "identifier already exists".into(),
594                            ));
595                        }
596                    }
597                }
598                self.push_pre_release(Identifier::Numeric(base));
599            }
600        }
601
602        if let Some(id) = identifier {
603            let prerelease = if identifier_base_is_false {
604                vec![Identifier::AlphaNumeric(id.clone())]
605            } else {
606                vec![
607                    Identifier::AlphaNumeric(id.clone()),
608                    Identifier::Numeric(base),
609                ]
610            };
611
612            if let Some(first) = self.pre_release().first() {
613                if compare_identifier_and_str(first, &id) == Ordering::Equal {
614                    if !matches!(self.pre_release().get(1), Some(Identifier::Numeric(_))) {
615                        self.set_pre_release(prerelease);
616                    }
617                } else {
618                    self.set_pre_release(prerelease);
619                }
620            } else {
621                self.set_pre_release(prerelease);
622            }
623        }
624
625        Ok(())
626    }
627
628    /// Parse a semver string into a [Version].
629    ///
630    /// ```rust
631    #[doc = include_str!("../examples/parse.rs")]
632    /// ```
633    pub fn parse<S: AsRef<str>>(input: S) -> Result<Version, SemverError> {
634        let input = input.as_ref();
635
636        if input.len() > MAX_LENGTH {
637            return Err(SemverError);
638        }
639
640        if let Some(version) = version_fast::parse(input) {
641            return Ok(version);
642        }
643
644        parse::version(input).ok_or(SemverError)
645    }
646
647    /// difference between two [Version]s by the release type,
648    /// or `None` if the [Version]s are the same.
649    ///
650    /// ```rust
651    #[doc = include_str!("../examples/diff.rs")]
652    /// ```
653    pub fn diff(&self, other: &Self) -> Option<VersionDiff> {
654        let cmp_result = self.cmp(other);
655
656        if cmp_result == Ordering::Equal {
657            return None;
658        }
659
660        let self_higher = cmp_result == Ordering::Greater;
661        let high_version = if self_higher { self } else { other };
662        let low_version = if self_higher { other } else { self };
663        let high_has_pre = high_version.is_prerelease();
664        let low_has_pre = low_version.is_prerelease();
665
666        if low_has_pre && !high_has_pre {
667            // Going from prerelease -> no prerelease requires some special casing
668
669            // If the low version has only a major, then it will always be a major
670            // Some examples:
671            // 1.0.0-1 -> 1.0.0
672            // 1.0.0-1 -> 1.1.1
673            // 1.0.0-1 -> 2.0.0
674            if low_version.patch == 0 && low_version.minor == 0 {
675                return Some(VersionDiff::Major);
676            }
677
678            // Otherwise it can be determined by checking the high version
679            if high_version.patch != 0 {
680                // anything higher than a patch bump would result in the wrong version
681                return Some(VersionDiff::Patch);
682            }
683
684            if high_version.minor != 0 {
685                // anything higher than a minor bump would result in the wrong version
686                return Some(VersionDiff::Minor);
687            }
688
689            // bumping major/minor/patch all have same result
690            return Some(VersionDiff::Major);
691        }
692
693        if self.major != other.major {
694            if high_has_pre {
695                return Some(VersionDiff::PreMajor);
696            }
697
698            return Some(VersionDiff::Major);
699        }
700
701        if self.minor != other.minor {
702            if high_has_pre {
703                return Some(VersionDiff::PreMinor);
704            }
705
706            return Some(VersionDiff::Minor);
707        }
708
709        if self.patch != other.patch {
710            if high_has_pre {
711                return Some(VersionDiff::PrePatch);
712            }
713
714            return Some(VersionDiff::Patch);
715        }
716
717        // high and low are preleases
718        Some(VersionDiff::PreRelease)
719    }
720}
721
722impl PartialEq for Version {
723    fn eq(&self, other: &Self) -> bool {
724        self.major == other.major
725            && self.minor == other.minor
726            && self.patch == other.patch
727            && self.pre_release() == other.pre_release()
728    }
729}
730
731impl Eq for Version {}
732
733impl std::hash::Hash for Version {
734    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
735        self.major.hash(state);
736        self.minor.hash(state);
737        self.patch.hash(state);
738        self.pre_release().hash(state);
739    }
740}
741
742impl fmt::Display for Version {
743    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
745
746        for (i, ident) in self.pre_release().iter().enumerate() {
747            if i == 0 {
748                write!(f, "-")?;
749            } else {
750                write!(f, ".")?;
751            }
752            write!(f, "{}", ident)?;
753        }
754
755        for (i, ident) in self.build().iter().enumerate() {
756            if i == 0 {
757                write!(f, "+")?;
758            } else {
759                write!(f, ".")?;
760            }
761            write!(f, "{}", ident)?;
762        }
763
764        Ok(())
765    }
766}
767
768macro_rules! impl_from_unsigned_for_version {
769    ($($t:ident),+) => {
770        $(
771            impl ::std::convert::From<($t, $t, $t)> for Version {
772                fn from((major, minor, patch): ($t, $t, $t)) -> Self {
773                    Version::new_empty(major as u64, minor as u64, patch as u64)
774                }
775            }
776
777            impl ::std::convert::From<($t, $t, $t, $t)> for Version {
778                fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
779                    Version::new_with_pre_release_identifier(
780                        major as u64,
781                        minor as u64,
782                        patch as u64,
783                        Identifier::Numeric(pre_release as u64),
784                    )
785                }
786            }
787        )+
788    }
789}
790
791macro_rules! impl_from_signed_for_version {
792    ($($t:ident),+) => {
793        $(
794            impl ::std::convert::From<($t, $t, $t)> for Version {
795                fn from((major, minor, patch): ($t, $t, $t)) -> Self {
796                    debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
797                    debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
798                    debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
799
800                    Version::new_empty(major as u64, minor as u64, patch as u64)
801                }
802            }
803
804            impl ::std::convert::From<($t, $t, $t, $t)> for Version {
805                fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
806                    debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
807                    debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
808                    debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
809                    debug_assert!(pre_release >= 0, "Version pre-release must be non-negative, got {}", pre_release);
810
811                    Version::new_with_pre_release_identifier(
812                        major as u64,
813                        minor as u64,
814                        patch as u64,
815                        Identifier::Numeric(pre_release as u64),
816                    )
817                }
818            }
819        )+
820    }
821}
822
823impl_from_unsigned_for_version!(u8, u16, u32, u64, usize);
824impl_from_signed_for_version!(i8, i16, i32, i64, isize);
825
826impl std::str::FromStr for Version {
827    type Err = SemverError;
828    fn from_str(s: &str) -> Result<Self, Self::Err> {
829        Version::parse(s)
830    }
831}
832
833impl cmp::PartialOrd for Version {
834    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
835        Some(self.cmp(other))
836    }
837}
838
839impl cmp::Ord for Version {
840    fn cmp(&self, other: &Version) -> cmp::Ordering {
841        match self.major.cmp(&other.major) {
842            Ordering::Equal => {}
843            //if difference in major version, just return result
844            order_result => return order_result,
845        }
846
847        match self.minor.cmp(&other.minor) {
848            Ordering::Equal => {}
849            //if difference in minor version, just return result
850            order_result => return order_result,
851        }
852
853        match self.patch.cmp(&other.patch) {
854            Ordering::Equal => {}
855            //if difference in patch version, just return result
856            order_result => return order_result,
857        }
858
859        match (self.pre_release().len(), other.pre_release().len()) {
860            //if no pre_release string, they're equal
861            (0, 0) => Ordering::Equal,
862            //if other has a pre-release string, but this doesn't, this one is greater
863            (0, _) => Ordering::Greater,
864            //if this one has a pre-release string, but other doesn't this one is less than
865            (_, 0) => Ordering::Less,
866            // if both have pre_release strings, compare the strings and return the result
867            (_, _) => self.pre_release().cmp(other.pre_release()),
868        }
869    }
870}
871
872fn is_valid_prerelease_identifier(identifier: &str) -> bool {
873    !identifier.is_empty()
874        && identifier.split('.').all(|segment| {
875            !segment.is_empty()
876                && segment
877                    .chars()
878                    .all(|ch| ch.is_ascii_alphanumeric() || ch == '-')
879        })
880}
881
882fn join_prerelease_components(pre_release: &[Identifier]) -> String {
883    pre_release
884        .iter()
885        .map(|ident| ident.to_string())
886        .collect::<Vec<_>>()
887        .join(".")
888}
889
890fn compare_identifier_and_str(existing: &Identifier, other: &str) -> Ordering {
891    match existing {
892        Identifier::Numeric(value) => {
893            if other.chars().all(|c| c.is_ascii_digit()) {
894                match other.parse::<u128>() {
895                    Ok(other_num) => (*value as u128).cmp(&other_num),
896                    Err(_) => Ordering::Less,
897                }
898            } else {
899                Ordering::Less
900            }
901        }
902        Identifier::AlphaNumeric(value) => {
903            if other.chars().all(|c| c.is_ascii_digit()) {
904                Ordering::Greater
905            } else {
906                value.as_str().cmp(other)
907            }
908        }
909    }
910}
911
912#[cfg(test)]
913mod tests {
914    use super::Identifier::*;
915    use super::*;
916
917    use pretty_assertions::assert_eq;
918
919    #[derive(Debug)]
920    struct IncrementCase {
921        version: String,
922        release: String,
923        expected: Option<String>,
924        identifier: Option<String>,
925        identifier_base: Option<IdentifierBase>,
926    }
927
928    #[derive(Debug)]
929    struct IncrementCaseRaw {
930        version: &'static str,
931        release: &'static str,
932        expected: Option<&'static str>,
933        identifier: Option<&'static str>,
934        identifier_base: Option<IdentifierBase>,
935    }
936
937    macro_rules! ic {
938        ($v:literal, $r:literal, $e:literal) => {
939            IncrementCaseRaw {
940                version: $v,
941                release: $r,
942                expected: Some($e),
943                identifier: None,
944                identifier_base: None,
945            }
946        };
947        ($v:literal, $r:literal, None) => {
948            IncrementCaseRaw {
949                version: $v,
950                release: $r,
951                expected: None,
952                identifier: None,
953                identifier_base: None,
954            }
955        };
956        ($v:literal, $r:literal, $e:literal, $id:literal) => {
957            IncrementCaseRaw {
958                version: $v,
959                release: $r,
960                expected: Some($e),
961                identifier: Some($id),
962                identifier_base: None,
963            }
964        };
965        ($v:literal, $r:literal, None, $id:literal) => {
966            IncrementCaseRaw {
967                version: $v,
968                release: $r,
969                expected: None,
970                identifier: Some($id),
971                identifier_base: None,
972            }
973        };
974        ($v:literal, $r:literal, $e:literal, $id:literal, $base:expr) => {
975            IncrementCaseRaw {
976                version: $v,
977                release: $r,
978                expected: Some($e),
979                identifier: Some($id),
980                identifier_base: Some($base),
981            }
982        };
983        ($v:literal, $r:literal, None, $id:literal, $base:expr) => {
984            IncrementCaseRaw {
985                version: $v,
986                release: $r,
987                expected: None,
988                identifier: Some($id),
989                identifier_base: Some($base),
990            }
991        };
992    }
993
994    // Generated from node-semver/test/fixtures/increments.js so tests don't rely on external JS fixtures.
995    static INCREMENT_CASES: &[IncrementCaseRaw] = &[
996        ic!("1.2.3", "major", "2.0.0"),
997        ic!("1.2.3", "minor", "1.3.0"),
998        ic!("1.2.3", "patch", "1.2.4"),
999        ic!("1.2.3tag", "major", "2.0.0"),
1000        ic!("1.2.3-tag", "major", "2.0.0"),
1001        ic!("1.2.3", "fake", None),
1002        ic!("1.2.0-0", "patch", "1.2.0"),
1003        ic!("fake", "major", None),
1004        ic!("1.2.3-4", "major", "2.0.0"),
1005        ic!("1.2.3-4", "minor", "1.3.0"),
1006        ic!("1.2.3-4", "patch", "1.2.3"),
1007        ic!("1.2.3-alpha.0.beta", "major", "2.0.0"),
1008        ic!("1.2.3-alpha.0.beta", "minor", "1.3.0"),
1009        ic!("1.2.3-alpha.0.beta", "patch", "1.2.3"),
1010        ic!("1.2.4", "prerelease", "1.2.5-0"),
1011        ic!("1.2.3-0", "prerelease", "1.2.3-1"),
1012        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1"),
1013        ic!("1.2.3-alpha.1", "prerelease", "1.2.3-alpha.2"),
1014        ic!("1.2.3-alpha.2", "prerelease", "1.2.3-alpha.3"),
1015        ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-alpha.1.beta"),
1016        ic!("1.2.3-alpha.1.beta", "prerelease", "1.2.3-alpha.2.beta"),
1017        ic!("1.2.3-alpha.2.beta", "prerelease", "1.2.3-alpha.3.beta"),
1018        ic!(
1019            "1.2.3-alpha.10.0.beta",
1020            "prerelease",
1021            "1.2.3-alpha.10.1.beta"
1022        ),
1023        ic!(
1024            "1.2.3-alpha.10.1.beta",
1025            "prerelease",
1026            "1.2.3-alpha.10.2.beta"
1027        ),
1028        ic!(
1029            "1.2.3-alpha.10.2.beta",
1030            "prerelease",
1031            "1.2.3-alpha.10.3.beta"
1032        ),
1033        ic!(
1034            "1.2.3-alpha.10.beta.0",
1035            "prerelease",
1036            "1.2.3-alpha.10.beta.1"
1037        ),
1038        ic!(
1039            "1.2.3-alpha.10.beta.1",
1040            "prerelease",
1041            "1.2.3-alpha.10.beta.2"
1042        ),
1043        ic!(
1044            "1.2.3-alpha.10.beta.2",
1045            "prerelease",
1046            "1.2.3-alpha.10.beta.3"
1047        ),
1048        ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-alpha.10.beta"),
1049        ic!("1.2.3-alpha.10.beta", "prerelease", "1.2.3-alpha.11.beta"),
1050        ic!("1.2.3-alpha.11.beta", "prerelease", "1.2.3-alpha.12.beta"),
1051        ic!("1.0.0", "prepatch", "1.0.1-alpha.1.1a.0", "alpha.1.1a"),
1052        ic!("1.2.0", "prepatch", "1.2.1-0"),
1053        ic!("1.2.0-1", "prepatch", "1.2.1-0"),
1054        ic!("1.2.0", "preminor", "1.3.0-0"),
1055        ic!("1.2.3-1", "preminor", "1.3.0-0"),
1056        ic!("1.2.0", "premajor", "2.0.0-0"),
1057        ic!("1.2.3-1", "premajor", "2.0.0-0"),
1058        ic!("1.2.0-1", "minor", "1.2.0"),
1059        ic!("1.0.0-1", "major", "1.0.0"),
1060        ic!("1.0.0-1", "release", "1.0.0"),
1061        ic!("1.2.0-1", "release", "1.2.0"),
1062        ic!("1.2.3-1", "release", "1.2.3"),
1063        ic!("1.2.3", "release", None),
1064        ic!("1.2.3", "major", "2.0.0", "dev"),
1065        ic!("1.2.3", "minor", "1.3.0", "dev"),
1066        ic!("1.2.3", "patch", "1.2.4", "dev"),
1067        ic!("1.2.3tag", "major", "2.0.0", "dev"),
1068        ic!("1.2.3-tag", "major", "2.0.0", "dev"),
1069        ic!("1.2.3", "fake", None, "dev"),
1070        ic!("1.2.0-0", "patch", "1.2.0", "dev"),
1071        ic!("fake", "major", None, "dev"),
1072        ic!("1.2.3-4", "major", "2.0.0", "dev"),
1073        ic!("1.2.3-4", "minor", "1.3.0", "dev"),
1074        ic!("1.2.3-4", "patch", "1.2.3", "dev"),
1075        ic!("1.2.3-alpha.0.beta", "major", "2.0.0", "dev"),
1076        ic!("1.2.3-alpha.0.beta", "minor", "1.3.0", "dev"),
1077        ic!("1.2.3-alpha.0.beta", "patch", "1.2.3", "dev"),
1078        ic!("1.2.4", "prerelease", "1.2.5-dev.0", "dev"),
1079        ic!("1.2.3-0", "prerelease", "1.2.3-dev.0", "dev"),
1080        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-dev.0", "dev"),
1081        ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1", "alpha"),
1082        ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1083        ic!(
1084            "1.2.3-alpha.0.beta",
1085            "prerelease",
1086            "1.2.3-alpha.1.beta",
1087            "alpha"
1088        ),
1089        ic!("1.2.3-alpha.10.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1090        ic!(
1091            "1.2.3-alpha.10.0.beta",
1092            "prerelease",
1093            "1.2.3-alpha.10.1.beta",
1094            "alpha"
1095        ),
1096        ic!(
1097            "1.2.3-alpha.10.1.beta",
1098            "prerelease",
1099            "1.2.3-alpha.10.2.beta",
1100            "alpha"
1101        ),
1102        ic!(
1103            "1.2.3-alpha.10.2.beta",
1104            "prerelease",
1105            "1.2.3-alpha.10.3.beta",
1106            "alpha"
1107        ),
1108        ic!("1.2.3-alpha.10.beta.0", "prerelease", "1.2.3-dev.0", "dev"),
1109        ic!(
1110            "1.2.3-alpha.10.beta.0",
1111            "prerelease",
1112            "1.2.3-alpha.10.beta.1",
1113            "alpha"
1114        ),
1115        ic!(
1116            "1.2.3-alpha.10.beta.1",
1117            "prerelease",
1118            "1.2.3-alpha.10.beta.2",
1119            "alpha"
1120        ),
1121        ic!(
1122            "1.2.3-alpha.10.beta.2",
1123            "prerelease",
1124            "1.2.3-alpha.10.beta.3",
1125            "alpha"
1126        ),
1127        ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-dev.0", "dev"),
1128        ic!(
1129            "1.2.3-alpha.9.beta",
1130            "prerelease",
1131            "1.2.3-alpha.10.beta",
1132            "alpha"
1133        ),
1134        ic!(
1135            "1.2.3-alpha.10.beta",
1136            "prerelease",
1137            "1.2.3-alpha.11.beta",
1138            "alpha"
1139        ),
1140        ic!(
1141            "1.2.3-alpha.11.beta",
1142            "prerelease",
1143            "1.2.3-alpha.12.beta",
1144            "alpha"
1145        ),
1146        ic!("1.2.0", "prepatch", "1.2.1-dev.0", "dev"),
1147        ic!("1.2.0-1", "prepatch", "1.2.1-dev.0", "dev"),
1148        ic!("1.2.0", "preminor", "1.3.0-dev.0", "dev"),
1149        ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1150        ic!("1.2.0", "premajor", "2.0.0-dev.0", "dev"),
1151        ic!("1.2.3-1", "premajor", "2.0.0-dev.0", "dev"),
1152        ic!(
1153            "1.2.3-1",
1154            "premajor",
1155            "2.0.0-dev.1",
1156            "dev",
1157            IdentifierBase::Value(1)
1158        ),
1159        ic!("1.2.0-1", "minor", "1.2.0", "dev"),
1160        ic!("1.0.0-1", "major", "1.0.0", "dev"),
1161        ic!("1.2.3-dev.bar", "prerelease", "1.2.3-dev.0", "dev"),
1162        ic!("1.2.3-0", "prerelease", "1.2.3-1.0", "1"),
1163        ic!("1.2.3-1.0", "prerelease", "1.2.3-1.1", "1"),
1164        ic!("1.2.3-1.1", "prerelease", "1.2.3-1.2", "1"),
1165        ic!("1.2.3-1.1", "prerelease", "1.2.3-2.0", "2"),
1166        ic!(
1167            "1.2.0-1",
1168            "prerelease",
1169            "1.2.0-alpha.0",
1170            "alpha",
1171            IdentifierBase::Value(0)
1172        ),
1173        ic!(
1174            "1.2.1",
1175            "prerelease",
1176            "1.2.2-alpha.0",
1177            "alpha",
1178            IdentifierBase::Value(0)
1179        ),
1180        ic!(
1181            "0.2.0",
1182            "prerelease",
1183            "0.2.1-alpha.0",
1184            "alpha",
1185            IdentifierBase::Value(0)
1186        ),
1187        ic!(
1188            "1.2.2",
1189            "prerelease",
1190            "1.2.3-alpha.1",
1191            "alpha",
1192            IdentifierBase::Value(1)
1193        ),
1194        ic!(
1195            "1.2.3",
1196            "prerelease",
1197            "1.2.4-alpha.1",
1198            "alpha",
1199            IdentifierBase::Value(1)
1200        ),
1201        ic!(
1202            "1.2.4",
1203            "prerelease",
1204            "1.2.5-alpha.1",
1205            "alpha",
1206            IdentifierBase::Value(1)
1207        ),
1208        ic!(
1209            "1.2.0",
1210            "prepatch",
1211            "1.2.1-dev.1",
1212            "dev",
1213            IdentifierBase::Value(1)
1214        ),
1215        ic!(
1216            "1.2.0-1",
1217            "prepatch",
1218            "1.2.1-dev.1",
1219            "dev",
1220            IdentifierBase::Value(1)
1221        ),
1222        ic!(
1223            "1.2.0",
1224            "premajor",
1225            "2.0.0-dev.0",
1226            "dev",
1227            IdentifierBase::Value(0)
1228        ),
1229        ic!(
1230            "1.2.3-1",
1231            "premajor",
1232            "2.0.0-dev.0",
1233            "dev",
1234            IdentifierBase::Value(0)
1235        ),
1236        ic!(
1237            "1.2.3-dev.bar",
1238            "prerelease",
1239            "1.2.3-dev.0",
1240            "dev",
1241            IdentifierBase::Value(0)
1242        ),
1243        ic!(
1244            "1.2.3-dev.bar",
1245            "prerelease",
1246            "1.2.3-dev.1",
1247            "dev",
1248            IdentifierBase::Value(1)
1249        ),
1250        ic!(
1251            "1.2.3-dev.bar",
1252            "prerelease",
1253            "1.2.3-dev.bar.0",
1254            "",
1255            IdentifierBase::Value(0)
1256        ),
1257        ic!(
1258            "1.2.3-dev.bar",
1259            "prerelease",
1260            "1.2.3-dev.bar.1",
1261            "",
1262            IdentifierBase::Value(1)
1263        ),
1264        ic!(
1265            "1.2.0",
1266            "preminor",
1267            "1.3.0-dev.1",
1268            "dev",
1269            IdentifierBase::Value(1)
1270        ),
1271        ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1272        ic!(
1273            "1.2.0",
1274            "prerelease",
1275            "1.2.1-1",
1276            "",
1277            IdentifierBase::Value(1)
1278        ),
1279        ic!(
1280            "1.2.0-1",
1281            "prerelease",
1282            "1.2.0-alpha",
1283            "alpha",
1284            IdentifierBase::False
1285        ),
1286        ic!(
1287            "1.2.1",
1288            "prerelease",
1289            "1.2.2-alpha",
1290            "alpha",
1291            IdentifierBase::False
1292        ),
1293        ic!(
1294            "1.2.2",
1295            "prerelease",
1296            "1.2.3-alpha",
1297            "alpha",
1298            IdentifierBase::False
1299        ),
1300        ic!(
1301            "1.2.0",
1302            "prepatch",
1303            "1.2.1-dev",
1304            "dev",
1305            IdentifierBase::False
1306        ),
1307        ic!(
1308            "1.2.0-1",
1309            "prepatch",
1310            "1.2.1-dev",
1311            "dev",
1312            IdentifierBase::False
1313        ),
1314        ic!(
1315            "1.2.0",
1316            "premajor",
1317            "2.0.0-dev",
1318            "dev",
1319            IdentifierBase::False
1320        ),
1321        ic!(
1322            "1.2.3-1",
1323            "premajor",
1324            "2.0.0-dev",
1325            "dev",
1326            IdentifierBase::False
1327        ),
1328        ic!(
1329            "1.2.3-dev.bar",
1330            "prerelease",
1331            "1.2.3-dev",
1332            "dev",
1333            IdentifierBase::False
1334        ),
1335        ic!(
1336            "1.2.3-dev.bar",
1337            "prerelease",
1338            "1.2.3-dev.baz",
1339            "dev.baz",
1340            IdentifierBase::False
1341        ),
1342        ic!(
1343            "1.2.0",
1344            "preminor",
1345            "1.3.0-dev",
1346            "dev",
1347            IdentifierBase::False
1348        ),
1349        ic!(
1350            "1.2.3-1",
1351            "preminor",
1352            "1.3.0-dev",
1353            "dev",
1354            IdentifierBase::False
1355        ),
1356        ic!(
1357            "1.2.3-dev",
1358            "prerelease",
1359            None,
1360            "dev",
1361            IdentifierBase::False
1362        ),
1363        ic!(
1364            "1.2.0-dev",
1365            "premajor",
1366            "2.0.0-dev",
1367            "dev",
1368            IdentifierBase::False
1369        ),
1370        ic!(
1371            "1.2.0-dev",
1372            "preminor",
1373            "1.3.0-beta",
1374            "beta",
1375            IdentifierBase::False
1376        ),
1377        ic!(
1378            "1.2.0-dev",
1379            "prepatch",
1380            "1.2.1-dev",
1381            "dev",
1382            IdentifierBase::False
1383        ),
1384        ic!("1.2.0", "prerelease", None, "", IdentifierBase::False),
1385        ic!(
1386            "1.0.0-rc.1+build.4",
1387            "prerelease",
1388            "1.0.0-rc.2",
1389            "rc",
1390            IdentifierBase::False
1391        ),
1392        ic!("1.2.0", "prerelease", None, "invalid/preid"),
1393        ic!("1.2.0", "prerelease", None, "invalid+build"),
1394        ic!("1.2.0beta", "prerelease", None, "invalid/preid"),
1395    ];
1396
1397    fn version_without_build(version: &Version) -> String {
1398        let mut output = format!("{}.{}.{}", version.major, version.minor, version.patch);
1399        if !version.pre_release().is_empty() {
1400            output.push('-');
1401            output.push_str(&join_prerelease_components(version.pre_release()));
1402        }
1403        output
1404    }
1405
1406    fn load_increment_cases() -> Vec<IncrementCase> {
1407        INCREMENT_CASES
1408            .iter()
1409            .map(|raw| IncrementCase {
1410                version: raw.version.to_string(),
1411                release: raw.release.to_string(),
1412                expected: raw.expected.map(str::to_string),
1413                identifier: raw.identifier.map(str::to_string),
1414                identifier_base: raw.identifier_base,
1415            })
1416            .collect()
1417    }
1418
1419    #[test]
1420    fn trivial_version_number() {
1421        let v = Version::parse("1.2.34").unwrap();
1422
1423        assert_eq!((v.major(), v.minor(), v.patch()), (1, 2, 34));
1424        assert_eq!(
1425            v,
1426            Version::new(1, 2, 34, Vec::with_capacity(2), Vec::with_capacity(2))
1427        );
1428    }
1429
1430    #[test]
1431    fn version_with_build() {
1432        let v = Version::parse("1.2.34+123.456").unwrap();
1433
1434        assert_eq!(
1435            v,
1436            Version::new(
1437                1,
1438                2,
1439                34,
1440                Vec::with_capacity(2),
1441                vec![Numeric(123), Numeric(456)]
1442            )
1443        );
1444    }
1445
1446    #[test]
1447    fn version_with_pre_release() {
1448        let v = Version::parse("1.2.34-abc.123").unwrap();
1449
1450        assert_eq!(
1451            v,
1452            Version::new(
1453                1,
1454                2,
1455                34,
1456                vec![AlphaNumeric("abc".into()), Numeric(123)],
1457                Vec::with_capacity(2),
1458            )
1459        );
1460    }
1461
1462    #[test]
1463    fn version_with_pre_release_and_build() {
1464        let v = Version::parse("1.2.34-abc.123+1").unwrap();
1465
1466        assert_eq!(
1467            v,
1468            Version::new(
1469                1,
1470                2,
1471                34,
1472                vec![AlphaNumeric("abc".into()), Numeric(123)],
1473                vec![Numeric(1)],
1474            )
1475        );
1476    }
1477
1478    #[test]
1479    fn into_parts_with_metadata() {
1480        let parts = Version::parse("1.2.34-abc.123+1").unwrap().into_parts();
1481
1482        assert_eq!(
1483            parts,
1484            VersionParts {
1485                major: 1,
1486                minor: 2,
1487                patch: 34,
1488                pre_release: vec![AlphaNumeric("abc".into()), Numeric(123)],
1489                build: vec![Numeric(1)],
1490            }
1491        );
1492    }
1493
1494    #[test]
1495    fn into_parts_without_metadata() {
1496        let parts = Version::parse("1.2.34").unwrap().into_parts();
1497
1498        assert_eq!(
1499            parts,
1500            VersionParts {
1501                major: 1,
1502                minor: 2,
1503                patch: 34,
1504                pre_release: Vec::new(),
1505                build: Vec::new(),
1506            }
1507        );
1508    }
1509
1510    #[test]
1511    fn pre_release_that_could_look_numeric_at_first() {
1512        let v = Version::parse("1.0.0-rc.2-migration").unwrap();
1513
1514        assert_eq!(
1515            v,
1516            Version::new(
1517                1,
1518                0,
1519                0,
1520                vec![
1521                    Identifier::AlphaNumeric("rc".into()),
1522                    Identifier::AlphaNumeric("2-migration".into())
1523                ],
1524                vec![],
1525            )
1526        );
1527    }
1528
1529    #[test]
1530    fn comparison_with_different_major_version() {
1531        let lesser_version = Version::new(
1532            1,
1533            2,
1534            34,
1535            vec![AlphaNumeric("abc".into()), Numeric(123)],
1536            vec![],
1537        );
1538        let greater_version = Version::new(
1539            2,
1540            2,
1541            34,
1542            vec![AlphaNumeric("abc".into()), Numeric(123)],
1543            vec![],
1544        );
1545        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1546        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1547    }
1548    #[test]
1549    fn comparison_with_different_minor_version() {
1550        let lesser_version = Version::new(
1551            1,
1552            2,
1553            34,
1554            vec![AlphaNumeric("abc".into()), Numeric(123)],
1555            vec![],
1556        );
1557        let greater_version = Version::new(
1558            1,
1559            3,
1560            34,
1561            vec![AlphaNumeric("abc".into()), Numeric(123)],
1562            vec![],
1563        );
1564        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1565        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1566    }
1567
1568    #[test]
1569    fn comparison_with_different_patch_version() {
1570        let lesser_version = Version::new(
1571            1,
1572            2,
1573            34,
1574            vec![AlphaNumeric("abc".into()), Numeric(123)],
1575            vec![],
1576        );
1577        let greater_version = Version::new(
1578            1,
1579            2,
1580            56,
1581            vec![AlphaNumeric("abc".into()), Numeric(123)],
1582            vec![],
1583        );
1584        assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1585        assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1586    }
1587
1588    #[test]
1589    //confirms the comparison matches the pre-release comparison example in the SemVer spec.
1590    //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.
1591    //for simplicity just checks them in order. Assumes that the transitive property holds. So if a < b & b < c then a < c.
1592    fn comparison_with_different_pre_release_version() {
1593        let v1_alpha = Version::new(1, 0, 0, vec![AlphaNumeric("alpha".into())], vec![]);
1594        let v1_alpha1 = Version::new(
1595            1,
1596            0,
1597            0,
1598            vec![AlphaNumeric("alpha".into()), Numeric(1)],
1599            vec![],
1600        );
1601        assert_eq!(v1_alpha.cmp(&v1_alpha1), Ordering::Less);
1602        let v1_alpha_beta = Version::new(
1603            1,
1604            0,
1605            0,
1606            vec![AlphaNumeric("alpha".into()), AlphaNumeric("beta".into())],
1607            vec![],
1608        );
1609        assert_eq!(v1_alpha1.cmp(&v1_alpha_beta), Ordering::Less);
1610        let v1_beta = Version::new(1, 0, 0, vec![AlphaNumeric("beta".into())], vec![]);
1611        assert_eq!(v1_alpha_beta.cmp(&v1_beta), Ordering::Less);
1612        let v1_beta2 = Version::new(
1613            1,
1614            0,
1615            0,
1616            vec![AlphaNumeric("beta".into()), Numeric(2)],
1617            vec![],
1618        );
1619        assert_eq!(v1_beta.cmp(&v1_beta2), Ordering::Less);
1620        let v1_beta11 = Version::new(
1621            1,
1622            0,
1623            0,
1624            vec![AlphaNumeric("beta".into()), Numeric(11)],
1625            vec![],
1626        );
1627        assert_eq!(v1_beta2.cmp(&v1_beta11), Ordering::Less);
1628        let v1_rc1 = Version::new(1, 0, 0, vec![AlphaNumeric("rc".into()), Numeric(1)], vec![]);
1629        assert_eq!(v1_beta11.cmp(&v1_rc1), Ordering::Less);
1630        let v1 = Version::new(1, 0, 0, vec![], vec![]);
1631        assert_eq!(v1_rc1.cmp(&v1), Ordering::Less);
1632    }
1633
1634    #[test]
1635    fn individual_version_component_has_an_upper_bound() {
1636        let out_of_range = MAX_SAFE_INTEGER + 1;
1637        let v = Version::parse(format!("1.2.{}", out_of_range));
1638        assert!(v.is_err());
1639        assert!(Version::parse(format!("1.2.{MAX_SAFE_INTEGER}")).is_ok());
1640    }
1641
1642    #[test]
1643    fn version_string_limited_to_256_characters() {
1644        let prebuild = (0..257).map(|_| "X").collect::<Vec<_>>().join("");
1645        let version_string = format!("1.1.1-{}", prebuild);
1646        let v = Version::parse(version_string.clone());
1647
1648        assert!(v.is_err());
1649
1650        let ok_version = version_string[0..255].to_string();
1651        let v = Version::parse(ok_version);
1652        assert!(v.is_ok());
1653    }
1654
1655    #[test]
1656    fn version_prefixed_with_v() {
1657        // TODO: This is part of strict parsing for nodejs-semver!
1658        let v = Version::parse("v1.2.3").unwrap();
1659        assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
1660    }
1661
1662    #[test]
1663    fn version_prefixed_with_v_space() {
1664        // TODO: Loose parsing supports this, so
1665        let v = Version::parse("v 1.2.3").unwrap();
1666        assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
1667    }
1668
1669    fn asset_version_diff(left: &str, right: &str, expected: &str) {
1670        let left = Version::parse(left).unwrap();
1671        let right = Version::parse(right).unwrap();
1672        let expected_diff = match expected {
1673            "major" => Some(VersionDiff::Major),
1674            "minor" => Some(VersionDiff::Minor),
1675            "patch" => Some(VersionDiff::Patch),
1676            "premajor" => Some(VersionDiff::PreMajor),
1677            "preminor" => Some(VersionDiff::PreMinor),
1678            "prepatch" => Some(VersionDiff::PrePatch),
1679            "null" => None,
1680            _ => unreachable!("unexpected version diff"),
1681        };
1682
1683        assert_eq!(
1684            left.diff(&right),
1685            expected_diff,
1686            "left: {}, right: {}",
1687            left,
1688            right
1689        );
1690    }
1691
1692    #[test]
1693    fn version_diffs() {
1694        let cases = vec![
1695            ("1.2.3", "0.2.3", "major"),
1696            ("0.2.3", "1.2.3", "major"),
1697            ("1.4.5", "0.2.3", "major"),
1698            ("1.2.3", "2.0.0-pre", "premajor"),
1699            ("2.0.0-pre", "1.2.3", "premajor"),
1700            ("1.2.3", "1.3.3", "minor"),
1701            ("1.0.1", "1.1.0-pre", "preminor"),
1702            ("1.2.3", "1.2.4", "patch"),
1703            ("1.2.3", "1.2.4-pre", "prepatch"),
1704            ("1.0.0", "1.0.0", "null"),
1705            ("1.0.0-1", "1.0.0-1", "null"),
1706            ("0.0.2-1", "0.0.2", "patch"),
1707            ("0.0.2-1", "0.0.3", "patch"),
1708            ("0.0.2-1", "0.1.0", "minor"),
1709            ("0.0.2-1", "1.0.0", "major"),
1710            ("0.1.0-1", "0.1.0", "minor"),
1711            ("1.0.0-1", "2.0.0-1", "premajor"),
1712            ("1.0.0-1", "1.1.0-1", "preminor"),
1713            ("1.0.0-1", "1.0.1-1", "prepatch"),
1714        ];
1715
1716        for case in cases {
1717            asset_version_diff(case.0, case.1, case.2);
1718        }
1719    }
1720
1721    #[test]
1722    fn increments_match_node_semver_fixture() {
1723        for case in load_increment_cases() {
1724            if let Some(expected) = &case.expected {
1725                let version = Version::parse(&case.version).unwrap_or_else(|e| {
1726                    panic!("expected to parse {} but failed: {}", case.version, e)
1727                });
1728                let before = version.to_string();
1729                let build = version.build().to_vec();
1730                let incremented = version
1731                    .inc(
1732                        &case.release,
1733                        case.identifier.as_deref(),
1734                        case.identifier_base,
1735                    )
1736                    .unwrap_or_else(|e| {
1737                        panic!(
1738                            "expected {} {} to succeed but errored: {}",
1739                            case.version, case.release, e
1740                        )
1741                    });
1742
1743                assert_eq!(
1744                    version_without_build(&incremented),
1745                    expected.as_str(),
1746                    "incrementing {} {} {:?} {:?}",
1747                    case.version,
1748                    case.release,
1749                    case.identifier,
1750                    case.identifier_base
1751                );
1752                assert_eq!(
1753                    incremented.build(),
1754                    build.as_slice(),
1755                    "build metadata should remain unchanged after increment"
1756                );
1757                assert_eq!(
1758                    version.to_string(),
1759                    before,
1760                    "original version should remain unchanged"
1761                );
1762            } else if let Ok(version) = Version::parse(&case.version) {
1763                let before = version.to_string();
1764                assert!(
1765                    version
1766                        .inc(
1767                            &case.release,
1768                            case.identifier.as_deref(),
1769                            case.identifier_base
1770                        )
1771                        .is_err(),
1772                    "expected {} {} to fail",
1773                    case.version,
1774                    case.release
1775                );
1776                assert_eq!(
1777                    version.to_string(),
1778                    before,
1779                    "version should stay unchanged on error"
1780                );
1781            }
1782        }
1783    }
1784
1785    #[test]
1786    fn invalid_increment_errors_match_node_semver() {
1787        let version = Version::parse("1.2.3").unwrap();
1788        let err = version
1789            .inc("prerelease", Some(""), Some(IdentifierBase::False))
1790            .unwrap_err();
1791        assert_eq!(
1792            err.to_string(),
1793            "invalid increment argument: identifier is empty"
1794        );
1795        assert_eq!(version.to_string(), "1.2.3");
1796
1797        let version = Version::parse("1.2.3-dev").unwrap();
1798        let err = version
1799            .inc("prerelease", Some("dev"), Some(IdentifierBase::False))
1800            .unwrap_err();
1801        assert_eq!(
1802            err.to_string(),
1803            "invalid increment argument: identifier already exists"
1804        );
1805        assert_eq!(version.to_string(), "1.2.3-dev");
1806
1807        let version = Version::parse("1.2.3").unwrap();
1808        let err = version
1809            .inc("prerelease", Some("invalid/preid"), None)
1810            .unwrap_err();
1811        assert_eq!(err.to_string(), "invalid identifier: invalid/preid");
1812        assert_eq!(version.to_string(), "1.2.3");
1813    }
1814}
1815
1816#[cfg(feature = "serde")]
1817#[cfg(test)]
1818mod serde_tests {
1819    use super::Identifier::*;
1820    use super::*;
1821
1822    #[test]
1823    fn version_serde() {
1824        let v = Version::new(
1825            1,
1826            2,
1827            3,
1828            vec![AlphaNumeric("abc".into()), Numeric(123)],
1829            vec![AlphaNumeric("build".into())],
1830        );
1831
1832        let serialized = serde_json::to_string(&v).unwrap();
1833        let deserialized: Version = serde_json::from_str(&serialized).unwrap();
1834
1835        assert_eq!(v, deserialized);
1836    }
1837}