Skip to main content

uv_pep440/
version.rs

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