uv_pep440/
version.rs

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