Skip to main content

uv_pep440/
version.rs

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