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    pub 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    pub 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 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 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 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 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 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 == self.release().len() {
632                // Already trimmed.
633                self.clone()
634            } else {
635                Self::new(self.release().iter().take(last_non_zero + 1).copied())
636            }
637        } else {
638            // `0` is a valid version.
639            Self::new([0])
640        }
641    }
642
643    /// Return the version with trailing `.0` release segments removed.
644    ///
645    /// # Panics
646    ///
647    /// When the release is all zero segments.
648    #[inline]
649    #[must_use]
650    pub fn without_trailing_zeros(self) -> Self {
651        let mut release = self.release().to_vec();
652        while let Some(0) = release.last() {
653            release.pop();
654        }
655        self.with_release(release)
656    }
657
658    /// Various "increment the version" operations
659    pub fn bump(&mut self, bump: BumpCommand) {
660        // This code operates on the understanding that the components of a version form
661        // the following hierarchy:
662        //
663        //   major > minor > patch > stable > pre > post > dev
664        //
665        // Any updates to something earlier in the hierarchy should clear all values lower
666        // in the hierarchy. So for instance:
667        //
668        // if you bump `minor`, then clear: patch, pre, post, dev
669        // if you bump `pre`, then clear: post, dev
670        //
671        // ...and so on.
672        //
673        // If you bump a value that doesn't exist, it will be set to "1".
674        //
675        // The special "stable" mode has no value, bumping it clears: pre, post, dev.
676        let full = self.make_full();
677
678        match bump {
679            BumpCommand::BumpRelease { index, value } => {
680                // Clear all sub-release items
681                full.pre = None;
682                full.post = None;
683                full.dev = None;
684
685                // Use `max` here to try to do 0.2 => 0.3 instead of 0.2 => 0.3.0
686                let old_parts = &full.release;
687                let len = old_parts.len().max(index + 1);
688                let new_release_vec = (0..len)
689                    .map(|i| match i.cmp(&index) {
690                        // Everything before the bumped value is preserved (or is an implicit 0)
691                        Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
692                        // This is the value to bump (could be implicit 0)
693                        Ordering::Equal => {
694                            value.unwrap_or_else(|| old_parts.get(i).copied().unwrap_or(0) + 1)
695                        }
696                        // Everything after the bumped value becomes 0
697                        Ordering::Greater => 0,
698                    })
699                    .collect::<Vec<u64>>();
700                full.release = new_release_vec;
701            }
702            BumpCommand::MakeStable => {
703                // Clear all sub-release items
704                full.pre = None;
705                full.post = None;
706                full.dev = None;
707            }
708            BumpCommand::BumpPrerelease { kind, value } => {
709                // Clear all sub-prerelease items
710                full.post = None;
711                full.dev = None;
712                if let Some(value) = value {
713                    full.pre = Some(Prerelease {
714                        kind,
715                        number: value,
716                    });
717                } else {
718                    // Either bump the matching kind or set to 1
719                    if let Some(prerelease) = &mut full.pre {
720                        if prerelease.kind == kind {
721                            prerelease.number += 1;
722                            return;
723                        }
724                    }
725                    full.pre = Some(Prerelease { kind, number: 1 });
726                }
727            }
728            BumpCommand::BumpPost { value } => {
729                // Clear sub-post items
730                full.dev = None;
731                if let Some(value) = value {
732                    full.post = Some(value);
733                } else {
734                    // Either bump or set to 1
735                    if let Some(post) = &mut full.post {
736                        *post += 1;
737                    } else {
738                        full.post = Some(1);
739                    }
740                }
741            }
742            BumpCommand::BumpDev { value } => {
743                if let Some(value) = value {
744                    full.dev = Some(value);
745                } else {
746                    // Either bump or set to 1
747                    if let Some(dev) = &mut full.dev {
748                        *dev += 1;
749                    } else {
750                        full.dev = Some(1);
751                    }
752                }
753            }
754        }
755    }
756
757    /// Set the min-release component and return the updated version.
758    ///
759    /// The "min" component is internal-only, and does not exist in PEP 440.
760    /// The version `1.0min0` is smaller than all other `1.0` versions,
761    /// like `1.0a1`, `1.0dev0`, etc.
762    #[inline]
763    #[must_use]
764    pub fn with_min(mut self, value: Option<u64>) -> Self {
765        debug_assert!(!self.is_pre(), "min is not allowed on pre-release versions");
766        debug_assert!(!self.is_dev(), "min is not allowed on dev versions");
767        if let VersionInner::Small { small } = &mut self.inner {
768            if small.set_min(value) {
769                return self;
770            }
771        }
772        self.make_full().min = value;
773        self
774    }
775
776    /// Set the max-release component and return the updated version.
777    ///
778    /// The "max" component is internal-only, and does not exist in PEP 440.
779    /// The version `1.0max0` is larger than all other `1.0` versions,
780    /// like `1.0.post1`, `1.0+local`, etc.
781    #[inline]
782    #[must_use]
783    pub fn with_max(mut self, value: Option<u64>) -> Self {
784        debug_assert!(
785            !self.is_post(),
786            "max is not allowed on post-release versions"
787        );
788        debug_assert!(!self.is_dev(), "max is not allowed on dev versions");
789        if let VersionInner::Small { small } = &mut self.inner {
790            if small.set_max(value) {
791                return self;
792            }
793        }
794        self.make_full().max = value;
795        self
796    }
797
798    /// Convert this version to a "full" representation in-place and return a
799    /// mutable borrow to the full type.
800    fn make_full(&mut self) -> &mut VersionFull {
801        if let VersionInner::Small { ref small } = self.inner {
802            let full = VersionFull {
803                epoch: small.epoch(),
804                release: self.release().to_vec(),
805                min: small.min(),
806                max: small.max(),
807                pre: small.pre(),
808                post: small.post(),
809                dev: small.dev(),
810                local: small.local(),
811            };
812            *self = Self {
813                inner: VersionInner::Full {
814                    full: Arc::new(full),
815                },
816            };
817        }
818        match &mut self.inner {
819            VersionInner::Full { full } => Arc::make_mut(full),
820            VersionInner::Small { .. } => unreachable!(),
821        }
822    }
823
824    /// Performs a "slow" but complete comparison between two versions.
825    ///
826    /// This comparison is done using only the public API of a `Version`, and
827    /// is thus independent of its specific representation. This is useful
828    /// to use when comparing two versions that aren't *both* the small
829    /// representation.
830    #[cold]
831    #[inline(never)]
832    fn cmp_slow(&self, other: &Self) -> Ordering {
833        match self.epoch().cmp(&other.epoch()) {
834            Ordering::Less => {
835                return Ordering::Less;
836            }
837            Ordering::Equal => {}
838            Ordering::Greater => {
839                return Ordering::Greater;
840            }
841        }
842
843        match compare_release(&self.release(), &other.release()) {
844            Ordering::Less => {
845                return Ordering::Less;
846            }
847            Ordering::Equal => {}
848            Ordering::Greater => {
849                return Ordering::Greater;
850            }
851        }
852
853        // release is equal, so compare the other parts
854        sortable_tuple(self).cmp(&sortable_tuple(other))
855    }
856}
857
858impl<'de> Deserialize<'de> for Version {
859    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
860    where
861        D: Deserializer<'de>,
862    {
863        struct Visitor;
864
865        impl de::Visitor<'_> for Visitor {
866            type Value = Version;
867
868            fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
869                f.write_str("a string")
870            }
871
872            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
873                Version::from_str(v).map_err(de::Error::custom)
874            }
875        }
876
877        deserializer.deserialize_str(Visitor)
878    }
879}
880
881/// <https://github.com/serde-rs/serde/issues/1316#issue-332908452>
882impl Serialize for Version {
883    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
884    where
885        S: Serializer,
886    {
887        serializer.collect_str(self)
888    }
889}
890
891/// Shows normalized version
892impl std::fmt::Display for Version {
893    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
894        if self.epoch() != 0 {
895            write!(f, "{}!", self.epoch())?;
896        }
897        let release = self.release();
898        let mut release_iter = release.iter();
899        if let Some(first) = release_iter.next() {
900            write!(f, "{first}")?;
901            for n in release_iter {
902                write!(f, ".{n}")?;
903            }
904        }
905
906        if let Some(Prerelease { kind, number }) = self.pre() {
907            write!(f, "{kind}{number}")?;
908        }
909        if let Some(post) = self.post() {
910            write!(f, ".post{post}")?;
911        }
912        if let Some(dev) = self.dev() {
913            write!(f, ".dev{dev}")?;
914        }
915        if !self.local().is_empty() {
916            match self.local() {
917                LocalVersionSlice::Segments(_) => {
918                    write!(f, "+{}", self.local())?;
919                }
920                LocalVersionSlice::Max => {
921                    write!(f, "+")?;
922                }
923            }
924        }
925        Ok(())
926    }
927}
928
929impl std::fmt::Debug for Version {
930    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
931        write!(f, "\"{self}\"")
932    }
933}
934
935impl PartialEq<Self> for Version {
936    #[inline]
937    fn eq(&self, other: &Self) -> bool {
938        self.cmp(other) == Ordering::Equal
939    }
940}
941
942impl Eq for Version {}
943
944impl Hash for Version {
945    /// Custom implementation to ignoring trailing zero because `PartialEq` zero pads
946    #[inline]
947    fn hash<H: Hasher>(&self, state: &mut H) {
948        self.epoch().hash(state);
949        // Skip trailing zeros
950        for i in self.release().iter().rev().skip_while(|x| **x == 0) {
951            i.hash(state);
952        }
953        self.pre().hash(state);
954        self.dev().hash(state);
955        self.post().hash(state);
956        self.local().hash(state);
957    }
958}
959
960impl CacheKey for Version {
961    fn cache_key(&self, state: &mut CacheKeyHasher) {
962        self.epoch().cache_key(state);
963
964        let release = self.release();
965        release.len().cache_key(state);
966        for segment in release.iter() {
967            segment.cache_key(state);
968        }
969
970        if let Some(pre) = self.pre() {
971            1u8.cache_key(state);
972            match pre.kind {
973                PrereleaseKind::Alpha => 0u8.cache_key(state),
974                PrereleaseKind::Beta => 1u8.cache_key(state),
975                PrereleaseKind::Rc => 2u8.cache_key(state),
976            }
977            pre.number.cache_key(state);
978        } else {
979            0u8.cache_key(state);
980        }
981
982        if let Some(post) = self.post() {
983            1u8.cache_key(state);
984            post.cache_key(state);
985        } else {
986            0u8.cache_key(state);
987        }
988
989        if let Some(dev) = self.dev() {
990            1u8.cache_key(state);
991            dev.cache_key(state);
992        } else {
993            0u8.cache_key(state);
994        }
995
996        self.local().cache_key(state);
997    }
998}
999
1000impl PartialOrd<Self> for Version {
1001    #[inline]
1002    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1003        Some(self.cmp(other))
1004    }
1005}
1006
1007impl Ord for Version {
1008    /// 1.0.dev456 < 1.0a1 < 1.0a2.dev456 < 1.0a12.dev456 < 1.0a12 < 1.0b1.dev456 < 1.0b2
1009    /// < 1.0b2.post345.dev456 < 1.0b2.post345 < 1.0b2-346 < 1.0c1.dev456 < 1.0c1 < 1.0rc2 < 1.0c3
1010    /// < 1.0 < 1.0.post456.dev34 < 1.0.post456
1011    #[inline]
1012    fn cmp(&self, other: &Self) -> Ordering {
1013        match (&self.inner, &other.inner) {
1014            (VersionInner::Small { small: small1 }, VersionInner::Small { small: small2 }) => {
1015                small1.repr.cmp(&small2.repr)
1016            }
1017            _ => self.cmp_slow(other),
1018        }
1019    }
1020}
1021
1022impl FromStr for Version {
1023    type Err = VersionParseError;
1024
1025    /// Parses a version such as `1.19`, `1.0a1`,`1.0+abc.5` or `1!2012.2`
1026    ///
1027    /// Note that this doesn't allow wildcard versions.
1028    fn from_str(version: &str) -> Result<Self, Self::Err> {
1029        Parser::new(version.as_bytes()).parse()
1030    }
1031}
1032
1033/// Various ways to "bump" a version
1034#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
1035pub enum BumpCommand {
1036    /// Bump or set the release component
1037    BumpRelease {
1038        /// The release component to bump (0 is major, 1 is minor, 2 is patch)
1039        index: usize,
1040        /// Explicit value to set; when absent the component is incremented
1041        value: Option<u64>,
1042    },
1043    /// Bump or set the prerelease component
1044    BumpPrerelease {
1045        /// prerelease component to bump
1046        kind: PrereleaseKind,
1047        /// Explicit value to set; when absent the component is incremented
1048        value: Option<u64>,
1049    },
1050    /// Bump to the associated stable release
1051    MakeStable,
1052    /// Bump or set the post component
1053    BumpPost {
1054        /// Explicit value to set; when absent the component is incremented
1055        value: Option<u64>,
1056    },
1057    /// Bump or set the dev component
1058    BumpDev {
1059        /// Explicit value to set; when absent the component is incremented
1060        value: Option<u64>,
1061    },
1062}
1063
1064/// A small representation of a version.
1065///
1066/// This representation is used for a (very common) subset of versions: the
1067/// set of all versions with ~small numbers and no local component. The
1068/// representation is designed to be (somewhat) compact, but also laid out in
1069/// a way that makes comparisons between two small versions equivalent to a
1070/// simple `memcmp`.
1071///
1072/// The methods on this type encapsulate the representation. Since this type
1073/// cannot represent the full range of all versions, setters on this type will
1074/// return `false` if the value could not be stored. In this case, callers
1075/// should generally convert a version into its "full" representation and then
1076/// set the value on the full type.
1077///
1078/// # Representation
1079///
1080/// At time of writing, this representation supports versions that meet all of
1081/// the following criteria:
1082///
1083/// * The epoch must be `0`.
1084/// * The release portion must have 4 or fewer segments.
1085/// * All release segments, except for the first, must be representable in a
1086///   `u8`. The first segment must be representable in a `u16`. (This permits
1087///   calendar versions, like `2023.03`, to be represented.)
1088/// * There is *at most* one of the following components: pre, dev or post.
1089/// * If there is a pre segment, then its numeric value is less than 64.
1090/// * If there is a dev or post segment, then its value is less than `u8::MAX`.
1091/// * There are zero "local" segments.
1092///
1093/// The above constraints were chosen as a balancing point between being able
1094/// to represent all parts of a version in a very small amount of space,
1095/// and for supporting as many versions in the wild as possible. There is,
1096/// however, another constraint in play here: comparisons between two `Version`
1097/// values. It turns out that we do a lot of them as part of resolution, and
1098/// the cheaper we can make that, the better. This constraint pushes us
1099/// toward using as little space as possible. Indeed, here, comparisons are
1100/// implemented via `u64::cmp`.
1101///
1102/// We pack versions fitting the above constraints into a `u64` in such a way
1103/// that it preserves the ordering between versions as prescribed in PEP 440.
1104/// Namely:
1105///
1106/// * Bytes 6 and 7 correspond to the first release segment as a `u16`.
1107/// * Bytes 5, 4 and 3 correspond to the second, third and fourth release
1108///   segments, respectively.
1109/// * Bytes 2, 1 and 0 represent *one* of the following:
1110///   `min, .devN, aN, bN, rcN, <no suffix>, local, .postN, max`.
1111///   Its representation is thus:
1112///   * The most significant 4 bits of Byte 2 corresponds to a value in
1113///     the range 0-8 inclusive, corresponding to min, dev, pre-a, pre-b,
1114///     pre-rc, no-suffix, post or max releases, respectively. `min` is a
1115///     special version that does not exist in PEP 440, but is used here to
1116///     represent the smallest possible version, preceding any `dev`, `pre`,
1117///     `post` or releases. `max` is an analogous concept for the largest
1118///     possible version, following any `post` or local releases.
1119///   * The low 4 bits combined with the bits in bytes 1 and 0 correspond
1120///     to the release number of the suffix, if one exists. If there is no
1121///     suffix, then these bits are always 0.
1122///
1123/// The order of the encoding above is significant. For example, suffixes are
1124/// encoded at a less significant location than the release numbers, so that
1125/// `1.2.3 < 1.2.3.post4`.
1126///
1127/// In a previous representation, we tried to encode the suffixes in different
1128/// locations so that, in theory, you could represent `1.2.3.dev2.post3` in the
1129/// packed form. But getting the ordering right for this is difficult (perhaps
1130/// impossible without extra space?). So we limited to only storing one suffix.
1131/// But even then, we wound up with a bug where `1.0dev1 > 1.0a1`, when of
1132/// course, all dev releases should compare less than pre releases. This was
1133/// because the encoding recorded the pre-release as "absent", and this in turn
1134/// screwed up the order comparisons.
1135///
1136/// Thankfully, such versions are incredibly rare. Virtually all versions have
1137/// zero or one pre, dev or post release components.
1138#[derive(Clone, Debug)]
1139#[cfg_attr(
1140    feature = "rkyv",
1141    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1142)]
1143#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1144struct VersionSmall {
1145    /// The number of segments in the release component.
1146    ///
1147    /// PEP 440 considers `1.2`  equivalent to `1.2.0.0`, but we want to preserve trailing zeroes
1148    /// in roundtrips, as the "full" version representation also does.
1149    len: u8,
1150    /// The representation discussed above.
1151    repr: u64,
1152    /// Force a niche into the aligned type so the [`Version`] enum is two words instead of three.
1153    _force_niche: NonZero<u8>,
1154}
1155
1156impl VersionSmall {
1157    // Constants for each suffix kind. They form an enumeration.
1158    //
1159    // The specific values are assigned in a way that provides the suffix kinds
1160    // their ordering. i.e., No suffix should sort after a dev suffix but
1161    // before a post suffix.
1162    //
1163    // The maximum possible suffix value is SUFFIX_KIND_MASK. If you need to
1164    // add another suffix value and you're at the max, then the mask must gain
1165    // another bit. And adding another bit to the mask will require taking it
1166    // from somewhere else. (Usually the suffix version.)
1167    //
1168    // NOTE: If you do change the bit format here, you'll need to bump any
1169    // cache versions in uv that use rkyv with `Version` in them. That includes
1170    // *at least* the "simple" cache.
1171    const SUFFIX_MIN: u64 = 0;
1172    const SUFFIX_DEV: u64 = 1;
1173    const SUFFIX_PRE_ALPHA: u64 = 2;
1174    const SUFFIX_PRE_BETA: u64 = 3;
1175    const SUFFIX_PRE_RC: u64 = 4;
1176    const SUFFIX_NONE: u64 = 5;
1177    const SUFFIX_LOCAL: u64 = 6;
1178    const SUFFIX_POST: u64 = 7;
1179    const SUFFIX_MAX: u64 = 8;
1180
1181    // The mask to get only the release segment bits.
1182    //
1183    // NOTE: If you change the release mask to have more or less bits,
1184    // then you'll also need to change `push_release` below and also
1185    // `Parser::parse_fast`.
1186    const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
1187    // The mask to get the version suffix.
1188    const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
1189    // The number of bits used by the version suffix. Shifting the `repr`
1190    // right by this number of bits should put the suffix kind in the least
1191    // significant bits.
1192    const SUFFIX_VERSION_BIT_LEN: u64 = 20;
1193    // The mask to get only the suffix kind, after shifting right by the
1194    // version bits. If you need to add a bit here, then you'll probably need
1195    // to take a bit from the suffix version. (Which requires a change to both
1196    // the mask and the bit length above.)
1197    const SUFFIX_KIND_MASK: u64 = 0b1111;
1198
1199    #[inline]
1200    fn new() -> Self {
1201        Self {
1202            _force_niche: NonZero::<u8>::MIN,
1203            repr: Self::SUFFIX_NONE << Self::SUFFIX_VERSION_BIT_LEN,
1204            len: 0,
1205        }
1206    }
1207
1208    #[inline]
1209    #[expect(clippy::unused_self)]
1210    fn epoch(&self) -> u64 {
1211        0
1212    }
1213
1214    #[inline]
1215    #[expect(clippy::unused_self)]
1216    fn set_epoch(&mut self, value: u64) -> bool {
1217        if value != 0 {
1218            return false;
1219        }
1220        true
1221    }
1222
1223    #[inline]
1224    fn clear_release(&mut self) {
1225        self.repr &= !Self::SUFFIX_RELEASE_MASK;
1226        self.len = 0;
1227    }
1228
1229    #[inline]
1230    fn push_release(&mut self, n: u64) -> bool {
1231        if self.len == 0 {
1232            if n > u64::from(u16::MAX) {
1233                return false;
1234            }
1235            self.repr |= n << 48;
1236            self.len = 1;
1237            true
1238        } else {
1239            if n > u64::from(u8::MAX) {
1240                return false;
1241            }
1242            if self.len >= 4 {
1243                return false;
1244            }
1245            let shift = 48 - (usize::from(self.len) * 8);
1246            self.repr |= n << shift;
1247            self.len += 1;
1248            true
1249        }
1250    }
1251
1252    #[inline]
1253    fn post(&self) -> Option<u64> {
1254        if self.suffix_kind() == Self::SUFFIX_POST {
1255            Some(self.suffix_version())
1256        } else {
1257            None
1258        }
1259    }
1260
1261    #[inline]
1262    fn set_post(&mut self, value: Option<u64>) -> bool {
1263        let suffix_kind = self.suffix_kind();
1264        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1265            return value.is_none();
1266        }
1267        match value {
1268            None => {
1269                self.set_suffix_kind(Self::SUFFIX_NONE);
1270            }
1271            Some(number) => {
1272                if number > Self::SUFFIX_VERSION_MASK {
1273                    return false;
1274                }
1275                self.set_suffix_kind(Self::SUFFIX_POST);
1276                self.set_suffix_version(number);
1277            }
1278        }
1279        true
1280    }
1281
1282    #[inline]
1283    fn pre(&self) -> Option<Prerelease> {
1284        let (kind, number) = (self.suffix_kind(), self.suffix_version());
1285        if kind == Self::SUFFIX_PRE_ALPHA {
1286            Some(Prerelease {
1287                kind: PrereleaseKind::Alpha,
1288                number,
1289            })
1290        } else if kind == Self::SUFFIX_PRE_BETA {
1291            Some(Prerelease {
1292                kind: PrereleaseKind::Beta,
1293                number,
1294            })
1295        } else if kind == Self::SUFFIX_PRE_RC {
1296            Some(Prerelease {
1297                kind: PrereleaseKind::Rc,
1298                number,
1299            })
1300        } else {
1301            None
1302        }
1303    }
1304
1305    #[inline]
1306    fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1307        let suffix_kind = self.suffix_kind();
1308        if !(suffix_kind == Self::SUFFIX_NONE
1309            || suffix_kind == Self::SUFFIX_PRE_ALPHA
1310            || suffix_kind == Self::SUFFIX_PRE_BETA
1311            || suffix_kind == Self::SUFFIX_PRE_RC)
1312        {
1313            return value.is_none();
1314        }
1315        match value {
1316            None => {
1317                self.set_suffix_kind(Self::SUFFIX_NONE);
1318            }
1319            Some(Prerelease { kind, number }) => {
1320                if number > Self::SUFFIX_VERSION_MASK {
1321                    return false;
1322                }
1323                match kind {
1324                    PrereleaseKind::Alpha => {
1325                        self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1326                    }
1327                    PrereleaseKind::Beta => {
1328                        self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1329                    }
1330                    PrereleaseKind::Rc => {
1331                        self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1332                    }
1333                }
1334                self.set_suffix_version(number);
1335            }
1336        }
1337        true
1338    }
1339
1340    #[inline]
1341    fn dev(&self) -> Option<u64> {
1342        if self.suffix_kind() == Self::SUFFIX_DEV {
1343            Some(self.suffix_version())
1344        } else {
1345            None
1346        }
1347    }
1348
1349    #[inline]
1350    fn set_dev(&mut self, value: Option<u64>) -> bool {
1351        let suffix_kind = self.suffix_kind();
1352        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1353            return value.is_none();
1354        }
1355        match value {
1356            None => {
1357                self.set_suffix_kind(Self::SUFFIX_NONE);
1358            }
1359            Some(number) => {
1360                if number > Self::SUFFIX_VERSION_MASK {
1361                    return false;
1362                }
1363                self.set_suffix_kind(Self::SUFFIX_DEV);
1364                self.set_suffix_version(number);
1365            }
1366        }
1367        true
1368    }
1369
1370    #[inline]
1371    fn min(&self) -> Option<u64> {
1372        if self.suffix_kind() == Self::SUFFIX_MIN {
1373            Some(self.suffix_version())
1374        } else {
1375            None
1376        }
1377    }
1378
1379    #[inline]
1380    fn set_min(&mut self, value: Option<u64>) -> bool {
1381        let suffix_kind = self.suffix_kind();
1382        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1383            return value.is_none();
1384        }
1385        match value {
1386            None => {
1387                self.set_suffix_kind(Self::SUFFIX_NONE);
1388            }
1389            Some(number) => {
1390                if number > Self::SUFFIX_VERSION_MASK {
1391                    return false;
1392                }
1393                self.set_suffix_kind(Self::SUFFIX_MIN);
1394                self.set_suffix_version(number);
1395            }
1396        }
1397        true
1398    }
1399
1400    #[inline]
1401    fn max(&self) -> Option<u64> {
1402        if self.suffix_kind() == Self::SUFFIX_MAX {
1403            Some(self.suffix_version())
1404        } else {
1405            None
1406        }
1407    }
1408
1409    #[inline]
1410    fn set_max(&mut self, value: Option<u64>) -> bool {
1411        let suffix_kind = self.suffix_kind();
1412        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1413            return value.is_none();
1414        }
1415        match value {
1416            None => {
1417                self.set_suffix_kind(Self::SUFFIX_NONE);
1418            }
1419            Some(number) => {
1420                if number > Self::SUFFIX_VERSION_MASK {
1421                    return false;
1422                }
1423                self.set_suffix_kind(Self::SUFFIX_MAX);
1424                self.set_suffix_version(number);
1425            }
1426        }
1427        true
1428    }
1429
1430    #[inline]
1431    fn local(&self) -> LocalVersion {
1432        if self.suffix_kind() == Self::SUFFIX_LOCAL {
1433            LocalVersion::Max
1434        } else {
1435            LocalVersion::empty()
1436        }
1437    }
1438
1439    #[inline]
1440    fn local_slice(&self) -> LocalVersionSlice<'_> {
1441        if self.suffix_kind() == Self::SUFFIX_LOCAL {
1442            LocalVersionSlice::Max
1443        } else {
1444            LocalVersionSlice::empty()
1445        }
1446    }
1447
1448    #[inline]
1449    fn set_local(&mut self, value: LocalVersion) -> bool {
1450        let suffix_kind = self.suffix_kind();
1451        if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1452            return value.is_empty();
1453        }
1454        match value {
1455            LocalVersion::Max => {
1456                self.set_suffix_kind(Self::SUFFIX_LOCAL);
1457                true
1458            }
1459            LocalVersion::Segments(segments) if segments.is_empty() => {
1460                self.set_suffix_kind(Self::SUFFIX_NONE);
1461                true
1462            }
1463            LocalVersion::Segments(_) => false,
1464        }
1465    }
1466
1467    #[inline]
1468    fn suffix_kind(&self) -> u64 {
1469        let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1470        debug_assert!(kind <= Self::SUFFIX_MAX);
1471        kind
1472    }
1473
1474    #[inline]
1475    fn set_suffix_kind(&mut self, kind: u64) {
1476        debug_assert!(kind <= Self::SUFFIX_MAX);
1477        self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1478        self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1479        if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1480            self.set_suffix_version(0);
1481        }
1482    }
1483
1484    #[inline]
1485    fn suffix_version(&self) -> u64 {
1486        self.repr & Self::SUFFIX_VERSION_MASK
1487    }
1488
1489    #[inline]
1490    fn set_suffix_version(&mut self, value: u64) {
1491        debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1492        self.repr &= !Self::SUFFIX_VERSION_MASK;
1493        self.repr |= value;
1494    }
1495}
1496
1497/// The "full" representation of a version.
1498///
1499/// This can represent all possible versions, but is a bit beefier because of
1500/// it. It also uses some indirection for variable length data such as the
1501/// release numbers and the local segments.
1502///
1503/// In general, the "full" representation is rarely used in practice since most
1504/// versions will fit into the "small" representation.
1505#[derive(Clone, Debug)]
1506#[cfg_attr(
1507    feature = "rkyv",
1508    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1509)]
1510#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1511struct VersionFull {
1512    /// The [versioning
1513    /// epoch](https://peps.python.org/pep-0440/#version-epochs). Normally
1514    /// just 0, but you can increment it if you switched the versioning
1515    /// scheme.
1516    epoch: u64,
1517    /// The normal number part of the version (["final
1518    /// release"](https://peps.python.org/pep-0440/#final-releases)), such
1519    /// a `1.2.3` in `4!1.2.3-a8.post9.dev1`
1520    ///
1521    /// Note that we drop the * placeholder by moving it to `Operator`
1522    release: Vec<u64>,
1523    /// The [prerelease](https://peps.python.org/pep-0440/#pre-releases),
1524    /// i.e. alpha, beta or rc plus a number
1525    ///
1526    /// Note that whether this is Some influences the version range
1527    /// matching since normally we exclude all pre-release versions
1528    pre: Option<Prerelease>,
1529    /// The [Post release
1530    /// version](https://peps.python.org/pep-0440/#post-releases), higher
1531    /// post version are preferred over lower post or none-post versions
1532    post: Option<u64>,
1533    /// The [developmental
1534    /// release](https://peps.python.org/pep-0440/#developmental-releases),
1535    /// if any
1536    dev: Option<u64>,
1537    /// A [local version
1538    /// identifier](https://peps.python.org/pep-0440/#local-version-identifiers)
1539    /// such as `+deadbeef` in `1.2.3+deadbeef`
1540    ///
1541    /// > They consist of a normal public version identifier (as defined
1542    /// > in the previous section), along with an arbitrary “local version
1543    /// > label”, separated from the public version identifier by a plus.
1544    /// > Local version labels have no specific semantics assigned, but
1545    /// > some syntactic restrictions are imposed.
1546    ///
1547    /// Local versions allow multiple segments separated by periods, such as `deadbeef.1.2.3`, see
1548    /// [`LocalSegment`] for details on the semantics.
1549    local: LocalVersion,
1550    /// An internal-only segment that does not exist in PEP 440, used to
1551    /// represent the smallest possible version of a release, preceding any
1552    /// `dev`, `pre`, `post` or releases.
1553    min: Option<u64>,
1554    /// An internal-only segment that does not exist in PEP 440, used to
1555    /// represent the largest possible version of a release, following any
1556    /// `post` or local releases.
1557    max: Option<u64>,
1558}
1559
1560/// A version number pattern.
1561///
1562/// A version pattern appears in a
1563/// [`VersionSpecifier`](crate::VersionSpecifier). It is just like a version,
1564/// except that it permits a trailing `*` (wildcard) at the end of the version
1565/// number. The wildcard indicates that any version with the same prefix should
1566/// match.
1567///
1568/// A `VersionPattern` cannot do any matching itself. Instead,
1569/// it needs to be paired with an [`Operator`] to create a
1570/// [`VersionSpecifier`](crate::VersionSpecifier).
1571///
1572/// Here are some valid and invalid examples:
1573///
1574/// * `1.2.3` -> verbatim pattern
1575/// * `1.2.3.*` -> wildcard pattern
1576/// * `1.2.*.4` -> invalid
1577/// * `1.0-dev1.*` -> invalid
1578#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1579pub struct VersionPattern {
1580    version: Version,
1581    wildcard: bool,
1582}
1583
1584impl VersionPattern {
1585    /// Creates a new verbatim version pattern that matches the given
1586    /// version exactly.
1587    #[inline]
1588    pub fn verbatim(version: Version) -> Self {
1589        Self {
1590            version,
1591            wildcard: false,
1592        }
1593    }
1594
1595    /// Creates a new wildcard version pattern that matches any version with
1596    /// the given version as a prefix.
1597    #[inline]
1598    pub fn wildcard(version: Version) -> Self {
1599        Self {
1600            version,
1601            wildcard: true,
1602        }
1603    }
1604
1605    /// Returns the underlying version.
1606    #[inline]
1607    pub fn version(&self) -> &Version {
1608        &self.version
1609    }
1610
1611    /// Consumes this pattern and returns ownership of the underlying version.
1612    #[inline]
1613    pub fn into_version(self) -> Version {
1614        self.version
1615    }
1616
1617    /// Returns true if and only if this pattern contains a wildcard.
1618    #[inline]
1619    pub fn is_wildcard(&self) -> bool {
1620        self.wildcard
1621    }
1622}
1623
1624impl FromStr for VersionPattern {
1625    type Err = VersionPatternParseError;
1626
1627    fn from_str(version: &str) -> Result<Self, VersionPatternParseError> {
1628        Parser::new(version.as_bytes()).parse_pattern()
1629    }
1630}
1631
1632/// Release digits of a [`Version`].
1633///
1634/// Lifetime and indexing workaround to allow accessing the release as `&[u64]` even though the
1635/// digits may be stored in a compressed representation.
1636pub struct Release<'a> {
1637    inner: ReleaseInner<'a>,
1638}
1639
1640enum ReleaseInner<'a> {
1641    // The small versions unpacked into larger u64 values.
1642    // We're storing at most 4 u64 plus determinant for the duration of the release call on the
1643    // stack, without heap allocation.
1644    Small0([u64; 0]),
1645    Small1([u64; 1]),
1646    Small2([u64; 2]),
1647    Small3([u64; 3]),
1648    Small4([u64; 4]),
1649    Full(&'a [u64]),
1650}
1651
1652impl Deref for Release<'_> {
1653    type Target = [u64];
1654
1655    fn deref(&self) -> &Self::Target {
1656        match &self.inner {
1657            ReleaseInner::Small0(v) => v,
1658            ReleaseInner::Small1(v) => v,
1659            ReleaseInner::Small2(v) => v,
1660            ReleaseInner::Small3(v) => v,
1661            ReleaseInner::Small4(v) => v,
1662            ReleaseInner::Full(v) => v,
1663        }
1664    }
1665}
1666
1667/// An optional pre-release modifier and number applied to a version.
1668#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1669#[cfg_attr(
1670    feature = "rkyv",
1671    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1672)]
1673#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1674pub struct Prerelease {
1675    /// The kind of pre-release.
1676    pub kind: PrereleaseKind,
1677    /// The number associated with the pre-release.
1678    pub number: u64,
1679}
1680
1681/// Optional pre-release modifier (alpha, beta or release candidate) appended to version
1682///
1683/// <https://peps.python.org/pep-0440/#pre-releases>
1684#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1685#[cfg_attr(
1686    feature = "rkyv",
1687    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1688)]
1689#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1690pub enum PrereleaseKind {
1691    /// alpha pre-release
1692    Alpha,
1693    /// beta pre-release
1694    Beta,
1695    /// release candidate pre-release
1696    Rc,
1697}
1698
1699impl std::fmt::Display for PrereleaseKind {
1700    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1701        match self {
1702            Self::Alpha => write!(f, "a"),
1703            Self::Beta => write!(f, "b"),
1704            Self::Rc => write!(f, "rc"),
1705        }
1706    }
1707}
1708
1709impl std::fmt::Display for Prerelease {
1710    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1711        write!(f, "{}{}", self.kind, self.number)
1712    }
1713}
1714
1715/// Either a sequence of local segments or [`LocalVersion::Sentinel`], an internal-only value that
1716/// compares greater than all other local versions.
1717#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1718#[cfg_attr(
1719    feature = "rkyv",
1720    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1721)]
1722#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1723pub enum LocalVersion {
1724    /// A sequence of local segments.
1725    Segments(Vec<LocalSegment>),
1726    /// An internal-only value that compares greater to all other local versions.
1727    Max,
1728}
1729
1730/// Like [`LocalVersion`], but using a slice
1731#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1732pub enum LocalVersionSlice<'a> {
1733    /// Like [`LocalVersion::Segments`]
1734    Segments(&'a [LocalSegment]),
1735    /// Like [`LocalVersion::Sentinel`]
1736    Max,
1737}
1738
1739impl LocalVersion {
1740    /// Return an empty local version.
1741    pub fn empty() -> Self {
1742        Self::Segments(Vec::new())
1743    }
1744
1745    /// Returns `true` if the local version is empty.
1746    pub fn is_empty(&self) -> bool {
1747        match self {
1748            Self::Segments(segments) => segments.is_empty(),
1749            Self::Max => false,
1750        }
1751    }
1752
1753    /// Convert the local version segments into a slice.
1754    pub fn as_slice(&self) -> LocalVersionSlice<'_> {
1755        match self {
1756            Self::Segments(segments) => LocalVersionSlice::Segments(segments),
1757            Self::Max => LocalVersionSlice::Max,
1758        }
1759    }
1760
1761    /// Clear the local version segments, if they exist.
1762    pub fn clear(&mut self) {
1763        match self {
1764            Self::Segments(segments) => segments.clear(),
1765            Self::Max => *self = Self::Segments(Vec::new()),
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    pub 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    /// Wraps a `Version` and provides a more "bloated" debug but standard
4222    /// representation.
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    struct VersionBloatedDebug<'a>(&'a Version);
4232
4233    impl std::fmt::Debug for VersionBloatedDebug<'_> {
4234        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4235            f.debug_struct("Version")
4236                .field("epoch", &self.0.epoch())
4237                .field("release", &&*self.0.release())
4238                .field("pre", &self.0.pre())
4239                .field("post", &self.0.post())
4240                .field("dev", &self.0.dev())
4241                .field("local", &self.0.local())
4242                .field("min", &self.0.min())
4243                .field("max", &self.0.max())
4244                .finish()
4245        }
4246    }
4247
4248    impl Version {
4249        pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4250            VersionBloatedDebug(self)
4251        }
4252    }
4253
4254    /// This explicitly tests that we preserve trailing zeros in a version
4255    /// string. i.e., Both `1.2` and `1.2.0` round-trip, with the former
4256    /// lacking a trailing zero and the latter including it.
4257    #[test]
4258    fn preserve_trailing_zeros() {
4259        let v1: Version = "1.2.0".parse().unwrap();
4260        assert_eq!(&*v1.release(), &[1, 2, 0]);
4261        assert_eq!(v1.to_string(), "1.2.0");
4262
4263        let v2: Version = "1.2".parse().unwrap();
4264        assert_eq!(&*v2.release(), &[1, 2]);
4265        assert_eq!(v2.to_string(), "1.2");
4266    }
4267
4268    #[test]
4269    fn type_size() {
4270        assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4271        assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4272    }
4273
4274    /// Test major bumping
4275    /// Explicitly using the string display because we want to preserve formatting where possible!
4276    #[test]
4277    fn bump_major() {
4278        // one digit
4279        let mut version = "0".parse::<Version>().unwrap();
4280        version.bump(BumpCommand::BumpRelease {
4281            index: 0,
4282            value: None,
4283        });
4284        assert_eq!(version.to_string().as_str(), "1");
4285
4286        // two digit
4287        let mut version = "1.5".parse::<Version>().unwrap();
4288        version.bump(BumpCommand::BumpRelease {
4289            index: 0,
4290            value: None,
4291        });
4292        assert_eq!(version.to_string().as_str(), "2.0");
4293
4294        // three digit (zero major)
4295        let mut version = "0.1.2".parse::<Version>().unwrap();
4296        version.bump(BumpCommand::BumpRelease {
4297            index: 0,
4298            value: None,
4299        });
4300        assert_eq!(version.to_string().as_str(), "1.0.0");
4301
4302        // three digit (non-zero major)
4303        let mut version = "1.2.3".parse::<Version>().unwrap();
4304        version.bump(BumpCommand::BumpRelease {
4305            index: 0,
4306            value: None,
4307        });
4308        assert_eq!(version.to_string().as_str(), "2.0.0");
4309
4310        // four digit
4311        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4312        version.bump(BumpCommand::BumpRelease {
4313            index: 0,
4314            value: None,
4315        });
4316        assert_eq!(version.to_string().as_str(), "2.0.0.0");
4317
4318        // All the version junk
4319        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4320            .parse::<Version>()
4321            .unwrap();
4322        version.bump(BumpCommand::BumpRelease {
4323            index: 0,
4324            value: None,
4325        });
4326        assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4327        version.bump(BumpCommand::BumpRelease {
4328            index: 0,
4329            value: None,
4330        });
4331        assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4332    }
4333
4334    /// Test minor bumping
4335    /// Explicitly using the string display because we want to preserve formatting where possible!
4336    #[test]
4337    fn bump_minor() {
4338        // one digit
4339        let mut version = "0".parse::<Version>().unwrap();
4340        version.bump(BumpCommand::BumpRelease {
4341            index: 1,
4342            value: None,
4343        });
4344        assert_eq!(version.to_string().as_str(), "0.1");
4345
4346        // two digit
4347        let mut version = "1.5".parse::<Version>().unwrap();
4348        version.bump(BumpCommand::BumpRelease {
4349            index: 1,
4350            value: None,
4351        });
4352        assert_eq!(version.to_string().as_str(), "1.6");
4353
4354        // three digit (non-zero major)
4355        let mut version = "5.3.6".parse::<Version>().unwrap();
4356        version.bump(BumpCommand::BumpRelease {
4357            index: 1,
4358            value: None,
4359        });
4360        assert_eq!(version.to_string().as_str(), "5.4.0");
4361
4362        // four digit
4363        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4364        version.bump(BumpCommand::BumpRelease {
4365            index: 1,
4366            value: None,
4367        });
4368        assert_eq!(version.to_string().as_str(), "1.3.0.0");
4369
4370        // All the version junk
4371        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4372            .parse::<Version>()
4373            .unwrap();
4374        version.bump(BumpCommand::BumpRelease {
4375            index: 1,
4376            value: None,
4377        });
4378        assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4379        version.bump(BumpCommand::BumpRelease {
4380            index: 1,
4381            value: None,
4382        });
4383        assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4384    }
4385
4386    /// Test patch bumping
4387    /// Explicitly using the string display because we want to preserve formatting where possible!
4388    #[test]
4389    fn bump_patch() {
4390        // one digit
4391        let mut version = "0".parse::<Version>().unwrap();
4392        version.bump(BumpCommand::BumpRelease {
4393            index: 2,
4394            value: None,
4395        });
4396        assert_eq!(version.to_string().as_str(), "0.0.1");
4397
4398        // two digit
4399        let mut version = "1.5".parse::<Version>().unwrap();
4400        version.bump(BumpCommand::BumpRelease {
4401            index: 2,
4402            value: None,
4403        });
4404        assert_eq!(version.to_string().as_str(), "1.5.1");
4405
4406        // three digit
4407        let mut version = "5.3.6".parse::<Version>().unwrap();
4408        version.bump(BumpCommand::BumpRelease {
4409            index: 2,
4410            value: None,
4411        });
4412        assert_eq!(version.to_string().as_str(), "5.3.7");
4413
4414        // four digit
4415        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4416        version.bump(BumpCommand::BumpRelease {
4417            index: 2,
4418            value: None,
4419        });
4420        assert_eq!(version.to_string().as_str(), "1.2.4.0");
4421
4422        // All the version junk
4423        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4424            .parse::<Version>()
4425            .unwrap();
4426        version.bump(BumpCommand::BumpRelease {
4427            index: 2,
4428            value: None,
4429        });
4430        assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4431        version.bump(BumpCommand::BumpRelease {
4432            index: 2,
4433            value: None,
4434        });
4435        assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4436    }
4437
4438    /// Test alpha bumping
4439    /// Explicitly using the string display because we want to preserve formatting where possible!
4440    #[test]
4441    fn bump_alpha() {
4442        // one digit
4443        let mut version = "0".parse::<Version>().unwrap();
4444        version.bump(BumpCommand::BumpPrerelease {
4445            kind: PrereleaseKind::Alpha,
4446            value: None,
4447        });
4448        assert_eq!(version.to_string().as_str(), "0a1");
4449
4450        // two digit
4451        let mut version = "1.5".parse::<Version>().unwrap();
4452        version.bump(BumpCommand::BumpPrerelease {
4453            kind: PrereleaseKind::Alpha,
4454            value: None,
4455        });
4456        assert_eq!(version.to_string().as_str(), "1.5a1");
4457
4458        // three digit
4459        let mut version = "5.3.6".parse::<Version>().unwrap();
4460        version.bump(BumpCommand::BumpPrerelease {
4461            kind: PrereleaseKind::Alpha,
4462            value: None,
4463        });
4464        assert_eq!(version.to_string().as_str(), "5.3.6a1");
4465
4466        // four digit
4467        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4468        version.bump(BumpCommand::BumpPrerelease {
4469            kind: PrereleaseKind::Alpha,
4470            value: None,
4471        });
4472        assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4473
4474        // All the version junk
4475        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4476            .parse::<Version>()
4477            .unwrap();
4478        version.bump(BumpCommand::BumpPrerelease {
4479            kind: PrereleaseKind::Alpha,
4480            value: None,
4481        });
4482        assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4483        version.bump(BumpCommand::BumpPrerelease {
4484            kind: PrereleaseKind::Alpha,
4485            value: None,
4486        });
4487        assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4488    }
4489
4490    /// Test beta bumping
4491    /// Explicitly using the string display because we want to preserve formatting where possible!
4492    #[test]
4493    fn bump_beta() {
4494        // one digit
4495        let mut version = "0".parse::<Version>().unwrap();
4496        version.bump(BumpCommand::BumpPrerelease {
4497            kind: PrereleaseKind::Beta,
4498            value: None,
4499        });
4500        assert_eq!(version.to_string().as_str(), "0b1");
4501
4502        // two digit
4503        let mut version = "1.5".parse::<Version>().unwrap();
4504        version.bump(BumpCommand::BumpPrerelease {
4505            kind: PrereleaseKind::Beta,
4506            value: None,
4507        });
4508        assert_eq!(version.to_string().as_str(), "1.5b1");
4509
4510        // three digit
4511        let mut version = "5.3.6".parse::<Version>().unwrap();
4512        version.bump(BumpCommand::BumpPrerelease {
4513            kind: PrereleaseKind::Beta,
4514            value: None,
4515        });
4516        assert_eq!(version.to_string().as_str(), "5.3.6b1");
4517
4518        // four digit
4519        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4520        version.bump(BumpCommand::BumpPrerelease {
4521            kind: PrereleaseKind::Beta,
4522            value: None,
4523        });
4524        assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4525
4526        // All the version junk
4527        let mut version = "5!1.7.3.5a2.post345.dev456+local"
4528            .parse::<Version>()
4529            .unwrap();
4530        version.bump(BumpCommand::BumpPrerelease {
4531            kind: PrereleaseKind::Beta,
4532            value: None,
4533        });
4534        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4535        version.bump(BumpCommand::BumpPrerelease {
4536            kind: PrereleaseKind::Beta,
4537            value: None,
4538        });
4539        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4540    }
4541
4542    /// Test rc bumping
4543    /// Explicitly using the string display because we want to preserve formatting where possible!
4544    #[test]
4545    fn bump_rc() {
4546        // one digit
4547        let mut version = "0".parse::<Version>().unwrap();
4548        version.bump(BumpCommand::BumpPrerelease {
4549            kind: PrereleaseKind::Rc,
4550            value: None,
4551        });
4552        assert_eq!(version.to_string().as_str(), "0rc1");
4553
4554        // two digit
4555        let mut version = "1.5".parse::<Version>().unwrap();
4556        version.bump(BumpCommand::BumpPrerelease {
4557            kind: PrereleaseKind::Rc,
4558            value: None,
4559        });
4560        assert_eq!(version.to_string().as_str(), "1.5rc1");
4561
4562        // three digit
4563        let mut version = "5.3.6".parse::<Version>().unwrap();
4564        version.bump(BumpCommand::BumpPrerelease {
4565            kind: PrereleaseKind::Rc,
4566            value: None,
4567        });
4568        assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4569
4570        // four digit
4571        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4572        version.bump(BumpCommand::BumpPrerelease {
4573            kind: PrereleaseKind::Rc,
4574            value: None,
4575        });
4576        assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4577
4578        // All the version junk
4579        let mut version = "5!1.7.3.5b2.post345.dev456+local"
4580            .parse::<Version>()
4581            .unwrap();
4582        version.bump(BumpCommand::BumpPrerelease {
4583            kind: PrereleaseKind::Rc,
4584            value: None,
4585        });
4586        assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4587        version.bump(BumpCommand::BumpPrerelease {
4588            kind: PrereleaseKind::Rc,
4589            value: None,
4590        });
4591        assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4592    }
4593
4594    /// Test post bumping
4595    /// Explicitly using the string display because we want to preserve formatting where possible!
4596    #[test]
4597    fn bump_post() {
4598        // one digit
4599        let mut version = "0".parse::<Version>().unwrap();
4600        version.bump(BumpCommand::BumpPost { value: None });
4601        assert_eq!(version.to_string().as_str(), "0.post1");
4602
4603        // two digit
4604        let mut version = "1.5".parse::<Version>().unwrap();
4605        version.bump(BumpCommand::BumpPost { value: None });
4606        assert_eq!(version.to_string().as_str(), "1.5.post1");
4607
4608        // three digit
4609        let mut version = "5.3.6".parse::<Version>().unwrap();
4610        version.bump(BumpCommand::BumpPost { value: None });
4611        assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4612
4613        // four digit
4614        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4615        version.bump(BumpCommand::BumpPost { value: None });
4616        assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4617
4618        // All the version junk
4619        let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4620        version.bump(BumpCommand::BumpPost { value: None });
4621        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4622        version.bump(BumpCommand::BumpPost { value: None });
4623        assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4624    }
4625
4626    /// Test dev bumping
4627    /// Explicitly using the string display because we want to preserve formatting where possible!
4628    #[test]
4629    fn bump_dev() {
4630        // one digit
4631        let mut version = "0".parse::<Version>().unwrap();
4632        version.bump(BumpCommand::BumpDev { value: None });
4633        assert_eq!(version.to_string().as_str(), "0.dev1");
4634
4635        // two digit
4636        let mut version = "1.5".parse::<Version>().unwrap();
4637        version.bump(BumpCommand::BumpDev { value: None });
4638        assert_eq!(version.to_string().as_str(), "1.5.dev1");
4639
4640        // three digit
4641        let mut version = "5.3.6".parse::<Version>().unwrap();
4642        version.bump(BumpCommand::BumpDev { value: None });
4643        assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4644
4645        // four digit
4646        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4647        version.bump(BumpCommand::BumpDev { value: None });
4648        assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4649
4650        // All the version junk
4651        let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4652        version.bump(BumpCommand::BumpDev { value: None });
4653        assert_eq!(
4654            version.to_string().as_str(),
4655            "5!1.7.3.5b2.post345.dev1+local"
4656        );
4657        version.bump(BumpCommand::BumpDev { value: None });
4658        assert_eq!(
4659            version.to_string().as_str(),
4660            "5!1.7.3.5b2.post345.dev2+local"
4661        );
4662    }
4663
4664    /// Test stable setting
4665    /// Explicitly using the string display because we want to preserve formatting where possible!
4666    #[test]
4667    fn make_stable() {
4668        // one digit
4669        let mut version = "0".parse::<Version>().unwrap();
4670        version.bump(BumpCommand::MakeStable);
4671        assert_eq!(version.to_string().as_str(), "0");
4672
4673        // two digit
4674        let mut version = "1.5".parse::<Version>().unwrap();
4675        version.bump(BumpCommand::MakeStable);
4676        assert_eq!(version.to_string().as_str(), "1.5");
4677
4678        // three digit
4679        let mut version = "5.3.6".parse::<Version>().unwrap();
4680        version.bump(BumpCommand::MakeStable);
4681        assert_eq!(version.to_string().as_str(), "5.3.6");
4682
4683        // four digit
4684        let mut version = "1.2.3.4".parse::<Version>().unwrap();
4685        version.bump(BumpCommand::MakeStable);
4686        assert_eq!(version.to_string().as_str(), "1.2.3.4");
4687
4688        // All the version junk
4689        let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4690        version.bump(BumpCommand::MakeStable);
4691        assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4692        version.bump(BumpCommand::MakeStable);
4693        assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4694    }
4695}