Skip to main content

uv_pep440/
version.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
2use std::fmt::Formatter;
3use std::num::NonZero;
4use std::ops::Deref;
5use std::sync::LazyLock;
6use std::{
7    borrow::Borrow,
8    cmp::Ordering,
9    hash::{Hash, Hasher},
10    str::FromStr,
11    sync::Arc,
12};
13use uv_cache_key::{CacheKey, CacheKeyHasher};
14
15/// One of `~=` `==` `!=` `<=` `>=` `<` `>` `===`
16#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Hash, Clone, Copy)]
17#[cfg_attr(
18    feature = "rkyv",
19    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
20)]
21#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
22pub enum Operator {
23    /// `== 1.2.3`
24    Equal,
25    /// `== 1.2.*`
26    EqualStar,
27    /// `===` (discouraged)
28    ///
29    /// <https://peps.python.org/pep-0440/#arbitrary-equality>
30    ///
31    /// "Use of this operator is heavily discouraged and tooling MAY display a warning when it is used"
32    // clippy doesn't like this: #[deprecated = "Use of this operator is heavily discouraged"]
33    ExactEqual,
34    /// `!= 1.2.3`
35    NotEqual,
36    /// `!= 1.2.*`
37    NotEqualStar,
38    /// `~=`
39    ///
40    /// Invariant: With `~=`, there are always at least 2 release segments.
41    TildeEqual,
42    /// `<`
43    LessThan,
44    /// `<=`
45    LessThanEqual,
46    /// `>`
47    GreaterThan,
48    /// `>=`
49    GreaterThanEqual,
50}
51
52impl Operator {
53    /// Negates this operator, if a negation exists, so that it has the
54    /// opposite meaning.
55    ///
56    /// This returns a negated operator in every case except for the `~=`
57    /// operator. In that case, `None` is returned and callers may need to
58    /// handle its negation at a higher level. (For example, if it's negated
59    /// in the context of a marker expression, then the "compatible" version
60    /// constraint can be split into its component parts and turned into a
61    /// disjunction of the negation of each of those parts.)
62    ///
63    /// Note that this routine is not reversible in all cases. For example
64    /// `Operator::ExactEqual` negates to `Operator::NotEqual`, and
65    /// `Operator::NotEqual` in turn negates to `Operator::Equal`.
66    pub fn negate(self) -> Option<Self> {
67        Some(match self {
68            Self::Equal => Self::NotEqual,
69            Self::EqualStar => Self::NotEqualStar,
70            Self::ExactEqual => Self::NotEqual,
71            Self::NotEqual => Self::Equal,
72            Self::NotEqualStar => Self::EqualStar,
73            Self::TildeEqual => return None,
74            Self::LessThan => Self::GreaterThanEqual,
75            Self::LessThanEqual => Self::GreaterThan,
76            Self::GreaterThan => Self::LessThanEqual,
77            Self::GreaterThanEqual => Self::LessThan,
78        })
79    }
80
81    /// Returns true if and only if this operator can be used in a version
82    /// specifier with a version containing a non-empty local segment.
83    ///
84    /// Specifically, this comes from the "Local version identifiers are
85    /// NOT permitted in this version specifier." phrasing in the version
86    /// specifiers [spec].
87    ///
88    /// [spec]: https://packaging.python.org/en/latest/specifications/version-specifiers/
89    pub(crate) fn is_local_compatible(self) -> bool {
90        !matches!(
91            self,
92            Self::GreaterThan
93                | Self::GreaterThanEqual
94                | Self::LessThan
95                | Self::LessThanEqual
96                | Self::TildeEqual
97                | Self::EqualStar
98                | Self::NotEqualStar
99        )
100    }
101
102    /// Returns the wildcard version of this operator, if appropriate.
103    ///
104    /// This returns `None` when this operator doesn't have an analogous
105    /// wildcard operator.
106    pub(crate) fn to_star(self) -> Option<Self> {
107        match self {
108            Self::Equal => Some(Self::EqualStar),
109            Self::NotEqual => Some(Self::NotEqualStar),
110            _ => None,
111        }
112    }
113
114    /// Returns `true` if this operator represents a wildcard.
115    pub fn is_star(self) -> bool {
116        matches!(self, Self::EqualStar | Self::NotEqualStar)
117    }
118
119    /// Returns the string representation of this operator.
120    pub fn as_str(self) -> &'static str {
121        match self {
122            Self::Equal => "==",
123            // Beware, this doesn't print the star
124            Self::EqualStar => "==",
125            #[allow(deprecated)]
126            Self::ExactEqual => "===",
127            Self::NotEqual => "!=",
128            Self::NotEqualStar => "!=",
129            Self::TildeEqual => "~=",
130            Self::LessThan => "<",
131            Self::LessThanEqual => "<=",
132            Self::GreaterThan => ">",
133            Self::GreaterThanEqual => ">=",
134        }
135    }
136}
137
138impl FromStr for Operator {
139    type Err = OperatorParseError;
140
141    /// Notably, this does not know about star versions, it just assumes the base operator
142    fn from_str(s: &str) -> Result<Self, Self::Err> {
143        let operator = match s {
144            "==" => Self::Equal,
145            "===" => {
146                #[cfg(feature = "tracing")]
147                {
148                    tracing::warn!("Using arbitrary equality (`===`) is discouraged");
149                }
150                #[allow(deprecated)]
151                Self::ExactEqual
152            }
153            "!=" => Self::NotEqual,
154            "~=" => Self::TildeEqual,
155            "<" => Self::LessThan,
156            "<=" => Self::LessThanEqual,
157            ">" => Self::GreaterThan,
158            ">=" => Self::GreaterThanEqual,
159            other => {
160                return Err(OperatorParseError {
161                    got: other.to_string(),
162                });
163            }
164        };
165        Ok(operator)
166    }
167}
168
169impl std::fmt::Display for Operator {
170    /// Note the `EqualStar` is also `==`.
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        let operator = self.as_str();
173        write!(f, "{operator}")
174    }
175}
176
177/// An error that occurs when parsing an invalid version specifier operator.
178#[derive(Clone, Debug, Eq, PartialEq)]
179pub struct OperatorParseError {
180    pub(crate) got: String,
181}
182
183impl std::error::Error for OperatorParseError {}
184
185impl std::fmt::Display for OperatorParseError {
186    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
187        write!(
188            f,
189            "no such comparison operator {:?}, must be one of ~= == != <= >= < > ===",
190            self.got
191        )
192    }
193}
194
195// NOTE: I did a little bit of experimentation to determine what most version
196// numbers actually look like. The idea here is that if we know what most look
197// like, then we can optimize our representation for the common case, while
198// falling back to something more complete for any cases that fall outside of
199// that.
200//
201// The experiment downloaded PyPI's distribution metadata from Google BigQuery,
202// and then counted the number of versions with various qualities:
203//
204//     total: 11264078
205//     release counts:
206//         01: 51204 (0.45%)
207//         02: 754520 (6.70%)
208//         03: 9757602 (86.63%)
209//         04: 527403 (4.68%)
210//         05: 77994 (0.69%)
211//         06: 91346 (0.81%)
212//         07: 1421 (0.01%)
213//         08: 205 (0.00%)
214//         09: 72 (0.00%)
215//         10: 2297 (0.02%)
216//         11: 5 (0.00%)
217//         12: 2 (0.00%)
218//         13: 4 (0.00%)
219//         20: 2 (0.00%)
220//         39: 1 (0.00%)
221//     JUST release counts:
222//         01: 48297 (0.43%)
223//         02: 604692 (5.37%)
224//         03: 8460917 (75.11%)
225//         04: 465354 (4.13%)
226//         05: 49293 (0.44%)
227//         06: 25909 (0.23%)
228//         07: 1413 (0.01%)
229//         08: 192 (0.00%)
230//         09: 72 (0.00%)
231//         10: 2292 (0.02%)
232//         11: 5 (0.00%)
233//         12: 2 (0.00%)
234//         13: 4 (0.00%)
235//         20: 2 (0.00%)
236//         39: 1 (0.00%)
237//     non-zero epochs: 1902 (0.02%)
238//     pre-releases: 752184 (6.68%)
239//     post-releases: 134383 (1.19%)
240//     dev-releases: 765099 (6.79%)
241//     locals: 1 (0.00%)
242//     fitsu8: 10388430 (92.23%)
243//     sweetspot: 10236089 (90.87%)
244//
245// The "JUST release counts" corresponds to versions that only have a release
246// component and nothing else. The "fitsu8" property indicates that all numbers
247// (except for local numeric segments) fit into `u8`. The "sweetspot" property
248// consists of any version number with no local part, 4 or fewer parts in the
249// release version and *all* numbers fit into a u8.
250//
251// This somewhat confirms what one might expect: the vast majority of versions
252// (75%) are precisely in the format of `x.y.z`. That is, a version with only a
253// release version of 3 components.
254//
255// ---AG
256
257/// A version number such as `1.2.3` or `4!5.6.7-a8.post9.dev0`.
258///
259/// Beware that the sorting implemented with [Ord] and [Eq] is not consistent with the operators
260/// from PEP 440, i.e. compare two versions in rust with `>` gives a different result than a
261/// `VersionSpecifier` with `>` as operator.
262///
263/// Parse with [`Version::from_str`]:
264///
265/// ```rust
266/// use std::str::FromStr;
267/// use uv_pep440::Version;
268///
269/// let version = Version::from_str("1.19").unwrap();
270/// ```
271#[derive(Clone)]
272#[cfg_attr(
273    feature = "rkyv",
274    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
275)]
276#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
277pub struct Version {
278    inner: VersionInner,
279}
280
281#[derive(Clone, Debug)]
282#[cfg_attr(
283    feature = "rkyv",
284    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
285)]
286#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
287enum VersionInner {
288    Small { small: VersionSmall },
289    Full { full: Arc<VersionFull> },
290}
291
292impl Version {
293    /// Create a new version from an iterator of segments in the release part
294    /// of a version.
295    ///
296    /// # Panics
297    ///
298    /// When the iterator yields no elements.
299    #[inline]
300    pub fn new<I, R>(release_numbers: I) -> Self
301    where
302        I: IntoIterator<Item = R>,
303        R: Borrow<u64>,
304    {
305        Self {
306            inner: VersionInner::Small {
307                small: VersionSmall::new(),
308            },
309        }
310        .with_release(release_numbers)
311    }
312
313    /// Whether this is an alpha/beta/rc or dev version
314    #[inline]
315    pub fn any_prerelease(&self) -> bool {
316        self.is_pre() || self.is_dev()
317    }
318
319    /// Whether this is a stable version (i.e., _not_ an alpha/beta/rc or dev version)
320    #[inline]
321    pub fn is_stable(&self) -> bool {
322        !self.is_pre() && !self.is_dev()
323    }
324
325    /// Whether this is an alpha/beta/rc version
326    #[inline]
327    pub fn is_pre(&self) -> bool {
328        self.pre().is_some()
329    }
330
331    /// Whether this is a dev version
332    #[inline]
333    pub fn is_dev(&self) -> bool {
334        self.dev().is_some()
335    }
336
337    /// Whether this is a post version
338    #[inline]
339    pub fn is_post(&self) -> bool {
340        self.post().is_some()
341    }
342
343    /// Whether this is a local version (e.g. `1.2.3+localsuffixesareweird`)
344    ///
345    /// When true, it is guaranteed that the slice returned by
346    /// [`Version::local`] is non-empty.
347    #[inline]
348    pub fn is_local(&self) -> bool {
349        !self.local().is_empty()
350    }
351
352    /// Returns the epoch of this version.
353    #[inline]
354    pub fn epoch(&self) -> u64 {
355        match self.inner {
356            VersionInner::Small { ref small } => small.epoch(),
357            VersionInner::Full { ref full } => full.epoch,
358        }
359    }
360
361    /// Returns the release number part of the version.
362    #[inline]
363    pub fn release(&self) -> Release<'_> {
364        let inner = match &self.inner {
365            VersionInner::Small { small } => {
366                // Parse out the version digits.
367                // * Bytes 6 and 7 correspond to the first release segment as a `u16`.
368                // * Bytes 5, 4 and 3 correspond to the second, third and fourth release
369                //   segments, respectively.
370                match small.len {
371                    0 => ReleaseInner::Small0([]),
372                    1 => ReleaseInner::Small1([(small.repr >> 0o60) & 0xFFFF]),
373                    2 => ReleaseInner::Small2([
374                        (small.repr >> 0o60) & 0xFFFF,
375                        (small.repr >> 0o50) & 0xFF,
376                    ]),
377                    3 => ReleaseInner::Small3([
378                        (small.repr >> 0o60) & 0xFFFF,
379                        (small.repr >> 0o50) & 0xFF,
380                        (small.repr >> 0o40) & 0xFF,
381                    ]),
382                    4 => ReleaseInner::Small4([
383                        (small.repr >> 0o60) & 0xFFFF,
384                        (small.repr >> 0o50) & 0xFF,
385                        (small.repr >> 0o40) & 0xFF,
386                        (small.repr >> 0o30) & 0xFF,
387                    ]),
388                    _ => unreachable!("{}", small.len),
389                }
390            }
391            VersionInner::Full { full } => ReleaseInner::Full(&full.release),
392        };
393
394        Release { inner }
395    }
396
397    /// Returns the pre-release part of this version, if it exists.
398    #[inline]
399    pub fn pre(&self) -> Option<Prerelease> {
400        match self.inner {
401            VersionInner::Small { ref small } => small.pre(),
402            VersionInner::Full { ref full } => full.pre,
403        }
404    }
405
406    /// Returns the post-release part of this version, if it exists.
407    #[inline]
408    pub fn post(&self) -> Option<u64> {
409        match self.inner {
410            VersionInner::Small { ref small } => small.post(),
411            VersionInner::Full { ref full } => full.post,
412        }
413    }
414
415    /// Returns the dev-release part of this version, if it exists.
416    #[inline]
417    pub fn dev(&self) -> Option<u64> {
418        match self.inner {
419            VersionInner::Small { ref small } => small.dev(),
420            VersionInner::Full { ref full } => full.dev,
421        }
422    }
423
424    /// Returns the local segments in this version, if any exist.
425    #[inline]
426    pub fn local(&self) -> LocalVersionSlice<'_> {
427        match self.inner {
428            VersionInner::Small { ref small } => small.local_slice(),
429            VersionInner::Full { ref full } => full.local.as_slice(),
430        }
431    }
432
433    /// Returns the min-release part of this version, if it exists.
434    ///
435    /// The "min" component is internal-only, and does not exist in PEP 440.
436    /// The version `1.0min0` is smaller than all other `1.0` versions,
437    /// like `1.0a1`, `1.0dev0`, etc.
438    #[inline]
439    fn min(&self) -> Option<u64> {
440        match self.inner {
441            VersionInner::Small { ref small } => small.min(),
442            VersionInner::Full { ref full } => full.min,
443        }
444    }
445
446    /// Returns the max-release part of this version, if it exists.
447    ///
448    /// The "max" component is internal-only, and does not exist in PEP 440.
449    /// The version `1.0max0` is larger than all other `1.0` versions,
450    /// like `1.0.post1`, `1.0+local`, etc.
451    #[inline]
452    fn max(&self) -> Option<u64> {
453        match self.inner {
454            VersionInner::Small { ref small } => small.max(),
455            VersionInner::Full { ref full } => full.max,
456        }
457    }
458
459    /// Set the release numbers and return the updated version.
460    ///
461    /// Usually one can just use `Version::new` to create a new version with
462    /// the updated release numbers, but this is useful when one wants to
463    /// preserve the other components of a version number while only changing
464    /// the release numbers.
465    ///
466    /// # Panics
467    ///
468    /// When the iterator yields no elements.
469    #[inline]
470    #[must_use]
471    pub fn with_release<I, R>(mut self, release_numbers: I) -> Self
472    where
473        I: IntoIterator<Item = R>,
474        R: Borrow<u64>,
475    {
476        self.clear_release();
477        for n in release_numbers {
478            self.push_release(*n.borrow());
479        }
480        assert!(
481            !self.release().is_empty(),
482            "release must have non-zero size"
483        );
484        self
485    }
486
487    /// Push the given release number into this version. It will become the
488    /// last number in the release component.
489    #[inline]
490    fn push_release(&mut self, n: u64) {
491        if let VersionInner::Small { small } = &mut self.inner {
492            if small.push_release(n) {
493                return;
494            }
495        }
496        self.make_full().release.push(n);
497    }
498
499    /// Clears the release component of this version so that it has no numbers.
500    ///
501    /// Generally speaking, this empty state should not be exposed to callers
502    /// since all versions should have at least one release number.
503    #[inline]
504    fn clear_release(&mut self) {
505        match &mut self.inner {
506            VersionInner::Small { small } => small.clear_release(),
507            VersionInner::Full { full } => {
508                Arc::make_mut(full).release.clear();
509            }
510        }
511    }
512
513    /// Set the epoch and return the updated version.
514    #[inline]
515    #[must_use]
516    pub(crate) fn with_epoch(mut self, value: u64) -> Self {
517        if let VersionInner::Small { small } = &mut self.inner {
518            if small.set_epoch(value) {
519                return self;
520            }
521        }
522        self.make_full().epoch = value;
523        self
524    }
525
526    /// Set the pre-release component and return the updated version.
527    #[inline]
528    #[must_use]
529    pub fn with_pre(mut self, value: Option<Prerelease>) -> Self {
530        if let VersionInner::Small { small } = &mut self.inner {
531            if small.set_pre(value) {
532                return self;
533            }
534        }
535        self.make_full().pre = value;
536        self
537    }
538
539    /// Set the post-release component and return the updated version.
540    #[inline]
541    #[must_use]
542    pub fn with_post(mut self, value: Option<u64>) -> Self {
543        if let VersionInner::Small { small } = &mut self.inner {
544            if small.set_post(value) {
545                return self;
546            }
547        }
548        self.make_full().post = value;
549        self
550    }
551
552    /// Set the dev-release component and return the updated version.
553    #[inline]
554    #[must_use]
555    pub(crate) fn with_dev(mut self, value: Option<u64>) -> Self {
556        if let VersionInner::Small { small } = &mut self.inner {
557            if small.set_dev(value) {
558                return self;
559            }
560        }
561        self.make_full().dev = value;
562        self
563    }
564
565    /// Set the local segments and return the updated version.
566    #[inline]
567    #[must_use]
568    pub(crate) fn with_local_segments(mut self, value: Vec<LocalSegment>) -> Self {
569        if value.is_empty() {
570            self.without_local()
571        } else {
572            self.make_full().local = LocalVersion::Segments(value);
573            self
574        }
575    }
576
577    /// Set the local version and return the updated version.
578    #[inline]
579    #[must_use]
580    pub(crate) fn with_local(mut self, value: LocalVersion) -> Self {
581        match value {
582            LocalVersion::Segments(segments) => self.with_local_segments(segments),
583            LocalVersion::Max => {
584                if let VersionInner::Small { small } = &mut self.inner {
585                    if small.set_local(LocalVersion::Max) {
586                        return self;
587                    }
588                }
589                self.make_full().local = value;
590                self
591            }
592        }
593    }
594
595    /// For PEP 440 specifier matching: "Except where specifically noted below,
596    /// local version identifiers MUST NOT be permitted in version specifiers,
597    /// and local version labels MUST be ignored entirely when checking if
598    /// candidate versions match a given version specifier."
599    #[inline]
600    #[must_use]
601    pub fn without_local(mut self) -> Self {
602        if let VersionInner::Small { small } = &mut self.inner {
603            if small.set_local(LocalVersion::empty()) {
604                return self;
605            }
606        }
607        self.make_full().local = LocalVersion::empty();
608        self
609    }
610
611    /// Return the version with any segments apart from the release removed.
612    #[inline]
613    #[must_use]
614    pub fn only_release(&self) -> Self {
615        Self::new(self.release().iter().copied())
616    }
617
618    /// Return the version with any segments apart from the minor version of the release removed.
619    #[inline]
620    #[must_use]
621    pub(crate) fn only_minor_release(&self) -> Self {
622        Self::new(self.release().iter().take(2).copied())
623    }
624
625    /// Return the version with any segments apart from the release removed, with trailing zeroes
626    /// trimmed.
627    #[inline]
628    #[must_use]
629    pub fn only_release_trimmed(&self) -> Self {
630        if let Some(last_non_zero) = self.release().iter().rposition(|segment| *segment != 0) {
631            if last_non_zero + 1 == self.release().len()
632                && self.epoch() == 0
633                && self.pre().is_none()
634                && self.post().is_none()
635                && self.dev().is_none()
636                && self.local().is_empty()
637                && self.min().is_none()
638                && self.max().is_none()
639            {
640                // Already a trimmed release-only version.
641                self.clone()
642            } else {
643                Self::new(self.release().iter().take(last_non_zero + 1).copied())
644            }
645        } else {
646            // `0` is a valid version.
647            Self::new([0])
648        }
649    }
650
651    /// Return the version with trailing `.0` release segments removed.
652    ///
653    /// # Panics
654    ///
655    /// When the release is all zero segments.
656    #[inline]
657    #[must_use]
658    pub fn without_trailing_zeros(self) -> Self {
659        let mut release = self.release().to_vec();
660        while let Some(0) = release.last() {
661            release.pop();
662        }
663        self.with_release(release)
664    }
665
666    /// Various "increment the version" operations
667    pub fn bump(&mut self, bump: BumpCommand) {
668        // This code operates on the understanding that the components of a version form
669        // the following hierarchy:
670        //
671        //   major > minor > patch > stable > pre > post > dev
672        //
673        // Any updates to something earlier in the hierarchy should clear all values lower
674        // in the hierarchy. So for instance:
675        //
676        // if you bump `minor`, then clear: patch, pre, post, dev
677        // if you bump `pre`, then clear: post, dev
678        //
679        // ...and so on.
680        //
681        // If you bump a value that doesn't exist, it will be set to "1".
682        //
683        // The special "stable" mode has no value, bumping it clears: pre, post, dev.
684        let full = self.make_full();
685
686        match bump {
687            BumpCommand::BumpRelease { index, value } => {
688                // Clear all sub-release items
689                full.pre = None;
690                full.post = None;
691                full.dev = None;
692
693                // Use `max` here to try to do 0.2 => 0.3 instead of 0.2 => 0.3.0
694                let old_parts = &full.release;
695                let len = old_parts.len().max(index + 1);
696                let new_release_vec = (0..len)
697                    .map(|i| match i.cmp(&index) {
698                        // Everything before the bumped value is preserved (or is an implicit 0)
699                        Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
700                        // This is the value to bump (could be implicit 0)
701                        Ordering::Equal => {
702                            value.unwrap_or_else(|| old_parts.get(i).copied().unwrap_or(0) + 1)
703                        }
704                        // Everything after the bumped value becomes 0
705                        Ordering::Greater => 0,
706                    })
707                    .collect::<Vec<u64>>();
708                full.release = new_release_vec;
709            }
710            BumpCommand::MakeStable => {
711                // Clear all sub-release items
712                full.pre = None;
713                full.post = None;
714                full.dev = None;
715            }
716            BumpCommand::BumpPrerelease { kind, value } => {
717                // Clear all sub-prerelease items
718                full.post = None;
719                full.dev = None;
720                if let Some(value) = value {
721                    full.pre = Some(Prerelease {
722                        kind,
723                        number: value,
724                    });
725                } else {
726                    // Either bump the matching kind or set to 1
727                    if let Some(prerelease) = &mut full.pre {
728                        if prerelease.kind == kind {
729                            prerelease.number += 1;
730                            return;
731                        }
732                    }
733                    full.pre = Some(Prerelease { kind, number: 1 });
734                }
735            }
736            BumpCommand::BumpPost { value } => {
737                // Clear sub-post items
738                full.dev = None;
739                if let Some(value) = value {
740                    full.post = Some(value);
741                } else {
742                    // Either bump or set to 1
743                    if let Some(post) = &mut full.post {
744                        *post += 1;
745                    } else {
746                        full.post = Some(1);
747                    }
748                }
749            }
750            BumpCommand::BumpDev { value } => {
751                if let Some(value) = value {
752                    full.dev = Some(value);
753                } else {
754                    // Either bump or set to 1
755                    if let Some(dev) = &mut full.dev {
756                        *dev += 1;
757                    } else {
758                        full.dev = Some(1);
759                    }
760                }
761            }
762        }
763    }
764
765    /// Set the min-release component and return the updated version.
766    ///
767    /// The "min" component is internal-only, and does not exist in PEP 440.
768    /// The version `1.0min0` is smaller than all other `1.0` versions,
769    /// like `1.0a1`, `1.0dev0`, etc.
770    #[inline]
771    #[must_use]
772    pub fn with_min(mut self, value: Option<u64>) -> Self {
773        debug_assert!(!self.is_pre(), "min is not allowed on pre-release versions");
774        debug_assert!(!self.is_dev(), "min is not allowed on dev versions");
775        if let VersionInner::Small { small } = &mut self.inner {
776            if small.set_min(value) {
777                return self;
778            }
779        }
780        self.make_full().min = value;
781        self
782    }
783
784    /// Set the max-release component and return the updated version.
785    ///
786    /// The "max" component is internal-only, and does not exist in PEP 440.
787    /// The version `1.0max0` is larger than all other `1.0` versions,
788    /// like `1.0.post1`, `1.0+local`, etc.
789    #[inline]
790    #[must_use]
791    pub fn with_max(mut self, value: Option<u64>) -> Self {
792        debug_assert!(
793            !self.is_post(),
794            "max is not allowed on post-release versions"
795        );
796        debug_assert!(!self.is_dev(), "max is not allowed on dev versions");
797        if let VersionInner::Small { small } = &mut self.inner {
798            if small.set_max(value) {
799                return self;
800            }
801        }
802        self.make_full().max = value;
803        self
804    }
805
806    /// Convert this version to a "full" representation in-place and return a
807    /// mutable borrow to the full type.
808    fn make_full(&mut self) -> &mut VersionFull {
809        if let VersionInner::Small { ref small } = self.inner {
810            let full = VersionFull {
811                epoch: small.epoch(),
812                release: self.release().to_vec(),
813                min: small.min(),
814                max: small.max(),
815                pre: small.pre(),
816                post: small.post(),
817                dev: small.dev(),
818                local: small.local(),
819            };
820            *self = Self {
821                inner: VersionInner::Full {
822                    full: Arc::new(full),
823                },
824            };
825        }
826        match &mut self.inner {
827            VersionInner::Full { full } => Arc::make_mut(full),
828            VersionInner::Small { .. } => unreachable!(),
829        }
830    }
831
832    /// Performs a "slow" but complete comparison between two versions.
833    ///
834    /// This comparison is done using only the public API of a `Version`, and
835    /// is thus independent of its specific representation. This is useful
836    /// to use when comparing two versions that aren't *both* the small
837    /// representation.
838    #[cold]
839    #[inline(never)]
840    fn cmp_slow(&self, other: &Self) -> Ordering {
841        match self.epoch().cmp(&other.epoch()) {
842            Ordering::Less => {
843                return Ordering::Less;
844            }
845            Ordering::Equal => {}
846            Ordering::Greater => {
847                return Ordering::Greater;
848            }
849        }
850
851        match compare_release(&self.release(), &other.release()) {
852            Ordering::Less => {
853                return Ordering::Less;
854            }
855            Ordering::Equal => {}
856            Ordering::Greater => {
857                return Ordering::Greater;
858            }
859        }
860
861        // release is equal, so compare the other parts
862        sortable_tuple(self).cmp(&sortable_tuple(other))
863    }
864}
865
866impl<'de> Deserialize<'de> for Version {
867    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
868    where
869        D: Deserializer<'de>,
870    {
871        struct Visitor;
872
873        impl de::Visitor<'_> for Visitor {
874            type Value = Version;
875
876            fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
877                f.write_str("a string")
878            }
879
880            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
881                Version::from_str(v).map_err(de::Error::custom)
882            }
883        }
884
885        deserializer.deserialize_str(Visitor)
886    }
887}
888
889/// <https://github.com/serde-rs/serde/issues/1316#issue-332908452>
890impl Serialize for Version {
891    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
892    where
893        S: Serializer,
894    {
895        serializer.collect_str(self)
896    }
897}
898
899/// Shows normalized version
900impl std::fmt::Display for Version {
901    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
902        if self.epoch() != 0 {
903            write!(f, "{}!", self.epoch())?;
904        }
905        let release = self.release();
906        let mut release_iter = release.iter();
907        if let Some(first) = release_iter.next() {
908            write!(f, "{first}")?;
909            for n in release_iter {
910                write!(f, ".{n}")?;
911            }
912        }
913
914        if let Some(Prerelease { kind, number }) = self.pre() {
915            write!(f, "{kind}{number}")?;
916        }
917        if let Some(post) = self.post() {
918            write!(f, ".post{post}")?;
919        }
920        if let Some(dev) = self.dev() {
921            write!(f, ".dev{dev}")?;
922        }
923        if !self.local().is_empty() {
924            match self.local() {
925                LocalVersionSlice::Segments(_) => {
926                    write!(f, "+{}", self.local())?;
927                }
928                LocalVersionSlice::Max => {
929                    write!(f, "+")?;
930                }
931            }
932        }
933        Ok(())
934    }
935}
936
937impl std::fmt::Debug for Version {
938    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
939        write!(f, "\"{self}\"")
940    }
941}
942
943impl PartialEq<Self> for Version {
944    #[inline]
945    fn eq(&self, other: &Self) -> bool {
946        self.cmp(other) == Ordering::Equal
947    }
948}
949
950impl Eq for Version {}
951
952impl Hash for Version {
953    /// Custom implementation to ignoring trailing zero because `PartialEq` zero pads
954    #[inline]
955    fn hash<H: Hasher>(&self, state: &mut H) {
956        self.epoch().hash(state);
957        // Skip trailing zeros
958        for i in self.release().iter().rev().skip_while(|x| **x == 0) {
959            i.hash(state);
960        }
961        self.pre().hash(state);
962        self.dev().hash(state);
963        self.post().hash(state);
964        self.local().hash(state);
965    }
966}
967
968impl CacheKey for Version {
969    fn cache_key(&self, state: &mut CacheKeyHasher) {
970        self.epoch().cache_key(state);
971
972        let release = self.release();
973        release.len().cache_key(state);
974        for segment in release.iter() {
975            segment.cache_key(state);
976        }
977
978        if let Some(pre) = self.pre() {
979            1u8.cache_key(state);
980            match pre.kind {
981                PrereleaseKind::Alpha => 0u8.cache_key(state),
982                PrereleaseKind::Beta => 1u8.cache_key(state),
983                PrereleaseKind::Rc => 2u8.cache_key(state),
984            }
985            pre.number.cache_key(state);
986        } else {
987            0u8.cache_key(state);
988        }
989
990        if let Some(post) = self.post() {
991            1u8.cache_key(state);
992            post.cache_key(state);
993        } else {
994            0u8.cache_key(state);
995        }
996
997        if let Some(dev) = self.dev() {
998            1u8.cache_key(state);
999            dev.cache_key(state);
1000        } else {
1001            0u8.cache_key(state);
1002        }
1003
1004        self.local().cache_key(state);
1005    }
1006}
1007
1008impl PartialOrd<Self> for Version {
1009    #[inline]
1010    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1011        Some(self.cmp(other))
1012    }
1013}
1014
1015impl Ord for Version {
1016    /// 1.0.dev456 < 1.0a1 < 1.0a2.dev456 < 1.0a12.dev456 < 1.0a12 < 1.0b1.dev456 < 1.0b2
1017    /// < 1.0b2.post345.dev456 < 1.0b2.post345 < 1.0b2-346 < 1.0c1.dev456 < 1.0c1 < 1.0rc2 < 1.0c3
1018    /// < 1.0 < 1.0.post456.dev34 < 1.0.post456
1019    #[inline]
1020    fn cmp(&self, other: &Self) -> Ordering {
1021        match (&self.inner, &other.inner) {
1022            (VersionInner::Small { small: small1 }, VersionInner::Small { small: small2 }) => {
1023                small1.repr.cmp(&small2.repr)
1024            }
1025            _ => self.cmp_slow(other),
1026        }
1027    }
1028}
1029
1030impl FromStr for Version {
1031    type Err = VersionParseError;
1032
1033    /// Parses a version such as `1.19`, `1.0a1`,`1.0+abc.5` or `1!2012.2`
1034    ///
1035    /// Note that this doesn't allow wildcard versions.
1036    fn from_str(version: &str) -> Result<Self, Self::Err> {
1037        Parser::new(version.as_bytes()).parse()
1038    }
1039}
1040
1041/// Various ways to "bump" a version
1042#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
1043pub enum BumpCommand {
1044    /// Bump or set the release component
1045    BumpRelease {
1046        /// The release component to bump (0 is major, 1 is minor, 2 is patch)
1047        index: usize,
1048        /// Explicit value to set; when absent the component is incremented
1049        value: Option<u64>,
1050    },
1051    /// Bump or set the prerelease component
1052    BumpPrerelease {
1053        /// prerelease component to bump
1054        kind: PrereleaseKind,
1055        /// Explicit value to set; when absent the component is incremented
1056        value: Option<u64>,
1057    },
1058    /// Bump to the associated stable release
1059    MakeStable,
1060    /// Bump or set the post component
1061    BumpPost {
1062        /// Explicit value to set; when absent the component is incremented
1063        value: Option<u64>,
1064    },
1065    /// Bump or set the dev component
1066    BumpDev {
1067        /// Explicit value to set; when absent the component is incremented
1068        value: Option<u64>,
1069    },
1070}
1071
1072/// A small representation of a version.
1073///
1074/// This representation is used for a (very common) subset of versions: the
1075/// set of all versions with ~small numbers and no local component. The
1076/// representation is designed to be (somewhat) compact, but also laid out in
1077/// a way that makes comparisons between two small versions equivalent to a
1078/// simple `memcmp`.
1079///
1080/// The methods on this type encapsulate the representation. Since this type
1081/// cannot represent the full range of all versions, setters on this type will
1082/// return `false` if the value could not be stored. In this case, callers
1083/// should generally convert a version into its "full" representation and then
1084/// set the value on the full type.
1085///
1086/// # Representation
1087///
1088/// At time of writing, this representation supports versions that meet all of
1089/// the following criteria:
1090///
1091/// * The epoch must be `0`.
1092/// * The release portion must have 4 or fewer segments.
1093/// * All release segments, except for the first, must be representable in a
1094///   `u8`. The first segment must be representable in a `u16`. (This permits
1095///   calendar versions, like `2023.03`, to be represented.)
1096/// * There is *at most* one of the following components: pre, dev or post.
1097/// * If there is a pre segment, then its numeric value is less than 64.
1098/// * If there is a dev or post segment, then its value is less than `u8::MAX`.
1099/// * There are zero "local" segments.
1100///
1101/// The above constraints were chosen as a balancing point between being able
1102/// to represent all parts of a version in a very small amount of space,
1103/// and for supporting as many versions in the wild as possible. There is,
1104/// however, another constraint in play here: comparisons between two `Version`
1105/// values. It turns out that we do a lot of them as part of resolution, and
1106/// the cheaper we can make that, the better. This constraint pushes us
1107/// toward using as little space as possible. Indeed, here, comparisons are
1108/// implemented via `u64::cmp`.
1109///
1110/// We pack versions fitting the above constraints into a `u64` in such a way
1111/// that it preserves the ordering between versions as prescribed in PEP 440.
1112/// Namely:
1113///
1114/// * Bytes 6 and 7 correspond to the first release segment as a `u16`.
1115/// * Bytes 5, 4 and 3 correspond to the second, third and fourth release
1116///   segments, respectively.
1117/// * Bytes 2, 1 and 0 represent *one* of the following:
1118///   `min, .devN, aN, bN, rcN, <no suffix>, local, .postN, max`.
1119///   Its representation is thus:
1120///   * The most significant 4 bits of Byte 2 corresponds to a value in
1121///     the range 0-8 inclusive, corresponding to min, dev, pre-a, pre-b,
1122///     pre-rc, no-suffix, post or max releases, respectively. `min` is a
1123///     special version that does not exist in PEP 440, but is used here to
1124///     represent the smallest possible version, preceding any `dev`, `pre`,
1125///     `post` or releases. `max` is an analogous concept for the largest
1126///     possible version, following any `post` or local releases.
1127///   * The low 4 bits combined with the bits in bytes 1 and 0 correspond
1128///     to the release number of the suffix, if one exists. If there is no
1129///     suffix, then these bits are always 0.
1130///
1131/// The order of the encoding above is significant. For example, suffixes are
1132/// encoded at a less significant location than the release numbers, so that
1133/// `1.2.3 < 1.2.3.post4`.
1134///
1135/// In a previous representation, we tried to encode the suffixes in different
1136/// locations so that, in theory, you could represent `1.2.3.dev2.post3` in the
1137/// packed form. But getting the ordering right for this is difficult (perhaps
1138/// impossible without extra space?). So we limited to only storing one suffix.
1139/// But even then, we wound up with a bug where `1.0dev1 > 1.0a1`, when of
1140/// course, all dev releases should compare less than pre releases. This was
1141/// because the encoding recorded the pre-release as "absent", and this in turn
1142/// screwed up the order comparisons.
1143///
1144/// Thankfully, such versions are incredibly rare. Virtually all versions have
1145/// zero or one pre, dev or post release components.
1146#[derive(Clone, Debug)]
1147#[cfg_attr(
1148    feature = "rkyv",
1149    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1150)]
1151#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1152struct VersionSmall {
1153    /// The number of segments in the release component.
1154    ///
1155    /// PEP 440 considers `1.2`  equivalent to `1.2.0.0`, but we want to preserve trailing zeroes
1156    /// in roundtrips, as the "full" version representation also does.
1157    len: u8,
1158    /// The representation discussed above.
1159    repr: u64,
1160    /// Force a niche into the aligned type so the [`Version`] enum is two words instead of three.
1161    _force_niche: NonZero<u8>,
1162}
1163
1164impl VersionSmall {
1165    // Constants for each suffix kind. They form an enumeration.
1166    //
1167    // The specific values are assigned in a way that provides the suffix kinds
1168    // their ordering. i.e., No suffix should sort after a dev suffix but
1169    // before a post suffix.
1170    //
1171    // The maximum possible suffix value is SUFFIX_KIND_MASK. If you need to
1172    // add another suffix value and you're at the max, then the mask must gain
1173    // another bit. And adding another bit to the mask will require taking it
1174    // from somewhere else. (Usually the suffix version.)
1175    //
1176    // NOTE: If you do change the bit format here, you'll need to bump any
1177    // cache versions in uv that use rkyv with `Version` in them. That includes
1178    // *at least* the "simple" cache.
1179    const SUFFIX_MIN: u64 = 0;
1180    const SUFFIX_DEV: u64 = 1;
1181    const SUFFIX_PRE_ALPHA: u64 = 2;
1182    const SUFFIX_PRE_BETA: u64 = 3;
1183    const SUFFIX_PRE_RC: u64 = 4;
1184    const SUFFIX_NONE: u64 = 5;
1185    const SUFFIX_LOCAL: u64 = 6;
1186    const SUFFIX_POST: u64 = 7;
1187    const SUFFIX_MAX: u64 = 8;
1188
1189    // The mask to get only the release segment bits.
1190    //
1191    // NOTE: If you change the release mask to have more or less bits,
1192    // then you'll also need to change `push_release` below and also
1193    // `Parser::parse_fast`.
1194    const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
1195    // The mask to get the version suffix.
1196    const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
1197    // The number of bits used by the version suffix. Shifting the `repr`
1198    // right by this number of bits should put the suffix kind in the least
1199    // significant bits.
1200    const SUFFIX_VERSION_BIT_LEN: u64 = 20;
1201    // The mask to get only the suffix kind, after shifting right by the
1202    // version bits. If you need to add a bit here, then you'll probably need
1203    // to take a bit from the suffix version. (Which requires a change to both
1204    // the mask and the bit length above.)
1205    const SUFFIX_KIND_MASK: u64 = 0b1111;
1206
1207    #[inline]
1208    fn new() -> Self {
1209        Self {
1210            _force_niche: NonZero::<u8>::MIN,
1211            repr: Self::SUFFIX_NONE << Self::SUFFIX_VERSION_BIT_LEN,
1212            len: 0,
1213        }
1214    }
1215
1216    #[inline]
1217    #[expect(clippy::unused_self)]
1218    fn epoch(&self) -> u64 {
1219        0
1220    }
1221
1222    #[inline]
1223    #[expect(clippy::unused_self)]
1224    fn set_epoch(&mut self, value: u64) -> bool {
1225        if value != 0 {
1226            return false;
1227        }
1228        true
1229    }
1230
1231    #[inline]
1232    fn clear_release(&mut self) {
1233        self.repr &= !Self::SUFFIX_RELEASE_MASK;
1234        self.len = 0;
1235    }
1236
1237    #[inline]
1238    fn push_release(&mut self, n: u64) -> bool {
1239        if self.len == 0 {
1240            if n > u64::from(u16::MAX) {
1241                return false;
1242            }
1243            self.repr |= n << 48;
1244            self.len = 1;
1245            true
1246        } else {
1247            if n > u64::from(u8::MAX) {
1248                return false;
1249            }
1250            if self.len >= 4 {
1251                return false;
1252            }
1253            let shift = 48 - (usize::from(self.len) * 8);
1254            self.repr |= n << shift;
1255            self.len += 1;
1256            true
1257        }
1258    }
1259
1260    #[inline]
1261    fn post(&self) -> Option<u64> {
1262        if self.suffix_kind() == Self::SUFFIX_POST {
1263            Some(self.suffix_version())
1264        } else {
1265            None
1266        }
1267    }
1268
1269    #[inline]
1270    fn set_post(&mut self, value: Option<u64>) -> bool {
1271        let suffix_kind = self.suffix_kind();
1272        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1273            return value.is_none();
1274        }
1275        match value {
1276            None => {
1277                self.set_suffix_kind(Self::SUFFIX_NONE);
1278            }
1279            Some(number) => {
1280                if number > Self::SUFFIX_VERSION_MASK {
1281                    return false;
1282                }
1283                self.set_suffix_kind(Self::SUFFIX_POST);
1284                self.set_suffix_version(number);
1285            }
1286        }
1287        true
1288    }
1289
1290    #[inline]
1291    fn pre(&self) -> Option<Prerelease> {
1292        let (kind, number) = (self.suffix_kind(), self.suffix_version());
1293        if kind == Self::SUFFIX_PRE_ALPHA {
1294            Some(Prerelease {
1295                kind: PrereleaseKind::Alpha,
1296                number,
1297            })
1298        } else if kind == Self::SUFFIX_PRE_BETA {
1299            Some(Prerelease {
1300                kind: PrereleaseKind::Beta,
1301                number,
1302            })
1303        } else if kind == Self::SUFFIX_PRE_RC {
1304            Some(Prerelease {
1305                kind: PrereleaseKind::Rc,
1306                number,
1307            })
1308        } else {
1309            None
1310        }
1311    }
1312
1313    #[inline]
1314    fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1315        let suffix_kind = self.suffix_kind();
1316        if !(suffix_kind == Self::SUFFIX_NONE
1317            || suffix_kind == Self::SUFFIX_PRE_ALPHA
1318            || suffix_kind == Self::SUFFIX_PRE_BETA
1319            || suffix_kind == Self::SUFFIX_PRE_RC)
1320        {
1321            return value.is_none();
1322        }
1323        match value {
1324            None => {
1325                self.set_suffix_kind(Self::SUFFIX_NONE);
1326            }
1327            Some(Prerelease { kind, number }) => {
1328                if number > Self::SUFFIX_VERSION_MASK {
1329                    return false;
1330                }
1331                match kind {
1332                    PrereleaseKind::Alpha => {
1333                        self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1334                    }
1335                    PrereleaseKind::Beta => {
1336                        self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1337                    }
1338                    PrereleaseKind::Rc => {
1339                        self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1340                    }
1341                }
1342                self.set_suffix_version(number);
1343            }
1344        }
1345        true
1346    }
1347
1348    #[inline]
1349    fn dev(&self) -> Option<u64> {
1350        if self.suffix_kind() == Self::SUFFIX_DEV {
1351            Some(self.suffix_version())
1352        } else {
1353            None
1354        }
1355    }
1356
1357    #[inline]
1358    fn set_dev(&mut self, value: Option<u64>) -> bool {
1359        let suffix_kind = self.suffix_kind();
1360        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1361            return value.is_none();
1362        }
1363        match value {
1364            None => {
1365                self.set_suffix_kind(Self::SUFFIX_NONE);
1366            }
1367            Some(number) => {
1368                if number > Self::SUFFIX_VERSION_MASK {
1369                    return false;
1370                }
1371                self.set_suffix_kind(Self::SUFFIX_DEV);
1372                self.set_suffix_version(number);
1373            }
1374        }
1375        true
1376    }
1377
1378    #[inline]
1379    fn min(&self) -> Option<u64> {
1380        if self.suffix_kind() == Self::SUFFIX_MIN {
1381            Some(self.suffix_version())
1382        } else {
1383            None
1384        }
1385    }
1386
1387    #[inline]
1388    fn set_min(&mut self, value: Option<u64>) -> bool {
1389        let suffix_kind = self.suffix_kind();
1390        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1391            return value.is_none();
1392        }
1393        match value {
1394            None => {
1395                self.set_suffix_kind(Self::SUFFIX_NONE);
1396            }
1397            Some(number) => {
1398                if number > Self::SUFFIX_VERSION_MASK {
1399                    return false;
1400                }
1401                self.set_suffix_kind(Self::SUFFIX_MIN);
1402                self.set_suffix_version(number);
1403            }
1404        }
1405        true
1406    }
1407
1408    #[inline]
1409    fn max(&self) -> Option<u64> {
1410        if self.suffix_kind() == Self::SUFFIX_MAX {
1411            Some(self.suffix_version())
1412        } else {
1413            None
1414        }
1415    }
1416
1417    #[inline]
1418    fn set_max(&mut self, value: Option<u64>) -> bool {
1419        let suffix_kind = self.suffix_kind();
1420        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1421            return value.is_none();
1422        }
1423        match value {
1424            None => {
1425                self.set_suffix_kind(Self::SUFFIX_NONE);
1426            }
1427            Some(number) => {
1428                if number > Self::SUFFIX_VERSION_MASK {
1429                    return false;
1430                }
1431                self.set_suffix_kind(Self::SUFFIX_MAX);
1432                self.set_suffix_version(number);
1433            }
1434        }
1435        true
1436    }
1437
1438    #[inline]
1439    fn local(&self) -> LocalVersion {
1440        if self.suffix_kind() == Self::SUFFIX_LOCAL {
1441            LocalVersion::Max
1442        } else {
1443            LocalVersion::empty()
1444        }
1445    }
1446
1447    #[inline]
1448    fn local_slice(&self) -> LocalVersionSlice<'_> {
1449        if self.suffix_kind() == Self::SUFFIX_LOCAL {
1450            LocalVersionSlice::Max
1451        } else {
1452            LocalVersionSlice::empty()
1453        }
1454    }
1455
1456    #[inline]
1457    fn set_local(&mut self, value: LocalVersion) -> bool {
1458        let suffix_kind = self.suffix_kind();
1459        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1460            return value.is_empty();
1461        }
1462        match value {
1463            LocalVersion::Max => {
1464                self.set_suffix_kind(Self::SUFFIX_LOCAL);
1465                true
1466            }
1467            LocalVersion::Segments(segments) if segments.is_empty() => {
1468                self.set_suffix_kind(Self::SUFFIX_NONE);
1469                true
1470            }
1471            LocalVersion::Segments(_) => false,
1472        }
1473    }
1474
1475    #[inline]
1476    fn suffix_kind(&self) -> u64 {
1477        let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1478        debug_assert!(kind <= Self::SUFFIX_MAX);
1479        kind
1480    }
1481
1482    #[inline]
1483    fn set_suffix_kind(&mut self, kind: u64) {
1484        debug_assert!(kind <= Self::SUFFIX_MAX);
1485        self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1486        self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1487        if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1488            self.set_suffix_version(0);
1489        }
1490    }
1491
1492    #[inline]
1493    fn suffix_version(&self) -> u64 {
1494        self.repr & Self::SUFFIX_VERSION_MASK
1495    }
1496
1497    #[inline]
1498    fn set_suffix_version(&mut self, value: u64) {
1499        debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1500        self.repr &= !Self::SUFFIX_VERSION_MASK;
1501        self.repr |= value;
1502    }
1503}
1504
1505/// The "full" representation of a version.
1506///
1507/// This can represent all possible versions, but is a bit beefier because of
1508/// it. It also uses some indirection for variable length data such as the
1509/// release numbers and the local segments.
1510///
1511/// In general, the "full" representation is rarely used in practice since most
1512/// versions will fit into the "small" representation.
1513#[derive(Clone, Debug)]
1514#[cfg_attr(
1515    feature = "rkyv",
1516    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1517)]
1518#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1519struct VersionFull {
1520    /// The [versioning
1521    /// epoch](https://peps.python.org/pep-0440/#version-epochs). Normally
1522    /// just 0, but you can increment it if you switched the versioning
1523    /// scheme.
1524    epoch: u64,
1525    /// The normal number part of the version (["final
1526    /// release"](https://peps.python.org/pep-0440/#final-releases)), such
1527    /// a `1.2.3` in `4!1.2.3-a8.post9.dev1`
1528    ///
1529    /// Note that we drop the * placeholder by moving it to `Operator`
1530    release: Vec<u64>,
1531    /// The [prerelease](https://peps.python.org/pep-0440/#pre-releases),
1532    /// i.e. alpha, beta or rc plus a number
1533    ///
1534    /// Note that whether this is Some influences the version range
1535    /// matching since normally we exclude all pre-release versions
1536    pre: Option<Prerelease>,
1537    /// The [Post release
1538    /// version](https://peps.python.org/pep-0440/#post-releases), higher
1539    /// post version are preferred over lower post or none-post versions
1540    post: Option<u64>,
1541    /// The [developmental
1542    /// release](https://peps.python.org/pep-0440/#developmental-releases),
1543    /// if any
1544    dev: Option<u64>,
1545    /// A [local version
1546    /// identifier](https://peps.python.org/pep-0440/#local-version-identifiers)
1547    /// such as `+deadbeef` in `1.2.3+deadbeef`
1548    ///
1549    /// > They consist of a normal public version identifier (as defined
1550    /// > in the previous section), along with an arbitrary “local version
1551    /// > label”, separated from the public version identifier by a plus.
1552    /// > Local version labels have no specific semantics assigned, but
1553    /// > some syntactic restrictions are imposed.
1554    ///
1555    /// Local versions allow multiple segments separated by periods, such as `deadbeef.1.2.3`, see
1556    /// [`LocalSegment`] for details on the semantics.
1557    local: LocalVersion,
1558    /// An internal-only segment that does not exist in PEP 440, used to
1559    /// represent the smallest possible version of a release, preceding any
1560    /// `dev`, `pre`, `post` or releases.
1561    min: Option<u64>,
1562    /// An internal-only segment that does not exist in PEP 440, used to
1563    /// represent the largest possible version of a release, following any
1564    /// `post` or local releases.
1565    max: Option<u64>,
1566}
1567
1568/// A version number pattern.
1569///
1570/// A version pattern appears in a
1571/// [`VersionSpecifier`](crate::VersionSpecifier). It is just like a version,
1572/// except that it permits a trailing `*` (wildcard) at the end of the version
1573/// number. The wildcard indicates that any version with the same prefix should
1574/// match.
1575///
1576/// A `VersionPattern` cannot do any matching itself. Instead,
1577/// it needs to be paired with an [`Operator`] to create a
1578/// [`VersionSpecifier`](crate::VersionSpecifier).
1579///
1580/// Here are some valid and invalid examples:
1581///
1582/// * `1.2.3` -> verbatim pattern
1583/// * `1.2.3.*` -> wildcard pattern
1584/// * `1.2.*.4` -> invalid
1585/// * `1.0-dev1.*` -> invalid
1586#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1587pub struct VersionPattern {
1588    version: Version,
1589    wildcard: bool,
1590}
1591
1592impl VersionPattern {
1593    /// Creates a new verbatim version pattern that matches the given
1594    /// version exactly.
1595    #[inline]
1596    pub fn verbatim(version: Version) -> Self {
1597        Self {
1598            version,
1599            wildcard: false,
1600        }
1601    }
1602
1603    /// Creates a new wildcard version pattern that matches any version with
1604    /// the given version as a prefix.
1605    #[inline]
1606    pub fn wildcard(version: Version) -> Self {
1607        Self {
1608            version,
1609            wildcard: true,
1610        }
1611    }
1612
1613    /// Returns the underlying version.
1614    #[inline]
1615    pub fn version(&self) -> &Version {
1616        &self.version
1617    }
1618
1619    /// Consumes this pattern and returns ownership of the underlying version.
1620    #[inline]
1621    pub(crate) fn into_version(self) -> Version {
1622        self.version
1623    }
1624
1625    /// Returns true if and only if this pattern contains a wildcard.
1626    #[inline]
1627    pub(crate) fn is_wildcard(&self) -> bool {
1628        self.wildcard
1629    }
1630}
1631
1632impl FromStr for VersionPattern {
1633    type Err = VersionPatternParseError;
1634
1635    fn from_str(version: &str) -> Result<Self, VersionPatternParseError> {
1636        Parser::new(version.as_bytes()).parse_pattern()
1637    }
1638}
1639
1640/// Release digits of a [`Version`].
1641///
1642/// Lifetime and indexing workaround to allow accessing the release as `&[u64]` even though the
1643/// digits may be stored in a compressed representation.
1644pub struct Release<'a> {
1645    inner: ReleaseInner<'a>,
1646}
1647
1648enum ReleaseInner<'a> {
1649    // The small versions unpacked into larger u64 values.
1650    // We're storing at most 4 u64 plus determinant for the duration of the release call on the
1651    // stack, without heap allocation.
1652    Small0([u64; 0]),
1653    Small1([u64; 1]),
1654    Small2([u64; 2]),
1655    Small3([u64; 3]),
1656    Small4([u64; 4]),
1657    Full(&'a [u64]),
1658}
1659
1660impl Deref for Release<'_> {
1661    type Target = [u64];
1662
1663    fn deref(&self) -> &Self::Target {
1664        match &self.inner {
1665            ReleaseInner::Small0(v) => v,
1666            ReleaseInner::Small1(v) => v,
1667            ReleaseInner::Small2(v) => v,
1668            ReleaseInner::Small3(v) => v,
1669            ReleaseInner::Small4(v) => v,
1670            ReleaseInner::Full(v) => v,
1671        }
1672    }
1673}
1674
1675/// An optional pre-release modifier and number applied to a version.
1676#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1677#[cfg_attr(
1678    feature = "rkyv",
1679    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1680)]
1681#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1682pub struct Prerelease {
1683    /// The kind of pre-release.
1684    pub kind: PrereleaseKind,
1685    /// The number associated with the pre-release.
1686    pub number: u64,
1687}
1688
1689/// Optional pre-release modifier (alpha, beta or release candidate) appended to version
1690///
1691/// <https://peps.python.org/pep-0440/#pre-releases>
1692#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1693#[cfg_attr(
1694    feature = "rkyv",
1695    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1696)]
1697#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1698pub enum PrereleaseKind {
1699    /// alpha pre-release
1700    Alpha,
1701    /// beta pre-release
1702    Beta,
1703    /// release candidate pre-release
1704    Rc,
1705}
1706
1707impl std::fmt::Display for PrereleaseKind {
1708    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1709        match self {
1710            Self::Alpha => write!(f, "a"),
1711            Self::Beta => write!(f, "b"),
1712            Self::Rc => write!(f, "rc"),
1713        }
1714    }
1715}
1716
1717impl std::fmt::Display for Prerelease {
1718    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1719        write!(f, "{}{}", self.kind, self.number)
1720    }
1721}
1722
1723/// Either a sequence of local segments or [`LocalVersion::Sentinel`], an internal-only value that
1724/// compares greater than all other local versions.
1725#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1726#[cfg_attr(
1727    feature = "rkyv",
1728    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1729)]
1730#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1731pub enum LocalVersion {
1732    /// A sequence of local segments.
1733    Segments(Vec<LocalSegment>),
1734    /// An internal-only value that compares greater to all other local versions.
1735    Max,
1736}
1737
1738/// Like [`LocalVersion`], but using a slice
1739#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1740pub enum LocalVersionSlice<'a> {
1741    /// Like [`LocalVersion::Segments`]
1742    Segments(&'a [LocalSegment]),
1743    /// Like [`LocalVersion::Sentinel`]
1744    Max,
1745}
1746
1747impl LocalVersion {
1748    /// Return an empty local version.
1749    fn empty() -> Self {
1750        Self::Segments(Vec::new())
1751    }
1752
1753    /// Returns `true` if the local version is empty.
1754    fn is_empty(&self) -> bool {
1755        match self {
1756            Self::Segments(segments) => segments.is_empty(),
1757            Self::Max => false,
1758        }
1759    }
1760
1761    /// Convert the local version segments into a slice.
1762    fn as_slice(&self) -> LocalVersionSlice<'_> {
1763        match self {
1764            Self::Segments(segments) => LocalVersionSlice::Segments(segments),
1765            Self::Max => LocalVersionSlice::Max,
1766        }
1767    }
1768}
1769
1770/// Output the local version identifier string.
1771///
1772/// [`LocalVersionSlice::Max`] maps to `"[max]"` which is otherwise an illegal local
1773/// version because `[` and `]` are not allowed.
1774impl std::fmt::Display for LocalVersionSlice<'_> {
1775    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1776        match self {
1777            Self::Segments(segments) => {
1778                for (i, segment) in segments.iter().enumerate() {
1779                    if i > 0 {
1780                        write!(f, ".")?;
1781                    }
1782                    write!(f, "{segment}")?;
1783                }
1784                Ok(())
1785            }
1786            Self::Max => write!(f, "[max]"),
1787        }
1788    }
1789}
1790
1791impl CacheKey for LocalVersionSlice<'_> {
1792    fn cache_key(&self, state: &mut CacheKeyHasher) {
1793        match self {
1794            Self::Segments(segments) => {
1795                0u8.cache_key(state);
1796                segments.len().cache_key(state);
1797                for segment in *segments {
1798                    segment.cache_key(state);
1799                }
1800            }
1801            Self::Max => {
1802                1u8.cache_key(state);
1803            }
1804        }
1805    }
1806}
1807
1808impl PartialOrd for LocalVersionSlice<'_> {
1809    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1810        Some(self.cmp(other))
1811    }
1812}
1813
1814impl Ord for LocalVersionSlice<'_> {
1815    fn cmp(&self, other: &Self) -> Ordering {
1816        match (self, other) {
1817            (LocalVersionSlice::Segments(lv1), LocalVersionSlice::Segments(lv2)) => lv1.cmp(lv2),
1818            (LocalVersionSlice::Segments(_), LocalVersionSlice::Max) => Ordering::Less,
1819            (LocalVersionSlice::Max, LocalVersionSlice::Segments(_)) => Ordering::Greater,
1820            (LocalVersionSlice::Max, LocalVersionSlice::Max) => Ordering::Equal,
1821        }
1822    }
1823}
1824
1825impl LocalVersionSlice<'_> {
1826    /// Return an empty local version.
1827    const fn empty() -> Self {
1828        Self::Segments(&[])
1829    }
1830
1831    /// Returns `true` if the local version is empty.
1832    pub fn is_empty(&self) -> bool {
1833        matches!(self, &Self::Segments(&[]))
1834    }
1835}
1836
1837/// A part of the [local version identifier](<https://peps.python.org/pep-0440/#local-version-identifiers>)
1838///
1839/// Local versions are a mess:
1840///
1841/// > Comparison and ordering of local versions considers each segment of the local version
1842/// > (divided by a .) separately. If a segment consists entirely of ASCII digits then that section
1843/// > should be considered an integer for comparison purposes and if a segment contains any ASCII
1844/// > letters then that segment is compared lexicographically with case insensitivity. When
1845/// > comparing a numeric and lexicographic segment, the numeric section always compares as greater
1846/// > than the lexicographic segment. Additionally, a local version with a great number of segments
1847/// > will always compare as greater than a local version with fewer segments, as long as the
1848/// > shorter local version’s segments match the beginning of the longer local version’s segments
1849/// > exactly.
1850///
1851/// Luckily the default `Ord` implementation for `Vec<LocalSegment>` matches the PEP 440 rules.
1852#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1853#[cfg_attr(
1854    feature = "rkyv",
1855    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1856)]
1857#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1858pub enum LocalSegment {
1859    /// Not-parseable as integer segment of local version
1860    String(String),
1861    /// Inferred integer segment of local version
1862    Number(u64),
1863}
1864
1865impl std::fmt::Display for LocalSegment {
1866    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1867        match self {
1868            Self::String(string) => write!(f, "{string}"),
1869            Self::Number(number) => write!(f, "{number}"),
1870        }
1871    }
1872}
1873
1874impl CacheKey for LocalSegment {
1875    fn cache_key(&self, state: &mut CacheKeyHasher) {
1876        match self {
1877            Self::String(string) => {
1878                0u8.cache_key(state);
1879                string.cache_key(state);
1880            }
1881            Self::Number(number) => {
1882                1u8.cache_key(state);
1883                number.cache_key(state);
1884            }
1885        }
1886    }
1887}
1888
1889impl PartialOrd for LocalSegment {
1890    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1891        Some(self.cmp(other))
1892    }
1893}
1894
1895impl Ord for LocalSegment {
1896    fn cmp(&self, other: &Self) -> Ordering {
1897        // <https://peps.python.org/pep-0440/#local-version-identifiers>
1898        match (self, other) {
1899            (Self::Number(n1), Self::Number(n2)) => n1.cmp(n2),
1900            (Self::String(s1), Self::String(s2)) => s1.cmp(s2),
1901            (Self::Number(_), Self::String(_)) => Ordering::Greater,
1902            (Self::String(_), Self::Number(_)) => Ordering::Less,
1903        }
1904    }
1905}
1906
1907/// The state used for [parsing a version][pep440].
1908///
1909/// This parses the most "flexible" format of a version as described in the
1910/// "normalization" section of PEP 440.
1911///
1912/// This can also parse a version "pattern," which essentially is just like
1913/// parsing a version, but permits a trailing wildcard. e.g., `1.2.*`.
1914///
1915/// [pep440]: https://packaging.python.org/en/latest/specifications/version-specifiers/
1916#[derive(Debug)]
1917struct Parser<'a> {
1918    /// The version string we are parsing.
1919    v: &'a [u8],
1920    /// The current position of the parser.
1921    i: usize,
1922    /// The epoch extracted from the version.
1923    epoch: u64,
1924    /// The release numbers extracted from the version.
1925    release: ReleaseNumbers,
1926    /// The pre-release version, if any.
1927    pre: Option<Prerelease>,
1928    /// The post-release version, if any.
1929    post: Option<u64>,
1930    /// The dev release, if any.
1931    dev: Option<u64>,
1932    /// The local segments, if any.
1933    local: Vec<LocalSegment>,
1934    /// Whether a wildcard at the end of the version was found or not.
1935    ///
1936    /// This is only valid when a version pattern is being parsed.
1937    wildcard: bool,
1938}
1939
1940impl<'a> Parser<'a> {
1941    /// The "separators" that are allowed in several different parts of a
1942    /// version.
1943    #[expect(clippy::byte_char_slices)]
1944    const SEPARATOR: ByteSet = ByteSet::new(&[b'.', b'_', b'-']);
1945
1946    /// Create a new `Parser` for parsing the version in the given byte string.
1947    fn new(version: &'a [u8]) -> Self {
1948        Parser {
1949            v: version,
1950            i: 0,
1951            epoch: 0,
1952            release: ReleaseNumbers::new(),
1953            pre: None,
1954            post: None,
1955            dev: None,
1956            local: vec![],
1957            wildcard: false,
1958        }
1959    }
1960
1961    /// Parse a verbatim version.
1962    ///
1963    /// If a version pattern is found, then an error is returned.
1964    fn parse(self) -> Result<Version, VersionParseError> {
1965        match self.parse_pattern() {
1966            Ok(vpat) => {
1967                if vpat.is_wildcard() {
1968                    Err(ErrorKind::Wildcard.into())
1969                } else {
1970                    Ok(vpat.into_version())
1971                }
1972            }
1973            // If we get an error when parsing a version pattern, then
1974            // usually it will actually just be a VersionParseError.
1975            // But if it's specific to version patterns, and since
1976            // we are expecting a verbatim version here, we can just
1977            // return a generic "wildcards not allowed" error in that
1978            // case.
1979            Err(err) => match *err.kind {
1980                PatternErrorKind::Version(err) => Err(err),
1981                PatternErrorKind::WildcardNotTrailing => Err(ErrorKind::Wildcard.into()),
1982            },
1983        }
1984    }
1985
1986    /// Parse a version pattern, which may be a verbatim version.
1987    fn parse_pattern(mut self) -> Result<VersionPattern, VersionPatternParseError> {
1988        if let Some(vpat) = self.parse_fast() {
1989            return Ok(vpat);
1990        }
1991        self.bump_while(|byte| byte.is_ascii_whitespace());
1992        self.bump_if("v");
1993        self.parse_epoch_and_initial_release()?;
1994        self.parse_rest_of_release()?;
1995        if self.parse_wildcard()? {
1996            return Ok(self.into_pattern());
1997        }
1998        self.parse_pre()?;
1999        self.parse_post()?;
2000        self.parse_dev()?;
2001        self.parse_local()?;
2002        self.bump_while(|byte| byte.is_ascii_whitespace());
2003        if !self.is_done() {
2004            let version = String::from_utf8_lossy(&self.v[..self.i]).into_owned();
2005            let remaining = String::from_utf8_lossy(&self.v[self.i..]).into_owned();
2006            return Err(ErrorKind::UnexpectedEnd { version, remaining }.into());
2007        }
2008        Ok(self.into_pattern())
2009    }
2010
2011    /// Attempts to do a "fast parse" of a version.
2012    ///
2013    /// This looks for versions of the form `w[.x[.y[.z]]]` while
2014    /// simultaneously parsing numbers. This format corresponds to the
2015    /// overwhelming majority of all version strings and can avoid most of the
2016    /// work done in the more general parser.
2017    ///
2018    /// If the version string is not in the format of `w[.x[.y[.z]]]`, then
2019    /// this returns `None`.
2020    fn parse_fast(&self) -> Option<VersionPattern> {
2021        let (mut prev_digit, mut cur, mut release, mut len) = (false, 0u8, [0u8; 4], 0u8);
2022        for &byte in self.v {
2023            if byte == b'.' {
2024                if !prev_digit {
2025                    return None;
2026                }
2027                prev_digit = false;
2028                *release.get_mut(usize::from(len))? = cur;
2029                len += 1;
2030                cur = 0;
2031            } else {
2032                let digit = byte.checked_sub(b'0')?;
2033                if digit > 9 {
2034                    return None;
2035                }
2036                prev_digit = true;
2037                cur = cur.checked_mul(10)?.checked_add(digit)?;
2038            }
2039        }
2040        if !prev_digit {
2041            return None;
2042        }
2043        *release.get_mut(usize::from(len))? = cur;
2044        len += 1;
2045        let small = VersionSmall {
2046            _force_niche: NonZero::<u8>::MIN,
2047            repr: (u64::from(release[0]) << 48)
2048                | (u64::from(release[1]) << 40)
2049                | (u64::from(release[2]) << 32)
2050                | (u64::from(release[3]) << 24)
2051                | (VersionSmall::SUFFIX_NONE << VersionSmall::SUFFIX_VERSION_BIT_LEN),
2052
2053            len,
2054        };
2055        let inner = VersionInner::Small { small };
2056        let version = Version { inner };
2057        Some(VersionPattern {
2058            version,
2059            wildcard: false,
2060        })
2061    }
2062
2063    /// Parses an optional initial epoch number and the first component of the
2064    /// release part of a version number. In all cases, the first part of a
2065    /// version must be a single number, and if one isn't found, an error is
2066    /// returned.
2067    ///
2068    /// Upon success, the epoch is possibly set and the release has exactly one
2069    /// number in it. The parser will be positioned at the beginning of the
2070    /// next component, which is usually a `.`, indicating the start of the
2071    /// second number in the release component. It could however point to the
2072    /// end of input, in which case, a valid version should be returned.
2073    fn parse_epoch_and_initial_release(&mut self) -> Result<(), VersionPatternParseError> {
2074        let first_number = self.parse_number()?.ok_or(ErrorKind::NoLeadingNumber)?;
2075        let first_release_number = if self.bump_if("!") {
2076            self.epoch = first_number;
2077            self.parse_number()?
2078                .ok_or(ErrorKind::NoLeadingReleaseNumber)?
2079        } else {
2080            first_number
2081        };
2082        self.release.push(first_release_number);
2083        Ok(())
2084    }
2085
2086    /// This parses the rest of the numbers in the release component of
2087    /// the version. Upon success, the release part of this parser will be
2088    /// completely finished, and the parser will be positioned at the first
2089    /// character after the last number in the release component. This position
2090    /// may point to a `.`, for example, the second dot in `1.2.*` or `1.2.a5`
2091    /// or `1.2.dev5`. It may also point to the end of the input, in which
2092    /// case, the caller should return the current version.
2093    ///
2094    /// Callers should use this after the initial optional epoch and the first
2095    /// release number have been parsed.
2096    fn parse_rest_of_release(&mut self) -> Result<(), VersionPatternParseError> {
2097        while self.bump_if(".") {
2098            let Some(n) = self.parse_number()? else {
2099                self.unbump();
2100                break;
2101            };
2102            self.release.push(n);
2103        }
2104        Ok(())
2105    }
2106
2107    /// Attempts to parse a trailing wildcard after the numbers in the release
2108    /// component. Upon success, this returns `true` and positions the parser
2109    /// immediately after the `.*` (which must necessarily be the end of
2110    /// input), or leaves it unchanged if no wildcard was found. It is an error
2111    /// if a `.*` is found and there is still more input after the `.*`.
2112    ///
2113    /// Callers should use this immediately after parsing all of the numbers in
2114    /// the release component of the version.
2115    fn parse_wildcard(&mut self) -> Result<bool, VersionPatternParseError> {
2116        if !self.bump_if(".*") {
2117            return Ok(false);
2118        }
2119        if !self.is_done() {
2120            return Err(PatternErrorKind::WildcardNotTrailing.into());
2121        }
2122        self.wildcard = true;
2123        Ok(true)
2124    }
2125
2126    /// Parses the pre-release component of a version.
2127    ///
2128    /// If this version has no pre-release component, then this is a no-op.
2129    /// Otherwise, it sets `self.pre` and positions the parser to the first
2130    /// byte immediately following the pre-release.
2131    fn parse_pre(&mut self) -> Result<(), VersionPatternParseError> {
2132        // SPELLINGS and MAP are in correspondence. SPELLINGS is used to look
2133        // for what spelling is used in the version string (if any), and
2134        // the index of the element found is used to lookup which type of
2135        // pre-release it is.
2136        //
2137        // Note also that the order of the strings themselves matters. If 'pre'
2138        // were before 'preview' for example, then 'preview' would never match
2139        // since the strings are matched in order.
2140        const SPELLINGS: StringSet =
2141            StringSet::new(&["alpha", "beta", "preview", "pre", "rc", "a", "b", "c"]);
2142        const MAP: &[PrereleaseKind] = &[
2143            PrereleaseKind::Alpha,
2144            PrereleaseKind::Beta,
2145            PrereleaseKind::Rc,
2146            PrereleaseKind::Rc,
2147            PrereleaseKind::Rc,
2148            PrereleaseKind::Alpha,
2149            PrereleaseKind::Beta,
2150            PrereleaseKind::Rc,
2151        ];
2152
2153        let oldpos = self.i;
2154        self.bump_if_byte_set(&Parser::SEPARATOR);
2155        let Some(spelling) = self.bump_if_string_set(&SPELLINGS) else {
2156            // We might see a separator (or not) and then something
2157            // that isn't a pre-release. At this stage, we can't tell
2158            // whether it's invalid or not. So we back-up and let the
2159            // caller try something else.
2160            self.reset(oldpos);
2161            return Ok(());
2162        };
2163        let kind = MAP[spelling];
2164        self.bump_if_byte_set(&Parser::SEPARATOR);
2165        // Under the normalization rules, a pre-release without an
2166        // explicit number defaults to `0`.
2167        let number = self.parse_number()?.unwrap_or(0);
2168        self.pre = Some(Prerelease { kind, number });
2169        Ok(())
2170    }
2171
2172    /// Parses the post-release component of a version.
2173    ///
2174    /// If this version has no post-release component, then this is a no-op.
2175    /// Otherwise, it sets `self.post` and positions the parser to the first
2176    /// byte immediately following the post-release.
2177    fn parse_post(&mut self) -> Result<(), VersionPatternParseError> {
2178        const SPELLINGS: StringSet = StringSet::new(&["post", "rev", "r"]);
2179
2180        let oldpos = self.i;
2181        if self.bump_if("-") {
2182            if let Some(n) = self.parse_number()? {
2183                self.post = Some(n);
2184                return Ok(());
2185            }
2186            self.reset(oldpos);
2187        }
2188        self.bump_if_byte_set(&Parser::SEPARATOR);
2189        if self.bump_if_string_set(&SPELLINGS).is_none() {
2190            // As with pre-releases, if we don't see post|rev|r here, we can't
2191            // yet determine whether the version as a whole is invalid since
2192            // post-releases are optional.
2193            self.reset(oldpos);
2194            return Ok(());
2195        }
2196        self.bump_if_byte_set(&Parser::SEPARATOR);
2197        // Under the normalization rules, a post-release without an
2198        // explicit number defaults to `0`.
2199        self.post = Some(self.parse_number()?.unwrap_or(0));
2200        Ok(())
2201    }
2202
2203    /// Parses the dev-release component of a version.
2204    ///
2205    /// If this version has no dev-release component, then this is a no-op.
2206    /// Otherwise, it sets `self.dev` and positions the parser to the first
2207    /// byte immediately following the post-release.
2208    fn parse_dev(&mut self) -> Result<(), VersionPatternParseError> {
2209        let oldpos = self.i;
2210        self.bump_if_byte_set(&Parser::SEPARATOR);
2211        if !self.bump_if("dev") {
2212            // As with pre-releases, if we don't see dev here, we can't
2213            // yet determine whether the version as a whole is invalid
2214            // since dev-releases are optional.
2215            self.reset(oldpos);
2216            return Ok(());
2217        }
2218        self.bump_if_byte_set(&Parser::SEPARATOR);
2219        // Under the normalization rules, a post-release without an
2220        // explicit number defaults to `0`.
2221        self.dev = Some(self.parse_number()?.unwrap_or(0));
2222        Ok(())
2223    }
2224
2225    /// Parses the local component of a version.
2226    ///
2227    /// If this version has no local component, then this is a no-op.
2228    /// Otherwise, it adds to `self.local` and positions the parser to the
2229    /// first byte immediately following the local component. (Which ought to
2230    /// be the end of the version since the local component is the last thing
2231    /// that can appear in a version.)
2232    fn parse_local(&mut self) -> Result<(), VersionPatternParseError> {
2233        if !self.bump_if("+") {
2234            return Ok(());
2235        }
2236        let mut precursor = '+';
2237        loop {
2238            let first = self.bump_while(|byte| byte.is_ascii_alphanumeric());
2239            if first.is_empty() {
2240                return Err(ErrorKind::LocalEmpty { precursor }.into());
2241            }
2242            self.local.push(if let Ok(number) = parse_u64(first) {
2243                LocalSegment::Number(number)
2244            } else {
2245                let string = String::from_utf8(first.to_ascii_lowercase())
2246                    .expect("ASCII alphanumerics are always valid UTF-8");
2247                LocalSegment::String(string)
2248            });
2249            let Some(byte) = self.bump_if_byte_set(&Parser::SEPARATOR) else {
2250                break;
2251            };
2252            precursor = char::from(byte);
2253        }
2254        Ok(())
2255    }
2256
2257    /// Consumes input from the current position while the characters are ASCII
2258    /// digits, and then attempts to parse what was consumed as a decimal
2259    /// number.
2260    ///
2261    /// If nothing was consumed, then `Ok(None)` is returned. Otherwise, if the
2262    /// digits consumed do not form a valid decimal number that fits into a
2263    /// `u64`, then an error is returned.
2264    fn parse_number(&mut self) -> Result<Option<u64>, VersionPatternParseError> {
2265        let digits = self.bump_while(|ch| ch.is_ascii_digit());
2266        if digits.is_empty() {
2267            return Ok(None);
2268        }
2269        let n = parse_u64(digits)?;
2270        // Reject `u64::MAX` to prevent arithmetic overflow in downstream code
2271        // that computes `segment + 1` (e.g., `~=` upper bound, `==*` upper
2272        // bound, `python_version` marker algebra). This only applies to version
2273        // segments (release, epoch, pre/post/dev), not local version segments
2274        // which don't undergo arithmetic.
2275        if n == u64::MAX {
2276            return Err(ErrorKind::NumberTooBig {
2277                bytes: digits.to_vec(),
2278            }
2279            .into());
2280        }
2281        Ok(Some(n))
2282    }
2283
2284    /// Turns whatever state has been gathered into a `VersionPattern`.
2285    ///
2286    /// # Panics
2287    ///
2288    /// When `self.release` is empty. Callers must ensure at least one part
2289    /// of the release component has been successfully parsed. Otherwise, the
2290    /// version itself is invalid.
2291    fn into_pattern(self) -> VersionPattern {
2292        assert!(
2293            self.release.len() > 0,
2294            "version with no release numbers is invalid"
2295        );
2296        let version = Version::new(self.release.as_slice())
2297            .with_epoch(self.epoch)
2298            .with_pre(self.pre)
2299            .with_post(self.post)
2300            .with_dev(self.dev)
2301            .with_local(LocalVersion::Segments(self.local));
2302        VersionPattern {
2303            version,
2304            wildcard: self.wildcard,
2305        }
2306    }
2307
2308    /// Consumes input from this parser while the given predicate returns true.
2309    /// The resulting input (which may be empty) is returned.
2310    ///
2311    /// Once returned, the parser is positioned at the first position where the
2312    /// predicate returns `false`. (This may be the position at the end of the
2313    /// input such that [`Parser::is_done`] returns `true`.)
2314    fn bump_while(&mut self, mut predicate: impl FnMut(u8) -> bool) -> &'a [u8] {
2315        let start = self.i;
2316        while !self.is_done() && predicate(self.byte()) {
2317            self.i = self.i.saturating_add(1);
2318        }
2319        &self.v[start..self.i]
2320    }
2321
2322    /// Consumes `bytes.len()` bytes from the current position of the parser if
2323    /// and only if `bytes` is a prefix of the input starting at the current
2324    /// position. Otherwise, this is a no-op. Returns true when consumption was
2325    /// successful.
2326    fn bump_if(&mut self, string: &str) -> bool {
2327        if self.is_done() {
2328            return false;
2329        }
2330        if starts_with_ignore_ascii_case(string.as_bytes(), &self.v[self.i..]) {
2331            self.i = self
2332                .i
2333                .checked_add(string.len())
2334                .expect("valid offset because of prefix");
2335            true
2336        } else {
2337            false
2338        }
2339    }
2340
2341    /// Like [`Parser::bump_if`], but attempts each string in the ordered set
2342    /// given. If one is successfully consumed from the start of the current
2343    /// position in the input, then it is returned.
2344    fn bump_if_string_set(&mut self, set: &StringSet) -> Option<usize> {
2345        let index = set.starts_with(&self.v[self.i..])?;
2346        let found = &set.strings[index];
2347        self.i = self
2348            .i
2349            .checked_add(found.len())
2350            .expect("valid offset because of prefix");
2351        Some(index)
2352    }
2353
2354    /// Like [`Parser::bump_if`], but attempts each byte in the set
2355    /// given. If one is successfully consumed from the start of the
2356    /// current position in the input.
2357    fn bump_if_byte_set(&mut self, set: &ByteSet) -> Option<u8> {
2358        let found = set.starts_with(&self.v[self.i..])?;
2359        self.i = self
2360            .i
2361            .checked_add(1)
2362            .expect("valid offset because of prefix");
2363        Some(found)
2364    }
2365
2366    /// Moves the parser back one byte. i.e., ungetch.
2367    ///
2368    /// This is useful when one has bumped the parser "too far" and wants to
2369    /// back-up. This tends to help with composition among parser routines.
2370    ///
2371    /// # Panics
2372    ///
2373    /// When the parser is already positioned at the beginning.
2374    fn unbump(&mut self) {
2375        self.i = self.i.checked_sub(1).expect("not at beginning of input");
2376    }
2377
2378    /// Resets the parser to the given position.
2379    ///
2380    /// # Panics
2381    ///
2382    /// When `offset` is greater than `self.v.len()`.
2383    fn reset(&mut self, offset: usize) {
2384        assert!(offset <= self.v.len());
2385        self.i = offset;
2386    }
2387
2388    /// Returns the byte at the current position of the parser.
2389    ///
2390    /// # Panics
2391    ///
2392    /// When `Parser::is_done` returns `true`.
2393    fn byte(&self) -> u8 {
2394        self.v[self.i]
2395    }
2396
2397    /// Returns true if and only if there is no more input to consume.
2398    fn is_done(&self) -> bool {
2399        self.i >= self.v.len()
2400    }
2401}
2402
2403/// Stores the numbers found in the release portion of a version.
2404///
2405/// We use this in the version parser to avoid allocating in the 90+% case.
2406#[derive(Debug)]
2407enum ReleaseNumbers {
2408    Inline { numbers: [u64; 4], len: usize },
2409    Vec(Vec<u64>),
2410}
2411
2412impl ReleaseNumbers {
2413    /// Create a new empty set of release numbers.
2414    fn new() -> Self {
2415        Self::Inline {
2416            numbers: [0; 4],
2417            len: 0,
2418        }
2419    }
2420
2421    /// Push a new release number. This automatically switches over to the heap
2422    /// when the lengths grow too big.
2423    fn push(&mut self, n: u64) {
2424        match *self {
2425            Self::Inline {
2426                ref mut numbers,
2427                ref mut len,
2428            } => {
2429                assert!(*len <= 4);
2430                if *len == 4 {
2431                    let mut numbers = numbers.to_vec();
2432                    numbers.push(n);
2433                    *self = Self::Vec(numbers.clone());
2434                } else {
2435                    numbers[*len] = n;
2436                    *len += 1;
2437                }
2438            }
2439            Self::Vec(ref mut numbers) => {
2440                numbers.push(n);
2441            }
2442        }
2443    }
2444
2445    /// Returns the number of components in this release component.
2446    fn len(&self) -> usize {
2447        self.as_slice().len()
2448    }
2449
2450    /// Returns the release components as a slice.
2451    fn as_slice(&self) -> &[u64] {
2452        match self {
2453            Self::Inline { numbers, len } => &numbers[..*len],
2454            Self::Vec(vec) => vec,
2455        }
2456    }
2457}
2458
2459/// Represents a set of strings for prefix searching.
2460///
2461/// This can be built as a constant and is useful for quickly looking for one
2462/// of a number of matching literal strings while ignoring ASCII case.
2463struct StringSet {
2464    /// A set of the first bytes of each string in this set. We use this to
2465    /// quickly bail out of searching if the first byte of our haystack doesn't
2466    /// match any element in this set.
2467    first_byte: ByteSet,
2468    /// The strings in this set. They are matched in order.
2469    strings: &'static [&'static str],
2470}
2471
2472impl StringSet {
2473    /// Create a new string set for prefix searching from the given strings.
2474    ///
2475    /// # Panics
2476    ///
2477    /// When the number of strings is too big.
2478    const fn new(strings: &'static [&'static str]) -> Self {
2479        assert!(
2480            strings.len() <= 20,
2481            "only a small number of strings are supported"
2482        );
2483        let (mut firsts, mut firsts_len) = ([0u8; 20], 0);
2484        let mut i = 0;
2485        while i < strings.len() {
2486            assert!(
2487                !strings[i].is_empty(),
2488                "every string in set should be non-empty",
2489            );
2490            firsts[firsts_len] = strings[i].as_bytes()[0];
2491            firsts_len += 1;
2492            i += 1;
2493        }
2494        let first_byte = ByteSet::new(&firsts);
2495        Self {
2496            first_byte,
2497            strings,
2498        }
2499    }
2500
2501    /// Returns the index of the first string in this set that is a prefix of
2502    /// the given haystack, or `None` if no elements are a prefix.
2503    fn starts_with(&self, haystack: &[u8]) -> Option<usize> {
2504        let first_byte = self.first_byte.starts_with(haystack)?;
2505        for (i, &string) in self.strings.iter().enumerate() {
2506            let bytes = string.as_bytes();
2507            if bytes[0].eq_ignore_ascii_case(&first_byte)
2508                && starts_with_ignore_ascii_case(bytes, haystack)
2509            {
2510                return Some(i);
2511            }
2512        }
2513        None
2514    }
2515}
2516
2517/// A set of bytes for searching case insensitively (ASCII only).
2518struct ByteSet {
2519    set: [bool; 256],
2520}
2521
2522impl ByteSet {
2523    /// Create a new byte set for searching from the given bytes.
2524    const fn new(bytes: &[u8]) -> Self {
2525        let mut set = [false; 256];
2526        let mut i = 0;
2527        while i < bytes.len() {
2528            set[bytes[i].to_ascii_uppercase() as usize] = true;
2529            set[bytes[i].to_ascii_lowercase() as usize] = true;
2530            i += 1;
2531        }
2532        Self { set }
2533    }
2534
2535    /// Returns the first byte in the haystack if and only if that byte is in
2536    /// this set (ignoring ASCII case).
2537    fn starts_with(&self, haystack: &[u8]) -> Option<u8> {
2538        let byte = *haystack.first()?;
2539        if self.contains(byte) {
2540            Some(byte)
2541        } else {
2542            None
2543        }
2544    }
2545
2546    /// Returns true if and only if the given byte is in this set.
2547    fn contains(&self, byte: u8) -> bool {
2548        self.set[usize::from(byte)]
2549    }
2550}
2551
2552impl std::fmt::Debug for ByteSet {
2553    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2554        let mut set = f.debug_set();
2555        for byte in 0..=255 {
2556            if self.contains(byte) {
2557                set.entry(&char::from(byte));
2558            }
2559        }
2560        set.finish()
2561    }
2562}
2563
2564/// An error that occurs when parsing a [`Version`] string fails.
2565#[derive(Clone, Debug, Eq, PartialEq)]
2566pub struct VersionParseError {
2567    kind: Box<ErrorKind>,
2568}
2569
2570impl std::error::Error for VersionParseError {}
2571
2572impl std::fmt::Display for VersionParseError {
2573    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2574        match *self.kind {
2575            ErrorKind::Wildcard => write!(f, "wildcards are not allowed in a version"),
2576            ErrorKind::InvalidDigit { got } if got.is_ascii() => {
2577                write!(f, "expected ASCII digit, but found {:?}", char::from(got))
2578            }
2579            ErrorKind::InvalidDigit { got } => {
2580                write!(
2581                    f,
2582                    "expected ASCII digit, but found non-ASCII byte \\x{got:02X}"
2583                )
2584            }
2585            ErrorKind::NumberTooBig { ref bytes } => {
2586                let string = match std::str::from_utf8(bytes) {
2587                    Ok(v) => v,
2588                    Err(err) => {
2589                        std::str::from_utf8(&bytes[..err.valid_up_to()]).expect("valid UTF-8")
2590                    }
2591                };
2592                write!(
2593                    f,
2594                    "expected number less than or equal to {}, \
2595                     but number found in {string:?} exceeds it",
2596                    u64::MAX - 1,
2597                )
2598            }
2599            ErrorKind::NoLeadingNumber => {
2600                write!(
2601                    f,
2602                    "expected version to start with a number, \
2603                     but no leading ASCII digits were found"
2604                )
2605            }
2606            ErrorKind::NoLeadingReleaseNumber => {
2607                write!(
2608                    f,
2609                    "expected version to have a non-empty release component after an epoch, \
2610                     but no ASCII digits after the epoch were found"
2611                )
2612            }
2613            ErrorKind::LocalEmpty { precursor } => {
2614                write!(
2615                    f,
2616                    "found a `{precursor}` indicating the start of a local \
2617                     component in a version, but did not find any alphanumeric \
2618                     ASCII segment following the `{precursor}`",
2619                )
2620            }
2621            ErrorKind::UnexpectedEnd {
2622                ref version,
2623                ref remaining,
2624            } => {
2625                write!(
2626                    f,
2627                    "after parsing `{version}`, found `{remaining}`, \
2628                     which is not part of a valid version",
2629                )
2630            }
2631        }
2632    }
2633}
2634
2635/// The kind of error that occurs when parsing a `Version`.
2636#[derive(Clone, Debug, Eq, PartialEq)]
2637pub(crate) enum ErrorKind {
2638    /// Occurs when a version pattern is found but a normal verbatim version is
2639    /// expected.
2640    Wildcard,
2641    /// Occurs when an ASCII digit was expected, but something else was found.
2642    InvalidDigit {
2643        /// The (possibly non-ASCII) byte that was seen instead of [0-9].
2644        got: u8,
2645    },
2646    /// Occurs when a number was found that exceeds what can fit into a u64.
2647    NumberTooBig {
2648        /// The bytes that were being parsed as a number. These may contain
2649        /// invalid digits or even invalid UTF-8.
2650        bytes: Vec<u8>,
2651    },
2652    /// Occurs when a version does not start with a leading number.
2653    NoLeadingNumber,
2654    /// Occurs when an epoch version does not have a number after the `!`.
2655    NoLeadingReleaseNumber,
2656    /// Occurs when a `+` (or a `.` after the first local segment) is seen
2657    /// (indicating a local component of a version), but no alphanumeric ASCII
2658    /// string is found following it.
2659    LocalEmpty {
2660        /// Either a `+` or a `[-_.]` indicating what was found that demands a
2661        /// non-empty local segment following it.
2662        precursor: char,
2663    },
2664    /// Occurs when a version has been parsed but there is some unexpected
2665    /// trailing data in the string.
2666    UnexpectedEnd {
2667        /// The version that has been parsed so far.
2668        version: String,
2669        /// The bytes that were remaining and not parsed.
2670        remaining: String,
2671    },
2672}
2673
2674impl From<ErrorKind> for VersionParseError {
2675    fn from(kind: ErrorKind) -> Self {
2676        Self {
2677            kind: Box::new(kind),
2678        }
2679    }
2680}
2681
2682/// An error that occurs when parsing a [`VersionPattern`] string fails.
2683#[derive(Clone, Debug, Eq, PartialEq)]
2684pub struct VersionPatternParseError {
2685    kind: Box<PatternErrorKind>,
2686}
2687
2688impl std::error::Error for VersionPatternParseError {}
2689
2690impl std::fmt::Display for VersionPatternParseError {
2691    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2692        match *self.kind {
2693            PatternErrorKind::Version(ref err) => err.fmt(f),
2694            PatternErrorKind::WildcardNotTrailing => {
2695                write!(f, "wildcards in versions must be at the end")
2696            }
2697        }
2698    }
2699}
2700
2701/// The kind of error that occurs when parsing a `VersionPattern`.
2702#[derive(Clone, Debug, Eq, PartialEq)]
2703pub(crate) enum PatternErrorKind {
2704    Version(VersionParseError),
2705    WildcardNotTrailing,
2706}
2707
2708impl From<PatternErrorKind> for VersionPatternParseError {
2709    fn from(kind: PatternErrorKind) -> Self {
2710        Self {
2711            kind: Box::new(kind),
2712        }
2713    }
2714}
2715
2716impl From<ErrorKind> for VersionPatternParseError {
2717    fn from(kind: ErrorKind) -> Self {
2718        Self::from(VersionParseError::from(kind))
2719    }
2720}
2721
2722impl From<VersionParseError> for VersionPatternParseError {
2723    fn from(err: VersionParseError) -> Self {
2724        Self {
2725            kind: Box::new(PatternErrorKind::Version(err)),
2726        }
2727    }
2728}
2729
2730/// Compare the release parts of two versions, e.g. `4.3.1` > `4.2`, `1.1.0` ==
2731/// `1.1` and `1.16` < `1.19`
2732pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2733    if this.len() == other.len() {
2734        return this.cmp(other);
2735    }
2736    // "When comparing release segments with different numbers of components, the shorter segment
2737    // is padded out with additional zeros as necessary"
2738    for (this, other) in this.iter().chain(std::iter::repeat(&0)).zip(
2739        other
2740            .iter()
2741            .chain(std::iter::repeat(&0))
2742            .take(this.len().max(other.len())),
2743    ) {
2744        match this.cmp(other) {
2745            Ordering::Less => {
2746                return Ordering::Less;
2747            }
2748            Ordering::Equal => {}
2749            Ordering::Greater => {
2750                return Ordering::Greater;
2751            }
2752        }
2753    }
2754    Ordering::Equal
2755}
2756
2757/// Compare the parts attached after the release, given equal release
2758///
2759/// According to [a summary of permitted suffixes and relative
2760/// ordering][pep440-suffix-ordering] the order of pre/post-releases is: .devN,
2761/// aN, bN, rcN, <no suffix (final)>, .postN but also, you can have dev/post
2762/// releases on beta releases, so we make a three stage ordering: ({min: 0,
2763/// dev: 1, a: 2, b: 3, rc: 4, (): 5, post: 6}, <preN>, <postN or None as
2764/// smallest>, <devN or Max as largest>, <local>)
2765///
2766/// For post, any number is better than none (so None defaults to None<0),
2767/// but for dev, no number is better (so None default to the maximum). For
2768/// local the Option<Vec<T>> luckily already has the correct default Ord
2769/// implementation
2770///
2771/// [pep440-suffix-ordering]: https://peps.python.org/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering
2772fn sortable_tuple(version: &Version) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2773    // If the version is a "max" version, use a post version larger than any possible post version.
2774    let post = if version.max().is_some() {
2775        Some(u64::MAX)
2776    } else {
2777        version.post()
2778    };
2779    match (version.pre(), post, version.dev(), version.min()) {
2780        // min release
2781        (_pre, post, _dev, Some(n)) => (0, 0, post, n, version.local()),
2782        // dev release
2783        (None, None, Some(n), None) => (1, 0, None, n, version.local()),
2784        // alpha release
2785        (
2786            Some(Prerelease {
2787                kind: PrereleaseKind::Alpha,
2788                number: n,
2789            }),
2790            post,
2791            dev,
2792            None,
2793        ) => (2, n, post, dev.unwrap_or(u64::MAX), version.local()),
2794        // beta release
2795        (
2796            Some(Prerelease {
2797                kind: PrereleaseKind::Beta,
2798                number: n,
2799            }),
2800            post,
2801            dev,
2802            None,
2803        ) => (3, n, post, dev.unwrap_or(u64::MAX), version.local()),
2804        // alpha release
2805        (
2806            Some(Prerelease {
2807                kind: PrereleaseKind::Rc,
2808                number: n,
2809            }),
2810            post,
2811            dev,
2812            None,
2813        ) => (4, n, post, dev.unwrap_or(u64::MAX), version.local()),
2814        // final release
2815        (None, None, None, None) => (5, 0, None, 0, version.local()),
2816        // post release
2817        (None, Some(post), dev, None) => {
2818            (6, 0, Some(post), dev.unwrap_or(u64::MAX), version.local())
2819        }
2820    }
2821}
2822
2823/// Returns true only when, ignoring ASCII case, `needle` is a prefix of
2824/// `haystack`.
2825fn starts_with_ignore_ascii_case(needle: &[u8], haystack: &[u8]) -> bool {
2826    needle.len() <= haystack.len()
2827        && std::iter::zip(needle, haystack).all(|(b1, b2)| b1.eq_ignore_ascii_case(b2))
2828}
2829
2830/// Parses a u64 number from the given slice of ASCII digit characters.
2831///
2832/// If any byte in the given slice is not [0-9], then this returns an error.
2833/// Similarly, if the number parsed does not fit into a `u64`, then this
2834/// returns an error.
2835///
2836/// # Motivation
2837///
2838/// We hand-write this for a couple reasons. Firstly, the standard library's
2839/// `FromStr` impl for parsing integers requires UTF-8 validation first. We
2840/// don't need that for version parsing since we stay in the realm of ASCII.
2841/// Secondly, std's version is a little more flexible because it supports
2842/// signed integers. So for example, it permits a leading `+` before the actual
2843/// integer. We don't need that for version parsing.
2844fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
2845    let mut n: u64 = 0;
2846    for &byte in bytes {
2847        let digit = match byte.checked_sub(b'0') {
2848            None => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2849            Some(digit) if digit > 9 => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2850            Some(digit) => {
2851                debug_assert!((0..=9).contains(&digit));
2852                u64::from(digit)
2853            }
2854        };
2855        n = n
2856            .checked_mul(10)
2857            .and_then(|n| n.checked_add(digit))
2858            .ok_or_else(|| ErrorKind::NumberTooBig {
2859                bytes: bytes.to_vec(),
2860            })?;
2861    }
2862    Ok(n)
2863}
2864
2865/// The minimum version that can be represented by a [`Version`]: `0a0.dev0`.
2866pub static MIN_VERSION: LazyLock<Version> =
2867    LazyLock::new(|| Version::from_str("0a0.dev0").unwrap());
2868
2869#[cfg(test)]
2870mod tests {
2871    use std::str::FromStr;
2872
2873    use crate::VersionSpecifier;
2874
2875    use super::*;
2876
2877    /// <https://github.com/pypa/packaging/blob/237ff3aa348486cf835a980592af3a59fccd6101/tests/test_version.py#L24-L81>
2878    #[test]
2879    fn test_packaging_versions() {
2880        let versions = [
2881            // Implicit epoch of 0
2882            ("1.0.dev456", Version::new([1, 0]).with_dev(Some(456))),
2883            (
2884                "1.0a1",
2885                Version::new([1, 0]).with_pre(Some(Prerelease {
2886                    kind: PrereleaseKind::Alpha,
2887                    number: 1,
2888                })),
2889            ),
2890            (
2891                "1.0a2.dev456",
2892                Version::new([1, 0])
2893                    .with_pre(Some(Prerelease {
2894                        kind: PrereleaseKind::Alpha,
2895                        number: 2,
2896                    }))
2897                    .with_dev(Some(456)),
2898            ),
2899            (
2900                "1.0a12.dev456",
2901                Version::new([1, 0])
2902                    .with_pre(Some(Prerelease {
2903                        kind: PrereleaseKind::Alpha,
2904                        number: 12,
2905                    }))
2906                    .with_dev(Some(456)),
2907            ),
2908            (
2909                "1.0a12",
2910                Version::new([1, 0]).with_pre(Some(Prerelease {
2911                    kind: PrereleaseKind::Alpha,
2912                    number: 12,
2913                })),
2914            ),
2915            (
2916                "1.0b1.dev456",
2917                Version::new([1, 0])
2918                    .with_pre(Some(Prerelease {
2919                        kind: PrereleaseKind::Beta,
2920                        number: 1,
2921                    }))
2922                    .with_dev(Some(456)),
2923            ),
2924            (
2925                "1.0b2",
2926                Version::new([1, 0]).with_pre(Some(Prerelease {
2927                    kind: PrereleaseKind::Beta,
2928                    number: 2,
2929                })),
2930            ),
2931            (
2932                "1.0b2.post345.dev456",
2933                Version::new([1, 0])
2934                    .with_pre(Some(Prerelease {
2935                        kind: PrereleaseKind::Beta,
2936                        number: 2,
2937                    }))
2938                    .with_dev(Some(456))
2939                    .with_post(Some(345)),
2940            ),
2941            (
2942                "1.0b2.post345",
2943                Version::new([1, 0])
2944                    .with_pre(Some(Prerelease {
2945                        kind: PrereleaseKind::Beta,
2946                        number: 2,
2947                    }))
2948                    .with_post(Some(345)),
2949            ),
2950            (
2951                "1.0b2-346",
2952                Version::new([1, 0])
2953                    .with_pre(Some(Prerelease {
2954                        kind: PrereleaseKind::Beta,
2955                        number: 2,
2956                    }))
2957                    .with_post(Some(346)),
2958            ),
2959            (
2960                "1.0c1.dev456",
2961                Version::new([1, 0])
2962                    .with_pre(Some(Prerelease {
2963                        kind: PrereleaseKind::Rc,
2964                        number: 1,
2965                    }))
2966                    .with_dev(Some(456)),
2967            ),
2968            (
2969                "1.0c1",
2970                Version::new([1, 0]).with_pre(Some(Prerelease {
2971                    kind: PrereleaseKind::Rc,
2972                    number: 1,
2973                })),
2974            ),
2975            (
2976                "1.0rc2",
2977                Version::new([1, 0]).with_pre(Some(Prerelease {
2978                    kind: PrereleaseKind::Rc,
2979                    number: 2,
2980                })),
2981            ),
2982            (
2983                "1.0c3",
2984                Version::new([1, 0]).with_pre(Some(Prerelease {
2985                    kind: PrereleaseKind::Rc,
2986                    number: 3,
2987                })),
2988            ),
2989            ("1.0", Version::new([1, 0])),
2990            (
2991                "1.0.post456.dev34",
2992                Version::new([1, 0]).with_post(Some(456)).with_dev(Some(34)),
2993            ),
2994            ("1.0.post456", Version::new([1, 0]).with_post(Some(456))),
2995            ("1.1.dev1", Version::new([1, 1]).with_dev(Some(1))),
2996            (
2997                "1.2+123abc",
2998                Version::new([1, 2])
2999                    .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3000            ),
3001            (
3002                "1.2+123abc456",
3003                Version::new([1, 2])
3004                    .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3005            ),
3006            (
3007                "1.2+abc",
3008                Version::new([1, 2])
3009                    .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3010            ),
3011            (
3012                "1.2+abc123",
3013                Version::new([1, 2])
3014                    .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3015            ),
3016            (
3017                "1.2+abc123def",
3018                Version::new([1, 2])
3019                    .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3020            ),
3021            (
3022                "1.2+1234.abc",
3023                Version::new([1, 2]).with_local_segments(vec![
3024                    LocalSegment::Number(1234),
3025                    LocalSegment::String("abc".to_string()),
3026                ]),
3027            ),
3028            (
3029                "1.2+123456",
3030                Version::new([1, 2]).with_local_segments(vec![LocalSegment::Number(123_456)]),
3031            ),
3032            (
3033                "1.2.r32+123456",
3034                Version::new([1, 2])
3035                    .with_post(Some(32))
3036                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3037            ),
3038            (
3039                "1.2.rev33+123456",
3040                Version::new([1, 2])
3041                    .with_post(Some(33))
3042                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3043            ),
3044            // Explicit epoch of 1
3045            (
3046                "1!1.0.dev456",
3047                Version::new([1, 0]).with_epoch(1).with_dev(Some(456)),
3048            ),
3049            (
3050                "1!1.0a1",
3051                Version::new([1, 0])
3052                    .with_epoch(1)
3053                    .with_pre(Some(Prerelease {
3054                        kind: PrereleaseKind::Alpha,
3055                        number: 1,
3056                    })),
3057            ),
3058            (
3059                "1!1.0a2.dev456",
3060                Version::new([1, 0])
3061                    .with_epoch(1)
3062                    .with_pre(Some(Prerelease {
3063                        kind: PrereleaseKind::Alpha,
3064                        number: 2,
3065                    }))
3066                    .with_dev(Some(456)),
3067            ),
3068            (
3069                "1!1.0a12.dev456",
3070                Version::new([1, 0])
3071                    .with_epoch(1)
3072                    .with_pre(Some(Prerelease {
3073                        kind: PrereleaseKind::Alpha,
3074                        number: 12,
3075                    }))
3076                    .with_dev(Some(456)),
3077            ),
3078            (
3079                "1!1.0a12",
3080                Version::new([1, 0])
3081                    .with_epoch(1)
3082                    .with_pre(Some(Prerelease {
3083                        kind: PrereleaseKind::Alpha,
3084                        number: 12,
3085                    })),
3086            ),
3087            (
3088                "1!1.0b1.dev456",
3089                Version::new([1, 0])
3090                    .with_epoch(1)
3091                    .with_pre(Some(Prerelease {
3092                        kind: PrereleaseKind::Beta,
3093                        number: 1,
3094                    }))
3095                    .with_dev(Some(456)),
3096            ),
3097            (
3098                "1!1.0b2",
3099                Version::new([1, 0])
3100                    .with_epoch(1)
3101                    .with_pre(Some(Prerelease {
3102                        kind: PrereleaseKind::Beta,
3103                        number: 2,
3104                    })),
3105            ),
3106            (
3107                "1!1.0b2.post345.dev456",
3108                Version::new([1, 0])
3109                    .with_epoch(1)
3110                    .with_pre(Some(Prerelease {
3111                        kind: PrereleaseKind::Beta,
3112                        number: 2,
3113                    }))
3114                    .with_post(Some(345))
3115                    .with_dev(Some(456)),
3116            ),
3117            (
3118                "1!1.0b2.post345",
3119                Version::new([1, 0])
3120                    .with_epoch(1)
3121                    .with_pre(Some(Prerelease {
3122                        kind: PrereleaseKind::Beta,
3123                        number: 2,
3124                    }))
3125                    .with_post(Some(345)),
3126            ),
3127            (
3128                "1!1.0b2-346",
3129                Version::new([1, 0])
3130                    .with_epoch(1)
3131                    .with_pre(Some(Prerelease {
3132                        kind: PrereleaseKind::Beta,
3133                        number: 2,
3134                    }))
3135                    .with_post(Some(346)),
3136            ),
3137            (
3138                "1!1.0c1.dev456",
3139                Version::new([1, 0])
3140                    .with_epoch(1)
3141                    .with_pre(Some(Prerelease {
3142                        kind: PrereleaseKind::Rc,
3143                        number: 1,
3144                    }))
3145                    .with_dev(Some(456)),
3146            ),
3147            (
3148                "1!1.0c1",
3149                Version::new([1, 0])
3150                    .with_epoch(1)
3151                    .with_pre(Some(Prerelease {
3152                        kind: PrereleaseKind::Rc,
3153                        number: 1,
3154                    })),
3155            ),
3156            (
3157                "1!1.0rc2",
3158                Version::new([1, 0])
3159                    .with_epoch(1)
3160                    .with_pre(Some(Prerelease {
3161                        kind: PrereleaseKind::Rc,
3162                        number: 2,
3163                    })),
3164            ),
3165            (
3166                "1!1.0c3",
3167                Version::new([1, 0])
3168                    .with_epoch(1)
3169                    .with_pre(Some(Prerelease {
3170                        kind: PrereleaseKind::Rc,
3171                        number: 3,
3172                    })),
3173            ),
3174            ("1!1.0", Version::new([1, 0]).with_epoch(1)),
3175            (
3176                "1!1.0.post456.dev34",
3177                Version::new([1, 0])
3178                    .with_epoch(1)
3179                    .with_post(Some(456))
3180                    .with_dev(Some(34)),
3181            ),
3182            (
3183                "1!1.0.post456",
3184                Version::new([1, 0]).with_epoch(1).with_post(Some(456)),
3185            ),
3186            (
3187                "1!1.1.dev1",
3188                Version::new([1, 1]).with_epoch(1).with_dev(Some(1)),
3189            ),
3190            (
3191                "1!1.2+123abc",
3192                Version::new([1, 2])
3193                    .with_epoch(1)
3194                    .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3195            ),
3196            (
3197                "1!1.2+123abc456",
3198                Version::new([1, 2])
3199                    .with_epoch(1)
3200                    .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3201            ),
3202            (
3203                "1!1.2+abc",
3204                Version::new([1, 2])
3205                    .with_epoch(1)
3206                    .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3207            ),
3208            (
3209                "1!1.2+abc123",
3210                Version::new([1, 2])
3211                    .with_epoch(1)
3212                    .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3213            ),
3214            (
3215                "1!1.2+abc123def",
3216                Version::new([1, 2])
3217                    .with_epoch(1)
3218                    .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3219            ),
3220            (
3221                "1!1.2+1234.abc",
3222                Version::new([1, 2]).with_epoch(1).with_local_segments(vec![
3223                    LocalSegment::Number(1234),
3224                    LocalSegment::String("abc".to_string()),
3225                ]),
3226            ),
3227            (
3228                "1!1.2+123456",
3229                Version::new([1, 2])
3230                    .with_epoch(1)
3231                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3232            ),
3233            (
3234                "1!1.2.r32+123456",
3235                Version::new([1, 2])
3236                    .with_epoch(1)
3237                    .with_post(Some(32))
3238                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3239            ),
3240            (
3241                "1!1.2.rev33+123456",
3242                Version::new([1, 2])
3243                    .with_epoch(1)
3244                    .with_post(Some(33))
3245                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3246            ),
3247            (
3248                "98765!1.2.rev33+123456",
3249                Version::new([1, 2])
3250                    .with_epoch(98765)
3251                    .with_post(Some(33))
3252                    .with_local_segments(vec![LocalSegment::Number(123_456)]),
3253            ),
3254        ];
3255        for (string, structured) in versions {
3256            match Version::from_str(string) {
3257                Err(err) => {
3258                    unreachable!(
3259                        "expected {string:?} to parse as {structured:?}, but got {err:?}",
3260                        structured = structured.as_bloated_debug(),
3261                    )
3262                }
3263                Ok(v) => assert!(
3264                    v == structured,
3265                    "for {string:?}, expected {structured:?} but got {v:?}",
3266                    structured = structured.as_bloated_debug(),
3267                    v = v.as_bloated_debug(),
3268                ),
3269            }
3270            let spec = format!("=={string}");
3271            match VersionSpecifier::from_str(&spec) {
3272                Err(err) => {
3273                    unreachable!(
3274                        "expected version in {spec:?} to parse as {structured:?}, but got {err:?}",
3275                        structured = structured.as_bloated_debug(),
3276                    )
3277                }
3278                Ok(v) => assert!(
3279                    v.version() == &structured,
3280                    "for {string:?}, expected {structured:?} but got {v:?}",
3281                    structured = structured.as_bloated_debug(),
3282                    v = v.version.as_bloated_debug(),
3283                ),
3284            }
3285        }
3286    }
3287
3288    /// <https://github.com/pypa/packaging/blob/237ff3aa348486cf835a980592af3a59fccd6101/tests/test_version.py#L91-L100>
3289    #[test]
3290    fn test_packaging_failures() {
3291        let versions = [
3292            // Versions with invalid local versions
3293            "1.0+a+",
3294            "1.0++",
3295            "1.0+_foobar",
3296            "1.0+foo&asd",
3297            "1.0+1+1",
3298            // Nonsensical versions should also be invalid
3299            "french toast",
3300            "==french toast",
3301        ];
3302        for version in versions {
3303            assert!(Version::from_str(version).is_err());
3304            assert!(VersionSpecifier::from_str(&format!("=={version}")).is_err());
3305        }
3306    }
3307
3308    #[test]
3309    fn test_equality_and_normalization() {
3310        let versions = [
3311            // Various development release incarnations
3312            ("1.0dev", "1.0.dev0"),
3313            ("1.0.dev", "1.0.dev0"),
3314            ("1.0dev1", "1.0.dev1"),
3315            ("1.0dev", "1.0.dev0"),
3316            ("1.0-dev", "1.0.dev0"),
3317            ("1.0-dev1", "1.0.dev1"),
3318            ("1.0DEV", "1.0.dev0"),
3319            ("1.0.DEV", "1.0.dev0"),
3320            ("1.0DEV1", "1.0.dev1"),
3321            ("1.0DEV", "1.0.dev0"),
3322            ("1.0.DEV1", "1.0.dev1"),
3323            ("1.0-DEV", "1.0.dev0"),
3324            ("1.0-DEV1", "1.0.dev1"),
3325            // Various alpha incarnations
3326            ("1.0a", "1.0a0"),
3327            ("1.0.a", "1.0a0"),
3328            ("1.0.a1", "1.0a1"),
3329            ("1.0-a", "1.0a0"),
3330            ("1.0-a1", "1.0a1"),
3331            ("1.0alpha", "1.0a0"),
3332            ("1.0.alpha", "1.0a0"),
3333            ("1.0.alpha1", "1.0a1"),
3334            ("1.0-alpha", "1.0a0"),
3335            ("1.0-alpha1", "1.0a1"),
3336            ("1.0A", "1.0a0"),
3337            ("1.0.A", "1.0a0"),
3338            ("1.0.A1", "1.0a1"),
3339            ("1.0-A", "1.0a0"),
3340            ("1.0-A1", "1.0a1"),
3341            ("1.0ALPHA", "1.0a0"),
3342            ("1.0.ALPHA", "1.0a0"),
3343            ("1.0.ALPHA1", "1.0a1"),
3344            ("1.0-ALPHA", "1.0a0"),
3345            ("1.0-ALPHA1", "1.0a1"),
3346            // Various beta incarnations
3347            ("1.0b", "1.0b0"),
3348            ("1.0.b", "1.0b0"),
3349            ("1.0.b1", "1.0b1"),
3350            ("1.0-b", "1.0b0"),
3351            ("1.0-b1", "1.0b1"),
3352            ("1.0beta", "1.0b0"),
3353            ("1.0.beta", "1.0b0"),
3354            ("1.0.beta1", "1.0b1"),
3355            ("1.0-beta", "1.0b0"),
3356            ("1.0-beta1", "1.0b1"),
3357            ("1.0B", "1.0b0"),
3358            ("1.0.B", "1.0b0"),
3359            ("1.0.B1", "1.0b1"),
3360            ("1.0-B", "1.0b0"),
3361            ("1.0-B1", "1.0b1"),
3362            ("1.0BETA", "1.0b0"),
3363            ("1.0.BETA", "1.0b0"),
3364            ("1.0.BETA1", "1.0b1"),
3365            ("1.0-BETA", "1.0b0"),
3366            ("1.0-BETA1", "1.0b1"),
3367            // Various release candidate incarnations
3368            ("1.0c", "1.0rc0"),
3369            ("1.0.c", "1.0rc0"),
3370            ("1.0.c1", "1.0rc1"),
3371            ("1.0-c", "1.0rc0"),
3372            ("1.0-c1", "1.0rc1"),
3373            ("1.0rc", "1.0rc0"),
3374            ("1.0.rc", "1.0rc0"),
3375            ("1.0.rc1", "1.0rc1"),
3376            ("1.0-rc", "1.0rc0"),
3377            ("1.0-rc1", "1.0rc1"),
3378            ("1.0C", "1.0rc0"),
3379            ("1.0.C", "1.0rc0"),
3380            ("1.0.C1", "1.0rc1"),
3381            ("1.0-C", "1.0rc0"),
3382            ("1.0-C1", "1.0rc1"),
3383            ("1.0RC", "1.0rc0"),
3384            ("1.0.RC", "1.0rc0"),
3385            ("1.0.RC1", "1.0rc1"),
3386            ("1.0-RC", "1.0rc0"),
3387            ("1.0-RC1", "1.0rc1"),
3388            // Various post release incarnations
3389            ("1.0post", "1.0.post0"),
3390            ("1.0.post", "1.0.post0"),
3391            ("1.0post1", "1.0.post1"),
3392            ("1.0post", "1.0.post0"),
3393            ("1.0-post", "1.0.post0"),
3394            ("1.0-post1", "1.0.post1"),
3395            ("1.0POST", "1.0.post0"),
3396            ("1.0.POST", "1.0.post0"),
3397            ("1.0POST1", "1.0.post1"),
3398            ("1.0POST", "1.0.post0"),
3399            ("1.0r", "1.0.post0"),
3400            ("1.0rev", "1.0.post0"),
3401            ("1.0.POST1", "1.0.post1"),
3402            ("1.0.r1", "1.0.post1"),
3403            ("1.0.rev1", "1.0.post1"),
3404            ("1.0-POST", "1.0.post0"),
3405            ("1.0-POST1", "1.0.post1"),
3406            ("1.0-5", "1.0.post5"),
3407            ("1.0-r5", "1.0.post5"),
3408            ("1.0-rev5", "1.0.post5"),
3409            // Local version case insensitivity
3410            ("1.0+AbC", "1.0+abc"),
3411            // Integer Normalization
3412            ("1.01", "1.1"),
3413            ("1.0a05", "1.0a5"),
3414            ("1.0b07", "1.0b7"),
3415            ("1.0c056", "1.0rc56"),
3416            ("1.0rc09", "1.0rc9"),
3417            ("1.0.post000", "1.0.post0"),
3418            ("1.1.dev09000", "1.1.dev9000"),
3419            ("00!1.2", "1.2"),
3420            ("0100!0.0", "100!0.0"),
3421            // Various other normalizations
3422            ("v1.0", "1.0"),
3423            ("   v1.0\t\n", "1.0"),
3424        ];
3425        for (version_str, normalized_str) in versions {
3426            let version = Version::from_str(version_str).unwrap();
3427            let normalized = Version::from_str(normalized_str).unwrap();
3428            // Just test version parsing again
3429            assert_eq!(version, normalized, "{version_str} {normalized_str}");
3430            // Test version normalization
3431            assert_eq!(
3432                version.to_string(),
3433                normalized.to_string(),
3434                "{version_str} {normalized_str}"
3435            );
3436        }
3437    }
3438
3439    /// <https://github.com/pypa/packaging/blob/237ff3aa348486cf835a980592af3a59fccd6101/tests/test_version.py#L229-L277>
3440    #[test]
3441    fn test_equality_and_normalization2() {
3442        let versions = [
3443            ("1.0.dev456", "1.0.dev456"),
3444            ("1.0a1", "1.0a1"),
3445            ("1.0a2.dev456", "1.0a2.dev456"),
3446            ("1.0a12.dev456", "1.0a12.dev456"),
3447            ("1.0a12", "1.0a12"),
3448            ("1.0b1.dev456", "1.0b1.dev456"),
3449            ("1.0b2", "1.0b2"),
3450            ("1.0b2.post345.dev456", "1.0b2.post345.dev456"),
3451            ("1.0b2.post345", "1.0b2.post345"),
3452            ("1.0rc1.dev456", "1.0rc1.dev456"),
3453            ("1.0rc1", "1.0rc1"),
3454            ("1.0", "1.0"),
3455            ("1.0.post456.dev34", "1.0.post456.dev34"),
3456            ("1.0.post456", "1.0.post456"),
3457            ("1.0.1", "1.0.1"),
3458            ("0!1.0.2", "1.0.2"),
3459            ("1.0.3+7", "1.0.3+7"),
3460            ("0!1.0.4+8.0", "1.0.4+8.0"),
3461            ("1.0.5+9.5", "1.0.5+9.5"),
3462            ("1.2+1234.abc", "1.2+1234.abc"),
3463            ("1.2+123456", "1.2+123456"),
3464            ("1.2+123abc", "1.2+123abc"),
3465            ("1.2+123abc456", "1.2+123abc456"),
3466            ("1.2+abc", "1.2+abc"),
3467            ("1.2+abc123", "1.2+abc123"),
3468            ("1.2+abc123def", "1.2+abc123def"),
3469            ("1.1.dev1", "1.1.dev1"),
3470            ("7!1.0.dev456", "7!1.0.dev456"),
3471            ("7!1.0a1", "7!1.0a1"),
3472            ("7!1.0a2.dev456", "7!1.0a2.dev456"),
3473            ("7!1.0a12.dev456", "7!1.0a12.dev456"),
3474            ("7!1.0a12", "7!1.0a12"),
3475            ("7!1.0b1.dev456", "7!1.0b1.dev456"),
3476            ("7!1.0b2", "7!1.0b2"),
3477            ("7!1.0b2.post345.dev456", "7!1.0b2.post345.dev456"),
3478            ("7!1.0b2.post345", "7!1.0b2.post345"),
3479            ("7!1.0rc1.dev456", "7!1.0rc1.dev456"),
3480            ("7!1.0rc1", "7!1.0rc1"),
3481            ("7!1.0", "7!1.0"),
3482            ("7!1.0.post456.dev34", "7!1.0.post456.dev34"),
3483            ("7!1.0.post456", "7!1.0.post456"),
3484            ("7!1.0.1", "7!1.0.1"),
3485            ("7!1.0.2", "7!1.0.2"),
3486            ("7!1.0.3+7", "7!1.0.3+7"),
3487            ("7!1.0.4+8.0", "7!1.0.4+8.0"),
3488            ("7!1.0.5+9.5", "7!1.0.5+9.5"),
3489            ("7!1.1.dev1", "7!1.1.dev1"),
3490        ];
3491        for (version_str, normalized_str) in versions {
3492            let version = Version::from_str(version_str).unwrap();
3493            let normalized = Version::from_str(normalized_str).unwrap();
3494            assert_eq!(version, normalized, "{version_str} {normalized_str}");
3495            // Test version normalization
3496            assert_eq!(
3497                version.to_string(),
3498                normalized_str,
3499                "{version_str} {normalized_str}"
3500            );
3501            // Since we're already at it
3502            assert_eq!(
3503                version.to_string(),
3504                normalized.to_string(),
3505                "{version_str} {normalized_str}"
3506            );
3507        }
3508    }
3509
3510    #[test]
3511    fn test_star_fixed_version() {
3512        let result = Version::from_str("0.9.1.*");
3513        assert_eq!(result.unwrap_err(), ErrorKind::Wildcard.into());
3514    }
3515
3516    #[test]
3517    fn test_invalid_word() {
3518        let result = Version::from_str("blergh");
3519        assert_eq!(result.unwrap_err(), ErrorKind::NoLeadingNumber.into());
3520    }
3521
3522    #[test]
3523    fn test_from_version_star() {
3524        let p = |s: &str| -> Result<VersionPattern, _> { s.parse() };
3525        assert!(!p("1.2.3").unwrap().is_wildcard());
3526        assert!(p("1.2.3.*").unwrap().is_wildcard());
3527        assert_eq!(
3528            p("1.2.*.4.*").unwrap_err(),
3529            PatternErrorKind::WildcardNotTrailing.into(),
3530        );
3531        assert_eq!(
3532            p("1.0-dev1.*").unwrap_err(),
3533            ErrorKind::UnexpectedEnd {
3534                version: "1.0-dev1".to_string(),
3535                remaining: ".*".to_string()
3536            }
3537            .into(),
3538        );
3539        assert_eq!(
3540            p("1.0a1.*").unwrap_err(),
3541            ErrorKind::UnexpectedEnd {
3542                version: "1.0a1".to_string(),
3543                remaining: ".*".to_string()
3544            }
3545            .into(),
3546        );
3547        assert_eq!(
3548            p("1.0.post1.*").unwrap_err(),
3549            ErrorKind::UnexpectedEnd {
3550                version: "1.0.post1".to_string(),
3551                remaining: ".*".to_string()
3552            }
3553            .into(),
3554        );
3555        assert_eq!(
3556            p("1.0+lolwat.*").unwrap_err(),
3557            ErrorKind::LocalEmpty { precursor: '.' }.into(),
3558        );
3559    }
3560
3561    // Tests the valid cases of our version parser. These were written
3562    // in tandem with the parser.
3563    //
3564    // They are meant to be additional (but in some cases likely redundant)
3565    // with some of the above tests.
3566    #[test]
3567    fn parse_version_valid() {
3568        let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3569            Ok(v) => v,
3570            Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3571        };
3572
3573        // release-only tests
3574        assert_eq!(p("5"), Version::new([5]));
3575        assert_eq!(p("5.6"), Version::new([5, 6]));
3576        assert_eq!(p("5.6.7"), Version::new([5, 6, 7]));
3577        assert_eq!(p("512.623.734"), Version::new([512, 623, 734]));
3578        assert_eq!(p("1.2.3.4"), Version::new([1, 2, 3, 4]));
3579        assert_eq!(p("1.2.3.4.5"), Version::new([1, 2, 3, 4, 5]));
3580
3581        // epoch tests
3582        assert_eq!(p("4!5"), Version::new([5]).with_epoch(4));
3583        assert_eq!(p("4!5.6"), Version::new([5, 6]).with_epoch(4));
3584
3585        // pre-release tests
3586        assert_eq!(
3587            p("5a1"),
3588            Version::new([5]).with_pre(Some(Prerelease {
3589                kind: PrereleaseKind::Alpha,
3590                number: 1
3591            }))
3592        );
3593        assert_eq!(
3594            p("5alpha1"),
3595            Version::new([5]).with_pre(Some(Prerelease {
3596                kind: PrereleaseKind::Alpha,
3597                number: 1
3598            }))
3599        );
3600        assert_eq!(
3601            p("5b1"),
3602            Version::new([5]).with_pre(Some(Prerelease {
3603                kind: PrereleaseKind::Beta,
3604                number: 1
3605            }))
3606        );
3607        assert_eq!(
3608            p("5beta1"),
3609            Version::new([5]).with_pre(Some(Prerelease {
3610                kind: PrereleaseKind::Beta,
3611                number: 1
3612            }))
3613        );
3614        assert_eq!(
3615            p("5rc1"),
3616            Version::new([5]).with_pre(Some(Prerelease {
3617                kind: PrereleaseKind::Rc,
3618                number: 1
3619            }))
3620        );
3621        assert_eq!(
3622            p("5c1"),
3623            Version::new([5]).with_pre(Some(Prerelease {
3624                kind: PrereleaseKind::Rc,
3625                number: 1
3626            }))
3627        );
3628        assert_eq!(
3629            p("5preview1"),
3630            Version::new([5]).with_pre(Some(Prerelease {
3631                kind: PrereleaseKind::Rc,
3632                number: 1
3633            }))
3634        );
3635        assert_eq!(
3636            p("5pre1"),
3637            Version::new([5]).with_pre(Some(Prerelease {
3638                kind: PrereleaseKind::Rc,
3639                number: 1
3640            }))
3641        );
3642        assert_eq!(
3643            p("5.6.7pre1"),
3644            Version::new([5, 6, 7]).with_pre(Some(Prerelease {
3645                kind: PrereleaseKind::Rc,
3646                number: 1
3647            }))
3648        );
3649        assert_eq!(
3650            p("5alpha789"),
3651            Version::new([5]).with_pre(Some(Prerelease {
3652                kind: PrereleaseKind::Alpha,
3653                number: 789
3654            }))
3655        );
3656        assert_eq!(
3657            p("5.alpha789"),
3658            Version::new([5]).with_pre(Some(Prerelease {
3659                kind: PrereleaseKind::Alpha,
3660                number: 789
3661            }))
3662        );
3663        assert_eq!(
3664            p("5-alpha789"),
3665            Version::new([5]).with_pre(Some(Prerelease {
3666                kind: PrereleaseKind::Alpha,
3667                number: 789
3668            }))
3669        );
3670        assert_eq!(
3671            p("5_alpha789"),
3672            Version::new([5]).with_pre(Some(Prerelease {
3673                kind: PrereleaseKind::Alpha,
3674                number: 789
3675            }))
3676        );
3677        assert_eq!(
3678            p("5alpha.789"),
3679            Version::new([5]).with_pre(Some(Prerelease {
3680                kind: PrereleaseKind::Alpha,
3681                number: 789
3682            }))
3683        );
3684        assert_eq!(
3685            p("5alpha-789"),
3686            Version::new([5]).with_pre(Some(Prerelease {
3687                kind: PrereleaseKind::Alpha,
3688                number: 789
3689            }))
3690        );
3691        assert_eq!(
3692            p("5alpha_789"),
3693            Version::new([5]).with_pre(Some(Prerelease {
3694                kind: PrereleaseKind::Alpha,
3695                number: 789
3696            }))
3697        );
3698        assert_eq!(
3699            p("5ALPHA789"),
3700            Version::new([5]).with_pre(Some(Prerelease {
3701                kind: PrereleaseKind::Alpha,
3702                number: 789
3703            }))
3704        );
3705        assert_eq!(
3706            p("5aLpHa789"),
3707            Version::new([5]).with_pre(Some(Prerelease {
3708                kind: PrereleaseKind::Alpha,
3709                number: 789
3710            }))
3711        );
3712        assert_eq!(
3713            p("5alpha"),
3714            Version::new([5]).with_pre(Some(Prerelease {
3715                kind: PrereleaseKind::Alpha,
3716                number: 0
3717            }))
3718        );
3719
3720        // post-release tests
3721        assert_eq!(p("5post2"), Version::new([5]).with_post(Some(2)));
3722        assert_eq!(p("5rev2"), Version::new([5]).with_post(Some(2)));
3723        assert_eq!(p("5r2"), Version::new([5]).with_post(Some(2)));
3724        assert_eq!(p("5.post2"), Version::new([5]).with_post(Some(2)));
3725        assert_eq!(p("5-post2"), Version::new([5]).with_post(Some(2)));
3726        assert_eq!(p("5_post2"), Version::new([5]).with_post(Some(2)));
3727        assert_eq!(p("5.post.2"), Version::new([5]).with_post(Some(2)));
3728        assert_eq!(p("5.post-2"), Version::new([5]).with_post(Some(2)));
3729        assert_eq!(p("5.post_2"), Version::new([5]).with_post(Some(2)));
3730        assert_eq!(
3731            p("5.6.7.post_2"),
3732            Version::new([5, 6, 7]).with_post(Some(2))
3733        );
3734        assert_eq!(p("5-2"), Version::new([5]).with_post(Some(2)));
3735        assert_eq!(p("5.6.7-2"), Version::new([5, 6, 7]).with_post(Some(2)));
3736        assert_eq!(p("5POST2"), Version::new([5]).with_post(Some(2)));
3737        assert_eq!(p("5PoSt2"), Version::new([5]).with_post(Some(2)));
3738        assert_eq!(p("5post"), Version::new([5]).with_post(Some(0)));
3739
3740        // dev-release tests
3741        assert_eq!(p("5dev2"), Version::new([5]).with_dev(Some(2)));
3742        assert_eq!(p("5.dev2"), Version::new([5]).with_dev(Some(2)));
3743        assert_eq!(p("5-dev2"), Version::new([5]).with_dev(Some(2)));
3744        assert_eq!(p("5_dev2"), Version::new([5]).with_dev(Some(2)));
3745        assert_eq!(p("5.dev.2"), Version::new([5]).with_dev(Some(2)));
3746        assert_eq!(p("5.dev-2"), Version::new([5]).with_dev(Some(2)));
3747        assert_eq!(p("5.dev_2"), Version::new([5]).with_dev(Some(2)));
3748        assert_eq!(p("5.6.7.dev_2"), Version::new([5, 6, 7]).with_dev(Some(2)));
3749        assert_eq!(p("5DEV2"), Version::new([5]).with_dev(Some(2)));
3750        assert_eq!(p("5dEv2"), Version::new([5]).with_dev(Some(2)));
3751        assert_eq!(p("5DeV2"), Version::new([5]).with_dev(Some(2)));
3752        assert_eq!(p("5dev"), Version::new([5]).with_dev(Some(0)));
3753
3754        // local tests
3755        assert_eq!(
3756            p("5+2"),
3757            Version::new([5]).with_local_segments(vec![LocalSegment::Number(2)])
3758        );
3759        assert_eq!(
3760            p("5+a"),
3761            Version::new([5]).with_local_segments(vec![LocalSegment::String("a".to_string())])
3762        );
3763        assert_eq!(
3764            p("5+abc.123"),
3765            Version::new([5]).with_local_segments(vec![
3766                LocalSegment::String("abc".to_string()),
3767                LocalSegment::Number(123),
3768            ])
3769        );
3770        assert_eq!(
3771            p("5+123.abc"),
3772            Version::new([5]).with_local_segments(vec![
3773                LocalSegment::Number(123),
3774                LocalSegment::String("abc".to_string()),
3775            ])
3776        );
3777        assert_eq!(
3778            p("5+18446744073709551615.abc"),
3779            Version::new([5]).with_local_segments(vec![
3780                LocalSegment::Number(18_446_744_073_709_551_615),
3781                LocalSegment::String("abc".to_string()),
3782            ])
3783        );
3784        assert_eq!(
3785            p("5+18446744073709551616.abc"),
3786            Version::new([5]).with_local_segments(vec![
3787                LocalSegment::String("18446744073709551616".to_string()),
3788                LocalSegment::String("abc".to_string()),
3789            ])
3790        );
3791        assert_eq!(
3792            p("5+ABC.123"),
3793            Version::new([5]).with_local_segments(vec![
3794                LocalSegment::String("abc".to_string()),
3795                LocalSegment::Number(123),
3796            ])
3797        );
3798        assert_eq!(
3799            p("5+ABC-123.4_5_xyz-MNO"),
3800            Version::new([5]).with_local_segments(vec![
3801                LocalSegment::String("abc".to_string()),
3802                LocalSegment::Number(123),
3803                LocalSegment::Number(4),
3804                LocalSegment::Number(5),
3805                LocalSegment::String("xyz".to_string()),
3806                LocalSegment::String("mno".to_string()),
3807            ])
3808        );
3809        assert_eq!(
3810            p("5.6.7+abc-00123"),
3811            Version::new([5, 6, 7]).with_local_segments(vec![
3812                LocalSegment::String("abc".to_string()),
3813                LocalSegment::Number(123),
3814            ])
3815        );
3816        assert_eq!(
3817            p("5.6.7+abc-foo00123"),
3818            Version::new([5, 6, 7]).with_local_segments(vec![
3819                LocalSegment::String("abc".to_string()),
3820                LocalSegment::String("foo00123".to_string()),
3821            ])
3822        );
3823        assert_eq!(
3824            p("5.6.7+abc-00123a"),
3825            Version::new([5, 6, 7]).with_local_segments(vec![
3826                LocalSegment::String("abc".to_string()),
3827                LocalSegment::String("00123a".to_string()),
3828            ])
3829        );
3830
3831        // {pre-release, post-release} tests
3832        assert_eq!(
3833            p("5a2post3"),
3834            Version::new([5])
3835                .with_pre(Some(Prerelease {
3836                    kind: PrereleaseKind::Alpha,
3837                    number: 2
3838                }))
3839                .with_post(Some(3))
3840        );
3841        assert_eq!(
3842            p("5.a-2_post-3"),
3843            Version::new([5])
3844                .with_pre(Some(Prerelease {
3845                    kind: PrereleaseKind::Alpha,
3846                    number: 2
3847                }))
3848                .with_post(Some(3))
3849        );
3850        assert_eq!(
3851            p("5a2-3"),
3852            Version::new([5])
3853                .with_pre(Some(Prerelease {
3854                    kind: PrereleaseKind::Alpha,
3855                    number: 2
3856                }))
3857                .with_post(Some(3))
3858        );
3859
3860        // Ignoring a no-op 'v' prefix.
3861        assert_eq!(p("v5"), Version::new([5]));
3862        assert_eq!(p("V5"), Version::new([5]));
3863        assert_eq!(p("v5.6.7"), Version::new([5, 6, 7]));
3864
3865        // Ignoring leading and trailing whitespace.
3866        assert_eq!(p("  v5  "), Version::new([5]));
3867        assert_eq!(p("  5  "), Version::new([5]));
3868        assert_eq!(
3869            p("  5.6.7+abc.123.xyz  "),
3870            Version::new([5, 6, 7]).with_local_segments(vec![
3871                LocalSegment::String("abc".to_string()),
3872                LocalSegment::Number(123),
3873                LocalSegment::String("xyz".to_string())
3874            ])
3875        );
3876        assert_eq!(p("  \n5\n \t"), Version::new([5]));
3877
3878        // min tests
3879        assert!(Parser::new("1.min0".as_bytes()).parse().is_err());
3880    }
3881
3882    // Tests the error cases of our version parser.
3883    //
3884    // I wrote these with the intent to cover every possible error
3885    // case.
3886    //
3887    // They are meant to be additional (but in some cases likely redundant)
3888    // with some of the above tests.
3889    #[test]
3890    fn parse_version_invalid() {
3891        let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3892            Err(err) => err,
3893            Ok(v) => unreachable!(
3894                "expected version parser error, but got: {v:?}",
3895                v = v.as_bloated_debug()
3896            ),
3897        };
3898
3899        assert_eq!(p(""), ErrorKind::NoLeadingNumber.into());
3900        assert_eq!(p("a"), ErrorKind::NoLeadingNumber.into());
3901        assert_eq!(p("v 5"), ErrorKind::NoLeadingNumber.into());
3902        assert_eq!(p("V 5"), ErrorKind::NoLeadingNumber.into());
3903        assert_eq!(p("x 5"), ErrorKind::NoLeadingNumber.into());
3904        assert_eq!(
3905            p("18446744073709551616"),
3906            ErrorKind::NumberTooBig {
3907                bytes: b"18446744073709551616".to_vec()
3908            }
3909            .into()
3910        );
3911        assert_eq!(p("5!"), ErrorKind::NoLeadingReleaseNumber.into());
3912        assert_eq!(
3913            p("5.6./"),
3914            ErrorKind::UnexpectedEnd {
3915                version: "5.6".to_string(),
3916                remaining: "./".to_string()
3917            }
3918            .into()
3919        );
3920        assert_eq!(
3921            p("5.6.-alpha2"),
3922            ErrorKind::UnexpectedEnd {
3923                version: "5.6".to_string(),
3924                remaining: ".-alpha2".to_string()
3925            }
3926            .into()
3927        );
3928        assert_eq!(
3929            p("1.2.3a18446744073709551616"),
3930            ErrorKind::NumberTooBig {
3931                bytes: b"18446744073709551616".to_vec()
3932            }
3933            .into()
3934        );
3935        assert_eq!(p("5+"), ErrorKind::LocalEmpty { precursor: '+' }.into());
3936        assert_eq!(p("5+ "), ErrorKind::LocalEmpty { precursor: '+' }.into());
3937        assert_eq!(p("5+abc."), ErrorKind::LocalEmpty { precursor: '.' }.into());
3938        assert_eq!(p("5+abc-"), ErrorKind::LocalEmpty { precursor: '-' }.into());
3939        assert_eq!(p("5+abc_"), ErrorKind::LocalEmpty { precursor: '_' }.into());
3940        assert_eq!(
3941            p("5+abc. "),
3942            ErrorKind::LocalEmpty { precursor: '.' }.into()
3943        );
3944        assert_eq!(
3945            p("5.6-"),
3946            ErrorKind::UnexpectedEnd {
3947                version: "5.6".to_string(),
3948                remaining: "-".to_string()
3949            }
3950            .into()
3951        );
3952    }
3953
3954    #[test]
3955    fn parse_version_pattern_valid() {
3956        let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3957            Ok(v) => v,
3958            Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3959        };
3960
3961        assert_eq!(p("5.*"), VersionPattern::wildcard(Version::new([5])));
3962        assert_eq!(p("5.6.*"), VersionPattern::wildcard(Version::new([5, 6])));
3963        assert_eq!(
3964            p("2!5.6.*"),
3965            VersionPattern::wildcard(Version::new([5, 6]).with_epoch(2))
3966        );
3967    }
3968
3969    #[test]
3970    fn parse_version_pattern_invalid() {
3971        let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3972            Err(err) => err,
3973            Ok(vpat) => unreachable!("expected version pattern parser error, but got: {vpat:?}"),
3974        };
3975
3976        assert_eq!(p("*"), ErrorKind::NoLeadingNumber.into());
3977        assert_eq!(p("2!*"), ErrorKind::NoLeadingReleaseNumber.into());
3978    }
3979
3980    // Tests that the ordering between versions is correct.
3981    //
3982    // The ordering example used here was taken from PEP 440:
3983    // https://packaging.python.org/en/latest/specifications/version-specifiers/#summary-of-permitted-suffixes-and-relative-ordering
3984    #[test]
3985    fn ordering() {
3986        let versions = &[
3987            "1.dev0",
3988            "1.0.dev456",
3989            "1.0a1",
3990            "1.0a2.dev456",
3991            "1.0a12.dev456",
3992            "1.0a12",
3993            "1.0b1.dev456",
3994            "1.0b2",
3995            "1.0b2.post345.dev456",
3996            "1.0b2.post345",
3997            "1.0rc1.dev456",
3998            "1.0rc1",
3999            "1.0",
4000            "1.0+abc.5",
4001            "1.0+abc.7",
4002            "1.0+5",
4003            "1.0.post456.dev34",
4004            "1.0.post456",
4005            "1.0.15",
4006            "1.1.dev1",
4007        ];
4008        for (i, v1) in versions.iter().enumerate() {
4009            for v2 in &versions[i + 1..] {
4010                let less = v1.parse::<Version>().unwrap();
4011                let greater = v2.parse::<Version>().unwrap();
4012                assert_eq!(
4013                    less.cmp(&greater),
4014                    Ordering::Less,
4015                    "less: {:?}\ngreater: {:?}",
4016                    less.as_bloated_debug(),
4017                    greater.as_bloated_debug()
4018                );
4019            }
4020        }
4021    }
4022
4023    #[test]
4024    fn local_sentinel_version() {
4025        let sentinel = Version::new([1, 0]).with_local(LocalVersion::Max);
4026
4027        // Ensure that the "max local version" sentinel is less than the following versions.
4028        let versions = &["1.0.post0", "1.1"];
4029
4030        for greater in versions {
4031            let greater = greater.parse::<Version>().unwrap();
4032            assert_eq!(
4033                sentinel.cmp(&greater),
4034                Ordering::Less,
4035                "less: {:?}\ngreater: {:?}",
4036                greater.as_bloated_debug(),
4037                sentinel.as_bloated_debug(),
4038            );
4039        }
4040
4041        // Ensure that the "max local version" sentinel is greater than the following versions.
4042        let versions = &["1.0", "1.0.a0", "1.0+local"];
4043
4044        for less in versions {
4045            let less = less.parse::<Version>().unwrap();
4046            assert_eq!(
4047                sentinel.cmp(&less),
4048                Ordering::Greater,
4049                "less: {:?}\ngreater: {:?}",
4050                sentinel.as_bloated_debug(),
4051                less.as_bloated_debug()
4052            );
4053        }
4054    }
4055
4056    #[test]
4057    fn min_version() {
4058        // Ensure that the `.min` suffix precedes all other suffixes.
4059        let less = Version::new([1, 0]).with_min(Some(0));
4060
4061        let versions = &[
4062            "1.dev0",
4063            "1.0.dev456",
4064            "1.0a1",
4065            "1.0a2.dev456",
4066            "1.0a12.dev456",
4067            "1.0a12",
4068            "1.0b1.dev456",
4069            "1.0b2",
4070            "1.0b2.post345.dev456",
4071            "1.0b2.post345",
4072            "1.0rc1.dev456",
4073            "1.0rc1",
4074            "1.0",
4075            "1.0+abc.5",
4076            "1.0+abc.7",
4077            "1.0+5",
4078            "1.0.post456.dev34",
4079            "1.0.post456",
4080            "1.0.15",
4081            "1.1.dev1",
4082        ];
4083
4084        for greater in versions {
4085            let greater = greater.parse::<Version>().unwrap();
4086            assert_eq!(
4087                less.cmp(&greater),
4088                Ordering::Less,
4089                "less: {:?}\ngreater: {:?}",
4090                less.as_bloated_debug(),
4091                greater.as_bloated_debug()
4092            );
4093        }
4094    }
4095
4096    #[test]
4097    fn max_version() {
4098        // Ensure that the `.max` suffix succeeds all other suffixes.
4099        let greater = Version::new([1, 0]).with_max(Some(0));
4100
4101        let versions = &[
4102            "1.dev0",
4103            "1.0.dev456",
4104            "1.0a1",
4105            "1.0a2.dev456",
4106            "1.0a12.dev456",
4107            "1.0a12",
4108            "1.0b1.dev456",
4109            "1.0b2",
4110            "1.0b2.post345.dev456",
4111            "1.0b2.post345",
4112            "1.0rc1.dev456",
4113            "1.0rc1",
4114            "1.0",
4115            "1.0+abc.5",
4116            "1.0+abc.7",
4117            "1.0+5",
4118            "1.0.post456.dev34",
4119            "1.0.post456",
4120            "1.0",
4121        ];
4122
4123        for less in versions {
4124            let less = less.parse::<Version>().unwrap();
4125            assert_eq!(
4126                less.cmp(&greater),
4127                Ordering::Less,
4128                "less: {:?}\ngreater: {:?}",
4129                less.as_bloated_debug(),
4130                greater.as_bloated_debug()
4131            );
4132        }
4133
4134        // Ensure that the `.max` suffix plays nicely with pre-release versions.
4135        let greater = Version::new([1, 0])
4136            .with_pre(Some(Prerelease {
4137                kind: PrereleaseKind::Alpha,
4138                number: 1,
4139            }))
4140            .with_max(Some(0));
4141
4142        let versions = &["1.0a1", "1.0a1+local", "1.0a1.post1"];
4143
4144        for less in versions {
4145            let less = less.parse::<Version>().unwrap();
4146            assert_eq!(
4147                less.cmp(&greater),
4148                Ordering::Less,
4149                "less: {:?}\ngreater: {:?}",
4150                less.as_bloated_debug(),
4151                greater.as_bloated_debug()
4152            );
4153        }
4154
4155        // Ensure that the `.max` suffix plays nicely with pre-release versions.
4156        let less = Version::new([1, 0])
4157            .with_pre(Some(Prerelease {
4158                kind: PrereleaseKind::Alpha,
4159                number: 1,
4160            }))
4161            .with_max(Some(0));
4162
4163        let versions = &["1.0b1", "1.0b1+local", "1.0b1.post1", "1.0"];
4164
4165        for greater in versions {
4166            let greater = greater.parse::<Version>().unwrap();
4167            assert_eq!(
4168                less.cmp(&greater),
4169                Ordering::Less,
4170                "less: {:?}\ngreater: {:?}",
4171                less.as_bloated_debug(),
4172                greater.as_bloated_debug()
4173            );
4174        }
4175    }
4176
4177    // Tests our bespoke u64 decimal integer parser.
4178    #[test]
4179    fn parse_number_u64() {
4180        let p = |s: &str| parse_u64(s.as_bytes());
4181        assert_eq!(p("0"), Ok(0));
4182        assert_eq!(p("00"), Ok(0));
4183        assert_eq!(p("1"), Ok(1));
4184        assert_eq!(p("01"), Ok(1));
4185        assert_eq!(p("9"), Ok(9));
4186        assert_eq!(p("10"), Ok(10));
4187        assert_eq!(p("18446744073709551615"), Ok(18_446_744_073_709_551_615));
4188        assert_eq!(p("018446744073709551615"), Ok(18_446_744_073_709_551_615));
4189        assert_eq!(
4190            p("000000018446744073709551615"),
4191            Ok(18_446_744_073_709_551_615)
4192        );
4193
4194        assert_eq!(p("10a"), Err(ErrorKind::InvalidDigit { got: b'a' }.into()));
4195        assert_eq!(p("10["), Err(ErrorKind::InvalidDigit { got: b'[' }.into()));
4196        assert_eq!(p("10/"), Err(ErrorKind::InvalidDigit { got: b'/' }.into()));
4197        // u64::MAX + 1 is rejected (overflow during parsing).
4198        assert_eq!(
4199            p("18446744073709551616"),
4200            Err(ErrorKind::NumberTooBig {
4201                bytes: b"18446744073709551616".to_vec()
4202            }
4203            .into())
4204        );
4205        assert_eq!(
4206            p("18446744073799551615abc"),
4207            Err(ErrorKind::NumberTooBig {
4208                bytes: b"18446744073799551615abc".to_vec()
4209            }
4210            .into())
4211        );
4212        assert_eq!(
4213            parse_u64(b"18446744073799551615\xFF"),
4214            Err(ErrorKind::NumberTooBig {
4215                bytes: b"18446744073799551615\xFF".to_vec()
4216            }
4217            .into())
4218        );
4219    }
4220
4221    impl Version {
4222        /// Returns a more "bloated" debug representation of this [`Version`].
4223        ///
4224        /// We don't do this by default because it takes up a ton of space, and
4225        /// just printing out the display version of the version is quite a bit
4226        /// simpler.
4227        ///
4228        /// Nevertheless, when *testing* version parsing, you really want to
4229        /// be able to peek at all of its constituent parts. So we use this in
4230        /// assertion failure messages.
4231        pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4232            std::fmt::from_fn(|f| {
4233                f.debug_struct("Version")
4234                    .field("epoch", &self.epoch())
4235                    .field("release", &&*self.release())
4236                    .field("pre", &self.pre())
4237                    .field("post", &self.post())
4238                    .field("dev", &self.dev())
4239                    .field("local", &self.local())
4240                    .field("min", &self.min())
4241                    .field("max", &self.max())
4242                    .finish()
4243            })
4244        }
4245    }
4246
4247    /// This explicitly tests that we preserve trailing zeros in a version
4248    /// string. i.e., Both `1.2` and `1.2.0` round-trip, with the former
4249    /// lacking a trailing zero and the latter including it.
4250    #[test]
4251    fn preserve_trailing_zeros() {
4252        let v1: Version = "1.2.0".parse().unwrap();
4253        assert_eq!(&*v1.release(), &[1, 2, 0]);
4254        assert_eq!(v1.to_string(), "1.2.0");
4255
4256        let v2: Version = "1.2".parse().unwrap();
4257        assert_eq!(&*v2.release(), &[1, 2]);
4258        assert_eq!(v2.to_string(), "1.2");
4259    }
4260
4261    #[test]
4262    fn only_release_trimmed_discards_non_release_segments() {
4263        for version in ["1.2a1", "1.2.post1", "1!1.2", "1.2+local", "1.2.dev1"] {
4264            let version = version.parse::<Version>().unwrap();
4265            assert_eq!(version.only_release_trimmed(), Version::new([1, 2]));
4266        }
4267
4268        assert_eq!(
4269            Version::new([1, 2])
4270                .with_min(Some(0))
4271                .only_release_trimmed(),
4272            Version::new([1, 2])
4273        );
4274        assert_eq!(
4275            Version::new([1, 2])
4276                .with_max(Some(0))
4277                .only_release_trimmed(),
4278            Version::new([1, 2])
4279        );
4280        assert_eq!(
4281            Version::new([1, 2, 0]).only_release_trimmed(),
4282            Version::new([1, 2])
4283        );
4284        assert_eq!(
4285            Version::new([1, 2]).only_release_trimmed(),
4286            Version::new([1, 2])
4287        );
4288    }
4289
4290    #[test]
4291    fn type_size() {
4292        assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4293        assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4294    }
4295
4296    /// Test major bumping
4297    /// Explicitly using the string display because we want to preserve formatting where possible!
4298    #[test]
4299    fn bump_major() {
4300        // one digit
4301        let mut version = "0".parse::<Version>().unwrap();
4302        version.bump(BumpCommand::BumpRelease {
4303            index: 0,
4304            value: None,
4305        });
4306        assert_eq!(version.to_string().as_str(), "1");
4307
4308        // two digit
4309        let mut version = "1.5".parse::<Version>().unwrap();
4310        version.bump(BumpCommand::BumpRelease {
4311            index: 0,
4312            value: None,
4313        });
4314        assert_eq!(version.to_string().as_str(), "2.0");
4315
4316        // three digit (zero major)
4317        let mut version = "0.1.2".parse::<Version>().unwrap();
4318        version.bump(BumpCommand::BumpRelease {
4319            index: 0,
4320            value: None,
4321        });
4322        assert_eq!(version.to_string().as_str(), "1.0.0");
4323
4324        // three digit (non-zero major)
4325        let mut version = "1.2.3".parse::<Version>().unwrap();
4326        version.bump(BumpCommand::BumpRelease {
4327            index: 0,
4328            value: None,
4329        });
4330        assert_eq!(version.to_string().as_str(), "2.0.0");
4331
4332        // four digit
4333        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4334        version.bump(BumpCommand::BumpRelease {
4335            index: 0,
4336            value: None,
4337        });
4338        assert_eq!(version.to_string().as_str(), "2.0.0.0");
4339
4340        // All the version junk
4341        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4342            .parse::<Version>()
4343            .unwrap();
4344        version.bump(BumpCommand::BumpRelease {
4345            index: 0,
4346            value: None,
4347        });
4348        assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4349        version.bump(BumpCommand::BumpRelease {
4350            index: 0,
4351            value: None,
4352        });
4353        assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4354    }
4355
4356    /// Test minor bumping
4357    /// Explicitly using the string display because we want to preserve formatting where possible!
4358    #[test]
4359    fn bump_minor() {
4360        // one digit
4361        let mut version = "0".parse::<Version>().unwrap();
4362        version.bump(BumpCommand::BumpRelease {
4363            index: 1,
4364            value: None,
4365        });
4366        assert_eq!(version.to_string().as_str(), "0.1");
4367
4368        // two digit
4369        let mut version = "1.5".parse::<Version>().unwrap();
4370        version.bump(BumpCommand::BumpRelease {
4371            index: 1,
4372            value: None,
4373        });
4374        assert_eq!(version.to_string().as_str(), "1.6");
4375
4376        // three digit (non-zero major)
4377        let mut version = "5.3.6".parse::<Version>().unwrap();
4378        version.bump(BumpCommand::BumpRelease {
4379            index: 1,
4380            value: None,
4381        });
4382        assert_eq!(version.to_string().as_str(), "5.4.0");
4383
4384        // four digit
4385        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4386        version.bump(BumpCommand::BumpRelease {
4387            index: 1,
4388            value: None,
4389        });
4390        assert_eq!(version.to_string().as_str(), "1.3.0.0");
4391
4392        // All the version junk
4393        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4394            .parse::<Version>()
4395            .unwrap();
4396        version.bump(BumpCommand::BumpRelease {
4397            index: 1,
4398            value: None,
4399        });
4400        assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4401        version.bump(BumpCommand::BumpRelease {
4402            index: 1,
4403            value: None,
4404        });
4405        assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4406    }
4407
4408    /// Test patch bumping
4409    /// Explicitly using the string display because we want to preserve formatting where possible!
4410    #[test]
4411    fn bump_patch() {
4412        // one digit
4413        let mut version = "0".parse::<Version>().unwrap();
4414        version.bump(BumpCommand::BumpRelease {
4415            index: 2,
4416            value: None,
4417        });
4418        assert_eq!(version.to_string().as_str(), "0.0.1");
4419
4420        // two digit
4421        let mut version = "1.5".parse::<Version>().unwrap();
4422        version.bump(BumpCommand::BumpRelease {
4423            index: 2,
4424            value: None,
4425        });
4426        assert_eq!(version.to_string().as_str(), "1.5.1");
4427
4428        // three digit
4429        let mut version = "5.3.6".parse::<Version>().unwrap();
4430        version.bump(BumpCommand::BumpRelease {
4431            index: 2,
4432            value: None,
4433        });
4434        assert_eq!(version.to_string().as_str(), "5.3.7");
4435
4436        // four digit
4437        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4438        version.bump(BumpCommand::BumpRelease {
4439            index: 2,
4440            value: None,
4441        });
4442        assert_eq!(version.to_string().as_str(), "1.2.4.0");
4443
4444        // All the version junk
4445        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4446            .parse::<Version>()
4447            .unwrap();
4448        version.bump(BumpCommand::BumpRelease {
4449            index: 2,
4450            value: None,
4451        });
4452        assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4453        version.bump(BumpCommand::BumpRelease {
4454            index: 2,
4455            value: None,
4456        });
4457        assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4458    }
4459
4460    /// Test alpha bumping
4461    /// Explicitly using the string display because we want to preserve formatting where possible!
4462    #[test]
4463    fn bump_alpha() {
4464        // one digit
4465        let mut version = "0".parse::<Version>().unwrap();
4466        version.bump(BumpCommand::BumpPrerelease {
4467            kind: PrereleaseKind::Alpha,
4468            value: None,
4469        });
4470        assert_eq!(version.to_string().as_str(), "0a1");
4471
4472        // two digit
4473        let mut version = "1.5".parse::<Version>().unwrap();
4474        version.bump(BumpCommand::BumpPrerelease {
4475            kind: PrereleaseKind::Alpha,
4476            value: None,
4477        });
4478        assert_eq!(version.to_string().as_str(), "1.5a1");
4479
4480        // three digit
4481        let mut version = "5.3.6".parse::<Version>().unwrap();
4482        version.bump(BumpCommand::BumpPrerelease {
4483            kind: PrereleaseKind::Alpha,
4484            value: None,
4485        });
4486        assert_eq!(version.to_string().as_str(), "5.3.6a1");
4487
4488        // four digit
4489        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4490        version.bump(BumpCommand::BumpPrerelease {
4491            kind: PrereleaseKind::Alpha,
4492            value: None,
4493        });
4494        assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4495
4496        // All the version junk
4497        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4498            .parse::<Version>()
4499            .unwrap();
4500        version.bump(BumpCommand::BumpPrerelease {
4501            kind: PrereleaseKind::Alpha,
4502            value: None,
4503        });
4504        assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4505        version.bump(BumpCommand::BumpPrerelease {
4506            kind: PrereleaseKind::Alpha,
4507            value: None,
4508        });
4509        assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4510    }
4511
4512    /// Test beta bumping
4513    /// Explicitly using the string display because we want to preserve formatting where possible!
4514    #[test]
4515    fn bump_beta() {
4516        // one digit
4517        let mut version = "0".parse::<Version>().unwrap();
4518        version.bump(BumpCommand::BumpPrerelease {
4519            kind: PrereleaseKind::Beta,
4520            value: None,
4521        });
4522        assert_eq!(version.to_string().as_str(), "0b1");
4523
4524        // two digit
4525        let mut version = "1.5".parse::<Version>().unwrap();
4526        version.bump(BumpCommand::BumpPrerelease {
4527            kind: PrereleaseKind::Beta,
4528            value: None,
4529        });
4530        assert_eq!(version.to_string().as_str(), "1.5b1");
4531
4532        // three digit
4533        let mut version = "5.3.6".parse::<Version>().unwrap();
4534        version.bump(BumpCommand::BumpPrerelease {
4535            kind: PrereleaseKind::Beta,
4536            value: None,
4537        });
4538        assert_eq!(version.to_string().as_str(), "5.3.6b1");
4539
4540        // four digit
4541        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4542        version.bump(BumpCommand::BumpPrerelease {
4543            kind: PrereleaseKind::Beta,
4544            value: None,
4545        });
4546        assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4547
4548        // All the version junk
4549        let mut version = "5!1.7.3.5a2.post345.dev456+local"
4550            .parse::<Version>()
4551            .unwrap();
4552        version.bump(BumpCommand::BumpPrerelease {
4553            kind: PrereleaseKind::Beta,
4554            value: None,
4555        });
4556        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4557        version.bump(BumpCommand::BumpPrerelease {
4558            kind: PrereleaseKind::Beta,
4559            value: None,
4560        });
4561        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4562    }
4563
4564    /// Test rc bumping
4565    /// Explicitly using the string display because we want to preserve formatting where possible!
4566    #[test]
4567    fn bump_rc() {
4568        // one digit
4569        let mut version = "0".parse::<Version>().unwrap();
4570        version.bump(BumpCommand::BumpPrerelease {
4571            kind: PrereleaseKind::Rc,
4572            value: None,
4573        });
4574        assert_eq!(version.to_string().as_str(), "0rc1");
4575
4576        // two digit
4577        let mut version = "1.5".parse::<Version>().unwrap();
4578        version.bump(BumpCommand::BumpPrerelease {
4579            kind: PrereleaseKind::Rc,
4580            value: None,
4581        });
4582        assert_eq!(version.to_string().as_str(), "1.5rc1");
4583
4584        // three digit
4585        let mut version = "5.3.6".parse::<Version>().unwrap();
4586        version.bump(BumpCommand::BumpPrerelease {
4587            kind: PrereleaseKind::Rc,
4588            value: None,
4589        });
4590        assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4591
4592        // four digit
4593        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4594        version.bump(BumpCommand::BumpPrerelease {
4595            kind: PrereleaseKind::Rc,
4596            value: None,
4597        });
4598        assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4599
4600        // All the version junk
4601        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4602            .parse::<Version>()
4603            .unwrap();
4604        version.bump(BumpCommand::BumpPrerelease {
4605            kind: PrereleaseKind::Rc,
4606            value: None,
4607        });
4608        assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4609        version.bump(BumpCommand::BumpPrerelease {
4610            kind: PrereleaseKind::Rc,
4611            value: None,
4612        });
4613        assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4614    }
4615
4616    /// Test post bumping
4617    /// Explicitly using the string display because we want to preserve formatting where possible!
4618    #[test]
4619    fn bump_post() {
4620        // one digit
4621        let mut version = "0".parse::<Version>().unwrap();
4622        version.bump(BumpCommand::BumpPost { value: None });
4623        assert_eq!(version.to_string().as_str(), "0.post1");
4624
4625        // two digit
4626        let mut version = "1.5".parse::<Version>().unwrap();
4627        version.bump(BumpCommand::BumpPost { value: None });
4628        assert_eq!(version.to_string().as_str(), "1.5.post1");
4629
4630        // three digit
4631        let mut version = "5.3.6".parse::<Version>().unwrap();
4632        version.bump(BumpCommand::BumpPost { value: None });
4633        assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4634
4635        // four digit
4636        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4637        version.bump(BumpCommand::BumpPost { value: None });
4638        assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4639
4640        // All the version junk
4641        let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4642        version.bump(BumpCommand::BumpPost { value: None });
4643        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4644        version.bump(BumpCommand::BumpPost { value: None });
4645        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4646    }
4647
4648    /// Test dev bumping
4649    /// Explicitly using the string display because we want to preserve formatting where possible!
4650    #[test]
4651    fn bump_dev() {
4652        // one digit
4653        let mut version = "0".parse::<Version>().unwrap();
4654        version.bump(BumpCommand::BumpDev { value: None });
4655        assert_eq!(version.to_string().as_str(), "0.dev1");
4656
4657        // two digit
4658        let mut version = "1.5".parse::<Version>().unwrap();
4659        version.bump(BumpCommand::BumpDev { value: None });
4660        assert_eq!(version.to_string().as_str(), "1.5.dev1");
4661
4662        // three digit
4663        let mut version = "5.3.6".parse::<Version>().unwrap();
4664        version.bump(BumpCommand::BumpDev { value: None });
4665        assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4666
4667        // four digit
4668        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4669        version.bump(BumpCommand::BumpDev { value: None });
4670        assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4671
4672        // All the version junk
4673        let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4674        version.bump(BumpCommand::BumpDev { value: None });
4675        assert_eq!(
4676            version.to_string().as_str(),
4677            "5!1.7.3.5b2.post345.dev1+local"
4678        );
4679        version.bump(BumpCommand::BumpDev { value: None });
4680        assert_eq!(
4681            version.to_string().as_str(),
4682            "5!1.7.3.5b2.post345.dev2+local"
4683        );
4684    }
4685
4686    /// Test stable setting
4687    /// Explicitly using the string display because we want to preserve formatting where possible!
4688    #[test]
4689    fn make_stable() {
4690        // one digit
4691        let mut version = "0".parse::<Version>().unwrap();
4692        version.bump(BumpCommand::MakeStable);
4693        assert_eq!(version.to_string().as_str(), "0");
4694
4695        // two digit
4696        let mut version = "1.5".parse::<Version>().unwrap();
4697        version.bump(BumpCommand::MakeStable);
4698        assert_eq!(version.to_string().as_str(), "1.5");
4699
4700        // three digit
4701        let mut version = "5.3.6".parse::<Version>().unwrap();
4702        version.bump(BumpCommand::MakeStable);
4703        assert_eq!(version.to_string().as_str(), "5.3.6");
4704
4705        // four digit
4706        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4707        version.bump(BumpCommand::MakeStable);
4708        assert_eq!(version.to_string().as_str(), "1.2.3.4");
4709
4710        // All the version junk
4711        let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4712        version.bump(BumpCommand::MakeStable);
4713        assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4714        version.bump(BumpCommand::MakeStable);
4715        assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4716    }
4717}