Skip to main content

uv_pep440/
version.rs

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