Skip to main content

uv_pep440/
version.rs

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