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#[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 Equal,
25 EqualStar,
27 ExactEqual,
34 NotEqual,
36 NotEqualStar,
38 TildeEqual,
42 LessThan,
44 LessThanEqual,
46 GreaterThan,
48 GreaterThanEqual,
50}
51
52impl Operator {
53 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 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 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 pub fn is_star(self) -> bool {
116 matches!(self, Self::EqualStar | Self::NotEqualStar)
117 }
118
119 pub fn as_str(self) -> &'static str {
121 match self {
122 Self::Equal => "==",
123 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 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 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#[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#[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 #[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 #[inline]
315 pub fn any_prerelease(&self) -> bool {
316 self.is_pre() || self.is_dev()
317 }
318
319 #[inline]
321 pub fn is_stable(&self) -> bool {
322 !self.is_pre() && !self.is_dev()
323 }
324
325 #[inline]
327 pub fn is_pre(&self) -> bool {
328 self.pre().is_some()
329 }
330
331 #[inline]
333 pub fn is_dev(&self) -> bool {
334 self.dev().is_some()
335 }
336
337 #[inline]
339 pub fn is_post(&self) -> bool {
340 self.post().is_some()
341 }
342
343 #[inline]
348 pub fn is_local(&self) -> bool {
349 !self.local().is_empty()
350 }
351
352 #[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 #[inline]
363 pub fn release(&self) -> Release<'_> {
364 let inner = match &self.inner {
365 VersionInner::Small { small } => {
366 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 #[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 #[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 #[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 #[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 #[inline]
439 fn min(&self) -> Option<u64> {
440 match self.inner {
441 VersionInner::Small { ref small } => small.min(),
442 VersionInner::Full { ref full } => full.min,
443 }
444 }
445
446 #[inline]
452 fn max(&self) -> Option<u64> {
453 match self.inner {
454 VersionInner::Small { ref small } => small.max(),
455 VersionInner::Full { ref full } => full.max,
456 }
457 }
458
459 #[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 #[inline]
492 #[must_use]
493 pub fn only_release_at_precision(&self, precision: usize) -> Option<Self> {
494 let release = self
495 .release()
496 .iter()
497 .copied()
498 .chain(std::iter::repeat(0))
499 .take(precision)
500 .collect::<Vec<_>>();
501 (!release.is_empty()).then(|| Self::new(release).with_epoch(self.epoch()))
502 }
503
504 #[inline]
507 fn push_release(&mut self, n: u64) {
508 if let VersionInner::Small { small } = &mut self.inner {
509 if small.push_release(n) {
510 return;
511 }
512 }
513 self.make_full().release.push(n);
514 }
515
516 #[inline]
521 fn clear_release(&mut self) {
522 match &mut self.inner {
523 VersionInner::Small { small } => small.clear_release(),
524 VersionInner::Full { full } => {
525 Arc::make_mut(full).release.clear();
526 }
527 }
528 }
529
530 #[inline]
532 #[must_use]
533 pub(crate) fn with_epoch(mut self, value: u64) -> Self {
534 if let VersionInner::Small { small } = &mut self.inner {
535 if small.set_epoch(value) {
536 return self;
537 }
538 }
539 self.make_full().epoch = value;
540 self
541 }
542
543 #[inline]
545 #[must_use]
546 pub fn with_pre(mut self, value: Option<Prerelease>) -> Self {
547 if let VersionInner::Small { small } = &mut self.inner {
548 if small.set_pre(value) {
549 return self;
550 }
551 }
552 self.make_full().pre = value;
553 self
554 }
555
556 #[inline]
558 #[must_use]
559 pub fn with_post(mut self, value: Option<u64>) -> Self {
560 if let VersionInner::Small { small } = &mut self.inner {
561 if small.set_post(value) {
562 return self;
563 }
564 }
565 self.make_full().post = value;
566 self
567 }
568
569 #[inline]
571 #[must_use]
572 pub(crate) fn with_dev(mut self, value: Option<u64>) -> Self {
573 if let VersionInner::Small { small } = &mut self.inner {
574 if small.set_dev(value) {
575 return self;
576 }
577 }
578 self.make_full().dev = value;
579 self
580 }
581
582 #[inline]
584 #[must_use]
585 pub(crate) fn with_local_segments(mut self, value: Vec<LocalSegment>) -> Self {
586 if value.is_empty() {
587 self.without_local()
588 } else {
589 self.make_full().local = LocalVersion::Segments(value);
590 self
591 }
592 }
593
594 #[inline]
596 #[must_use]
597 pub(crate) fn with_local(mut self, value: LocalVersion) -> Self {
598 match value {
599 LocalVersion::Segments(segments) => self.with_local_segments(segments),
600 LocalVersion::Max => {
601 if let VersionInner::Small { small } = &mut self.inner {
602 if small.set_local(LocalVersion::Max) {
603 return self;
604 }
605 }
606 self.make_full().local = value;
607 self
608 }
609 }
610 }
611
612 #[inline]
617 #[must_use]
618 pub fn without_local(mut self) -> Self {
619 if let VersionInner::Small { small } = &mut self.inner {
620 if small.set_local(LocalVersion::empty()) {
621 return self;
622 }
623 }
624 self.make_full().local = LocalVersion::empty();
625 self
626 }
627
628 #[inline]
630 #[must_use]
631 pub fn only_release(&self) -> Self {
632 Self::new(self.release().iter().copied())
633 }
634
635 #[inline]
637 #[must_use]
638 pub(crate) fn only_minor_release(&self) -> Self {
639 Self::new(self.release().iter().take(2).copied())
640 }
641
642 #[inline]
645 #[must_use]
646 pub fn only_release_trimmed(&self) -> Self {
647 if let Some(last_non_zero) = self.release().iter().rposition(|segment| *segment != 0) {
648 if last_non_zero + 1 == self.release().len()
649 && self.epoch() == 0
650 && self.pre().is_none()
651 && self.post().is_none()
652 && self.dev().is_none()
653 && self.local().is_empty()
654 && self.min().is_none()
655 && self.max().is_none()
656 {
657 self.clone()
659 } else {
660 Self::new(self.release().iter().take(last_non_zero + 1).copied())
661 }
662 } else {
663 Self::new([0])
665 }
666 }
667
668 #[inline]
674 #[must_use]
675 pub fn without_trailing_zeros(self) -> Self {
676 let mut release = self.release().to_vec();
677 while let Some(0) = release.last() {
678 release.pop();
679 }
680 self.with_release(release)
681 }
682
683 pub fn bump(&mut self, bump: BumpCommand) {
685 let full = self.make_full();
702
703 match bump {
704 BumpCommand::BumpRelease { index, value } => {
705 full.pre = None;
707 full.post = None;
708 full.dev = None;
709
710 let old_parts = &full.release;
712 let len = old_parts.len().max(index + 1);
713 let new_release_vec = (0..len)
714 .map(|i| match i.cmp(&index) {
715 Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
717 Ordering::Equal => {
719 value.unwrap_or_else(|| old_parts.get(i).copied().unwrap_or(0) + 1)
720 }
721 Ordering::Greater => 0,
723 })
724 .collect::<Vec<u64>>();
725 full.release = new_release_vec;
726 }
727 BumpCommand::MakeStable => {
728 full.pre = None;
730 full.post = None;
731 full.dev = None;
732 }
733 BumpCommand::BumpPrerelease { kind, value } => {
734 full.post = None;
736 full.dev = None;
737 if let Some(value) = value {
738 full.pre = Some(Prerelease {
739 kind,
740 number: value,
741 });
742 } else {
743 if let Some(prerelease) = &mut full.pre {
745 if prerelease.kind == kind {
746 prerelease.number += 1;
747 return;
748 }
749 }
750 full.pre = Some(Prerelease { kind, number: 1 });
751 }
752 }
753 BumpCommand::BumpPost { value } => {
754 full.dev = None;
756 if let Some(value) = value {
757 full.post = Some(value);
758 } else {
759 if let Some(post) = &mut full.post {
761 *post += 1;
762 } else {
763 full.post = Some(1);
764 }
765 }
766 }
767 BumpCommand::BumpDev { value } => {
768 if let Some(value) = value {
769 full.dev = Some(value);
770 } else {
771 if let Some(dev) = &mut full.dev {
773 *dev += 1;
774 } else {
775 full.dev = Some(1);
776 }
777 }
778 }
779 }
780 }
781
782 #[inline]
788 #[must_use]
789 pub fn with_min(mut self, value: Option<u64>) -> Self {
790 debug_assert!(!self.is_pre(), "min is not allowed on pre-release versions");
791 debug_assert!(!self.is_dev(), "min is not allowed on dev versions");
792 if let VersionInner::Small { small } = &mut self.inner {
793 if small.set_min(value) {
794 return self;
795 }
796 }
797 self.make_full().min = value;
798 self
799 }
800
801 #[inline]
807 #[must_use]
808 pub fn with_max(mut self, value: Option<u64>) -> Self {
809 debug_assert!(
810 !self.is_post(),
811 "max is not allowed on post-release versions"
812 );
813 debug_assert!(!self.is_dev(), "max is not allowed on dev versions");
814 if let VersionInner::Small { small } = &mut self.inner {
815 if small.set_max(value) {
816 return self;
817 }
818 }
819 self.make_full().max = value;
820 self
821 }
822
823 fn make_full(&mut self) -> &mut VersionFull {
826 if let VersionInner::Small { ref small } = self.inner {
827 let full = VersionFull {
828 epoch: small.epoch(),
829 release: self.release().to_vec(),
830 min: small.min(),
831 max: small.max(),
832 pre: small.pre(),
833 post: small.post(),
834 dev: small.dev(),
835 local: small.local(),
836 };
837 *self = Self {
838 inner: VersionInner::Full {
839 full: Arc::new(full),
840 },
841 };
842 }
843 match &mut self.inner {
844 VersionInner::Full { full } => Arc::make_mut(full),
845 VersionInner::Small { .. } => unreachable!(),
846 }
847 }
848
849 #[cold]
856 #[inline(never)]
857 fn cmp_slow(&self, other: &Self) -> Ordering {
858 match self.epoch().cmp(&other.epoch()) {
859 Ordering::Less => {
860 return Ordering::Less;
861 }
862 Ordering::Equal => {}
863 Ordering::Greater => {
864 return Ordering::Greater;
865 }
866 }
867
868 match compare_release(&self.release(), &other.release()) {
869 Ordering::Less => {
870 return Ordering::Less;
871 }
872 Ordering::Equal => {}
873 Ordering::Greater => {
874 return Ordering::Greater;
875 }
876 }
877
878 sortable_tuple(self).cmp(&sortable_tuple(other))
880 }
881}
882
883impl<'de> Deserialize<'de> for Version {
884 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
885 where
886 D: Deserializer<'de>,
887 {
888 struct Visitor;
889
890 impl de::Visitor<'_> for Visitor {
891 type Value = Version;
892
893 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
894 f.write_str("a string")
895 }
896
897 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
898 Version::from_str(v).map_err(de::Error::custom)
899 }
900 }
901
902 deserializer.deserialize_str(Visitor)
903 }
904}
905
906impl Serialize for Version {
908 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
909 where
910 S: Serializer,
911 {
912 serializer.collect_str(self)
913 }
914}
915
916impl std::fmt::Display for Version {
918 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
919 if self.epoch() != 0 {
920 write!(f, "{}!", self.epoch())?;
921 }
922 let release = self.release();
923 let mut release_iter = release.iter();
924 if let Some(first) = release_iter.next() {
925 write!(f, "{first}")?;
926 for n in release_iter {
927 write!(f, ".{n}")?;
928 }
929 }
930
931 if let Some(Prerelease { kind, number }) = self.pre() {
932 write!(f, "{kind}{number}")?;
933 }
934 if let Some(post) = self.post() {
935 write!(f, ".post{post}")?;
936 }
937 if let Some(dev) = self.dev() {
938 write!(f, ".dev{dev}")?;
939 }
940 if !self.local().is_empty() {
941 match self.local() {
942 LocalVersionSlice::Segments(_) => {
943 write!(f, "+{}", self.local())?;
944 }
945 LocalVersionSlice::Max => {
946 write!(f, "+")?;
947 }
948 }
949 }
950 Ok(())
951 }
952}
953
954impl std::fmt::Debug for Version {
955 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
956 write!(f, "\"{self}\"")
957 }
958}
959
960impl PartialEq<Self> for Version {
961 #[inline]
962 fn eq(&self, other: &Self) -> bool {
963 self.cmp(other) == Ordering::Equal
964 }
965}
966
967impl Eq for Version {}
968
969impl Hash for Version {
970 #[inline]
972 fn hash<H: Hasher>(&self, state: &mut H) {
973 self.epoch().hash(state);
974 for i in self.release().iter().rev().skip_while(|x| **x == 0) {
976 i.hash(state);
977 }
978 self.pre().hash(state);
979 self.dev().hash(state);
980 self.post().hash(state);
981 self.local().hash(state);
982 }
983}
984
985impl CacheKey for Version {
986 fn cache_key(&self, state: &mut CacheKeyHasher) {
987 self.epoch().cache_key(state);
988
989 let release = self.release();
990 release.len().cache_key(state);
991 for segment in release.iter() {
992 segment.cache_key(state);
993 }
994
995 if let Some(pre) = self.pre() {
996 1u8.cache_key(state);
997 match pre.kind {
998 PrereleaseKind::Alpha => 0u8.cache_key(state),
999 PrereleaseKind::Beta => 1u8.cache_key(state),
1000 PrereleaseKind::Rc => 2u8.cache_key(state),
1001 }
1002 pre.number.cache_key(state);
1003 } else {
1004 0u8.cache_key(state);
1005 }
1006
1007 if let Some(post) = self.post() {
1008 1u8.cache_key(state);
1009 post.cache_key(state);
1010 } else {
1011 0u8.cache_key(state);
1012 }
1013
1014 if let Some(dev) = self.dev() {
1015 1u8.cache_key(state);
1016 dev.cache_key(state);
1017 } else {
1018 0u8.cache_key(state);
1019 }
1020
1021 self.local().cache_key(state);
1022 }
1023}
1024
1025impl PartialOrd<Self> for Version {
1026 #[inline]
1027 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1028 Some(self.cmp(other))
1029 }
1030}
1031
1032impl Ord for Version {
1033 #[inline]
1037 fn cmp(&self, other: &Self) -> Ordering {
1038 match (&self.inner, &other.inner) {
1039 (VersionInner::Small { small: small1 }, VersionInner::Small { small: small2 }) => {
1040 small1.repr.cmp(&small2.repr)
1041 }
1042 _ => self.cmp_slow(other),
1043 }
1044 }
1045}
1046
1047impl FromStr for Version {
1048 type Err = VersionParseError;
1049
1050 fn from_str(version: &str) -> Result<Self, Self::Err> {
1054 Parser::new(version.as_bytes()).parse()
1055 }
1056}
1057
1058#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
1060pub enum BumpCommand {
1061 BumpRelease {
1063 index: usize,
1065 value: Option<u64>,
1067 },
1068 BumpPrerelease {
1070 kind: PrereleaseKind,
1072 value: Option<u64>,
1074 },
1075 MakeStable,
1077 BumpPost {
1079 value: Option<u64>,
1081 },
1082 BumpDev {
1084 value: Option<u64>,
1086 },
1087}
1088
1089#[derive(Clone, Debug)]
1164#[cfg_attr(
1165 feature = "rkyv",
1166 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1167)]
1168#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1169struct VersionSmall {
1170 len: u8,
1175 repr: u64,
1177 _force_niche: NonZero<u8>,
1179}
1180
1181impl VersionSmall {
1182 const SUFFIX_MIN: u64 = 0;
1197 const SUFFIX_DEV: u64 = 1;
1198 const SUFFIX_PRE_ALPHA: u64 = 2;
1199 const SUFFIX_PRE_BETA: u64 = 3;
1200 const SUFFIX_PRE_RC: u64 = 4;
1201 const SUFFIX_NONE: u64 = 5;
1202 const SUFFIX_LOCAL: u64 = 6;
1203 const SUFFIX_POST: u64 = 7;
1204 const SUFFIX_MAX: u64 = 8;
1205
1206 const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
1212 const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
1214 const SUFFIX_VERSION_BIT_LEN: u64 = 20;
1218 const SUFFIX_KIND_MASK: u64 = 0b1111;
1223
1224 #[inline]
1225 fn new() -> Self {
1226 Self {
1227 _force_niche: NonZero::<u8>::MIN,
1228 repr: Self::SUFFIX_NONE << Self::SUFFIX_VERSION_BIT_LEN,
1229 len: 0,
1230 }
1231 }
1232
1233 #[inline]
1234 #[expect(clippy::unused_self)]
1235 fn epoch(&self) -> u64 {
1236 0
1237 }
1238
1239 #[inline]
1240 #[expect(clippy::unused_self)]
1241 fn set_epoch(&mut self, value: u64) -> bool {
1242 if value != 0 {
1243 return false;
1244 }
1245 true
1246 }
1247
1248 #[inline]
1249 fn clear_release(&mut self) {
1250 self.repr &= !Self::SUFFIX_RELEASE_MASK;
1251 self.len = 0;
1252 }
1253
1254 #[inline]
1255 fn push_release(&mut self, n: u64) -> bool {
1256 if self.len == 0 {
1257 if n > u64::from(u16::MAX) {
1258 return false;
1259 }
1260 self.repr |= n << 48;
1261 self.len = 1;
1262 true
1263 } else {
1264 if n > u64::from(u8::MAX) {
1265 return false;
1266 }
1267 if self.len >= 4 {
1268 return false;
1269 }
1270 let shift = 48 - (usize::from(self.len) * 8);
1271 self.repr |= n << shift;
1272 self.len += 1;
1273 true
1274 }
1275 }
1276
1277 #[inline]
1278 fn post(&self) -> Option<u64> {
1279 if self.suffix_kind() == Self::SUFFIX_POST {
1280 Some(self.suffix_version())
1281 } else {
1282 None
1283 }
1284 }
1285
1286 #[inline]
1287 fn set_post(&mut self, value: Option<u64>) -> bool {
1288 let suffix_kind = self.suffix_kind();
1289 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1290 return value.is_none();
1291 }
1292 match value {
1293 None => {
1294 self.set_suffix_kind(Self::SUFFIX_NONE);
1295 }
1296 Some(number) => {
1297 if number > Self::SUFFIX_VERSION_MASK {
1298 return false;
1299 }
1300 self.set_suffix_kind(Self::SUFFIX_POST);
1301 self.set_suffix_version(number);
1302 }
1303 }
1304 true
1305 }
1306
1307 #[inline]
1308 fn pre(&self) -> Option<Prerelease> {
1309 let (kind, number) = (self.suffix_kind(), self.suffix_version());
1310 if kind == Self::SUFFIX_PRE_ALPHA {
1311 Some(Prerelease {
1312 kind: PrereleaseKind::Alpha,
1313 number,
1314 })
1315 } else if kind == Self::SUFFIX_PRE_BETA {
1316 Some(Prerelease {
1317 kind: PrereleaseKind::Beta,
1318 number,
1319 })
1320 } else if kind == Self::SUFFIX_PRE_RC {
1321 Some(Prerelease {
1322 kind: PrereleaseKind::Rc,
1323 number,
1324 })
1325 } else {
1326 None
1327 }
1328 }
1329
1330 #[inline]
1331 fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1332 let suffix_kind = self.suffix_kind();
1333 if !(suffix_kind == Self::SUFFIX_NONE
1334 || suffix_kind == Self::SUFFIX_PRE_ALPHA
1335 || suffix_kind == Self::SUFFIX_PRE_BETA
1336 || suffix_kind == Self::SUFFIX_PRE_RC)
1337 {
1338 return value.is_none();
1339 }
1340 match value {
1341 None => {
1342 self.set_suffix_kind(Self::SUFFIX_NONE);
1343 }
1344 Some(Prerelease { kind, number }) => {
1345 if number > Self::SUFFIX_VERSION_MASK {
1346 return false;
1347 }
1348 match kind {
1349 PrereleaseKind::Alpha => {
1350 self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1351 }
1352 PrereleaseKind::Beta => {
1353 self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1354 }
1355 PrereleaseKind::Rc => {
1356 self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1357 }
1358 }
1359 self.set_suffix_version(number);
1360 }
1361 }
1362 true
1363 }
1364
1365 #[inline]
1366 fn dev(&self) -> Option<u64> {
1367 if self.suffix_kind() == Self::SUFFIX_DEV {
1368 Some(self.suffix_version())
1369 } else {
1370 None
1371 }
1372 }
1373
1374 #[inline]
1375 fn set_dev(&mut self, value: Option<u64>) -> bool {
1376 let suffix_kind = self.suffix_kind();
1377 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1378 return value.is_none();
1379 }
1380 match value {
1381 None => {
1382 self.set_suffix_kind(Self::SUFFIX_NONE);
1383 }
1384 Some(number) => {
1385 if number > Self::SUFFIX_VERSION_MASK {
1386 return false;
1387 }
1388 self.set_suffix_kind(Self::SUFFIX_DEV);
1389 self.set_suffix_version(number);
1390 }
1391 }
1392 true
1393 }
1394
1395 #[inline]
1396 fn min(&self) -> Option<u64> {
1397 if self.suffix_kind() == Self::SUFFIX_MIN {
1398 Some(self.suffix_version())
1399 } else {
1400 None
1401 }
1402 }
1403
1404 #[inline]
1405 fn set_min(&mut self, value: Option<u64>) -> bool {
1406 let suffix_kind = self.suffix_kind();
1407 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1408 return value.is_none();
1409 }
1410 match value {
1411 None => {
1412 self.set_suffix_kind(Self::SUFFIX_NONE);
1413 }
1414 Some(number) => {
1415 if number > Self::SUFFIX_VERSION_MASK {
1416 return false;
1417 }
1418 self.set_suffix_kind(Self::SUFFIX_MIN);
1419 self.set_suffix_version(number);
1420 }
1421 }
1422 true
1423 }
1424
1425 #[inline]
1426 fn max(&self) -> Option<u64> {
1427 if self.suffix_kind() == Self::SUFFIX_MAX {
1428 Some(self.suffix_version())
1429 } else {
1430 None
1431 }
1432 }
1433
1434 #[inline]
1435 fn set_max(&mut self, value: Option<u64>) -> bool {
1436 let suffix_kind = self.suffix_kind();
1437 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1438 return value.is_none();
1439 }
1440 match value {
1441 None => {
1442 self.set_suffix_kind(Self::SUFFIX_NONE);
1443 }
1444 Some(number) => {
1445 if number > Self::SUFFIX_VERSION_MASK {
1446 return false;
1447 }
1448 self.set_suffix_kind(Self::SUFFIX_MAX);
1449 self.set_suffix_version(number);
1450 }
1451 }
1452 true
1453 }
1454
1455 #[inline]
1456 fn local(&self) -> LocalVersion {
1457 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1458 LocalVersion::Max
1459 } else {
1460 LocalVersion::empty()
1461 }
1462 }
1463
1464 #[inline]
1465 fn local_slice(&self) -> LocalVersionSlice<'_> {
1466 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1467 LocalVersionSlice::Max
1468 } else {
1469 LocalVersionSlice::empty()
1470 }
1471 }
1472
1473 #[inline]
1474 fn set_local(&mut self, value: LocalVersion) -> bool {
1475 let suffix_kind = self.suffix_kind();
1476 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1477 return value.is_empty();
1478 }
1479 match value {
1480 LocalVersion::Max => {
1481 self.set_suffix_kind(Self::SUFFIX_LOCAL);
1482 true
1483 }
1484 LocalVersion::Segments(segments) if segments.is_empty() => {
1485 self.set_suffix_kind(Self::SUFFIX_NONE);
1486 true
1487 }
1488 LocalVersion::Segments(_) => false,
1489 }
1490 }
1491
1492 #[inline]
1493 fn suffix_kind(&self) -> u64 {
1494 let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1495 debug_assert!(kind <= Self::SUFFIX_MAX);
1496 kind
1497 }
1498
1499 #[inline]
1500 fn set_suffix_kind(&mut self, kind: u64) {
1501 debug_assert!(kind <= Self::SUFFIX_MAX);
1502 self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1503 self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1504 if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1505 self.set_suffix_version(0);
1506 }
1507 }
1508
1509 #[inline]
1510 fn suffix_version(&self) -> u64 {
1511 self.repr & Self::SUFFIX_VERSION_MASK
1512 }
1513
1514 #[inline]
1515 fn set_suffix_version(&mut self, value: u64) {
1516 debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1517 self.repr &= !Self::SUFFIX_VERSION_MASK;
1518 self.repr |= value;
1519 }
1520}
1521
1522#[derive(Clone, Debug)]
1531#[cfg_attr(
1532 feature = "rkyv",
1533 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1534)]
1535#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1536struct VersionFull {
1537 epoch: u64,
1542 release: Vec<u64>,
1548 pre: Option<Prerelease>,
1554 post: Option<u64>,
1558 dev: Option<u64>,
1562 local: LocalVersion,
1575 min: Option<u64>,
1579 max: Option<u64>,
1583}
1584
1585#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1604pub struct VersionPattern {
1605 version: Version,
1606 wildcard: bool,
1607}
1608
1609impl VersionPattern {
1610 #[inline]
1613 pub fn verbatim(version: Version) -> Self {
1614 Self {
1615 version,
1616 wildcard: false,
1617 }
1618 }
1619
1620 #[inline]
1623 pub fn wildcard(version: Version) -> Self {
1624 Self {
1625 version,
1626 wildcard: true,
1627 }
1628 }
1629
1630 #[inline]
1632 pub fn version(&self) -> &Version {
1633 &self.version
1634 }
1635
1636 #[inline]
1638 pub(crate) fn into_version(self) -> Version {
1639 self.version
1640 }
1641
1642 #[inline]
1644 pub(crate) fn is_wildcard(&self) -> bool {
1645 self.wildcard
1646 }
1647}
1648
1649impl FromStr for VersionPattern {
1650 type Err = VersionPatternParseError;
1651
1652 fn from_str(version: &str) -> Result<Self, VersionPatternParseError> {
1653 Parser::new(version.as_bytes()).parse_pattern()
1654 }
1655}
1656
1657pub struct Release<'a> {
1662 inner: ReleaseInner<'a>,
1663}
1664
1665enum ReleaseInner<'a> {
1666 Small0([u64; 0]),
1670 Small1([u64; 1]),
1671 Small2([u64; 2]),
1672 Small3([u64; 3]),
1673 Small4([u64; 4]),
1674 Full(&'a [u64]),
1675}
1676
1677impl Deref for Release<'_> {
1678 type Target = [u64];
1679
1680 fn deref(&self) -> &Self::Target {
1681 match &self.inner {
1682 ReleaseInner::Small0(v) => v,
1683 ReleaseInner::Small1(v) => v,
1684 ReleaseInner::Small2(v) => v,
1685 ReleaseInner::Small3(v) => v,
1686 ReleaseInner::Small4(v) => v,
1687 ReleaseInner::Full(v) => v,
1688 }
1689 }
1690}
1691
1692#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1694#[cfg_attr(
1695 feature = "rkyv",
1696 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1697)]
1698#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1699pub struct Prerelease {
1700 pub kind: PrereleaseKind,
1702 pub number: u64,
1704}
1705
1706#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1710#[cfg_attr(
1711 feature = "rkyv",
1712 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1713)]
1714#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1715pub enum PrereleaseKind {
1716 Alpha,
1718 Beta,
1720 Rc,
1722}
1723
1724impl std::fmt::Display for PrereleaseKind {
1725 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1726 match self {
1727 Self::Alpha => write!(f, "a"),
1728 Self::Beta => write!(f, "b"),
1729 Self::Rc => write!(f, "rc"),
1730 }
1731 }
1732}
1733
1734impl std::fmt::Display for Prerelease {
1735 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1736 write!(f, "{}{}", self.kind, self.number)
1737 }
1738}
1739
1740#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1743#[cfg_attr(
1744 feature = "rkyv",
1745 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1746)]
1747#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1748pub enum LocalVersion {
1749 Segments(Vec<LocalSegment>),
1751 Max,
1753}
1754
1755#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1757pub enum LocalVersionSlice<'a> {
1758 Segments(&'a [LocalSegment]),
1760 Max,
1762}
1763
1764impl LocalVersion {
1765 fn empty() -> Self {
1767 Self::Segments(Vec::new())
1768 }
1769
1770 fn is_empty(&self) -> bool {
1772 match self {
1773 Self::Segments(segments) => segments.is_empty(),
1774 Self::Max => false,
1775 }
1776 }
1777
1778 fn as_slice(&self) -> LocalVersionSlice<'_> {
1780 match self {
1781 Self::Segments(segments) => LocalVersionSlice::Segments(segments),
1782 Self::Max => LocalVersionSlice::Max,
1783 }
1784 }
1785}
1786
1787impl std::fmt::Display for LocalVersionSlice<'_> {
1792 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1793 match self {
1794 Self::Segments(segments) => {
1795 for (i, segment) in segments.iter().enumerate() {
1796 if i > 0 {
1797 write!(f, ".")?;
1798 }
1799 write!(f, "{segment}")?;
1800 }
1801 Ok(())
1802 }
1803 Self::Max => write!(f, "[max]"),
1804 }
1805 }
1806}
1807
1808impl CacheKey for LocalVersionSlice<'_> {
1809 fn cache_key(&self, state: &mut CacheKeyHasher) {
1810 match self {
1811 Self::Segments(segments) => {
1812 0u8.cache_key(state);
1813 segments.len().cache_key(state);
1814 for segment in *segments {
1815 segment.cache_key(state);
1816 }
1817 }
1818 Self::Max => {
1819 1u8.cache_key(state);
1820 }
1821 }
1822 }
1823}
1824
1825impl PartialOrd for LocalVersionSlice<'_> {
1826 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1827 Some(self.cmp(other))
1828 }
1829}
1830
1831impl Ord for LocalVersionSlice<'_> {
1832 fn cmp(&self, other: &Self) -> Ordering {
1833 match (self, other) {
1834 (LocalVersionSlice::Segments(lv1), LocalVersionSlice::Segments(lv2)) => lv1.cmp(lv2),
1835 (LocalVersionSlice::Segments(_), LocalVersionSlice::Max) => Ordering::Less,
1836 (LocalVersionSlice::Max, LocalVersionSlice::Segments(_)) => Ordering::Greater,
1837 (LocalVersionSlice::Max, LocalVersionSlice::Max) => Ordering::Equal,
1838 }
1839 }
1840}
1841
1842impl LocalVersionSlice<'_> {
1843 const fn empty() -> Self {
1845 Self::Segments(&[])
1846 }
1847
1848 pub fn is_empty(&self) -> bool {
1850 matches!(self, &Self::Segments(&[]))
1851 }
1852}
1853
1854#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1870#[cfg_attr(
1871 feature = "rkyv",
1872 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1873)]
1874#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1875pub enum LocalSegment {
1876 String(String),
1878 Number(u64),
1880}
1881
1882impl std::fmt::Display for LocalSegment {
1883 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1884 match self {
1885 Self::String(string) => write!(f, "{string}"),
1886 Self::Number(number) => write!(f, "{number}"),
1887 }
1888 }
1889}
1890
1891impl CacheKey for LocalSegment {
1892 fn cache_key(&self, state: &mut CacheKeyHasher) {
1893 match self {
1894 Self::String(string) => {
1895 0u8.cache_key(state);
1896 string.cache_key(state);
1897 }
1898 Self::Number(number) => {
1899 1u8.cache_key(state);
1900 number.cache_key(state);
1901 }
1902 }
1903 }
1904}
1905
1906impl PartialOrd for LocalSegment {
1907 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1908 Some(self.cmp(other))
1909 }
1910}
1911
1912impl Ord for LocalSegment {
1913 fn cmp(&self, other: &Self) -> Ordering {
1914 match (self, other) {
1916 (Self::Number(n1), Self::Number(n2)) => n1.cmp(n2),
1917 (Self::String(s1), Self::String(s2)) => s1.cmp(s2),
1918 (Self::Number(_), Self::String(_)) => Ordering::Greater,
1919 (Self::String(_), Self::Number(_)) => Ordering::Less,
1920 }
1921 }
1922}
1923
1924#[derive(Debug)]
1934struct Parser<'a> {
1935 v: &'a [u8],
1937 i: usize,
1939 epoch: u64,
1941 release: ReleaseNumbers,
1943 pre: Option<Prerelease>,
1945 post: Option<u64>,
1947 dev: Option<u64>,
1949 local: Vec<LocalSegment>,
1951 wildcard: bool,
1955}
1956
1957impl<'a> Parser<'a> {
1958 #[expect(clippy::byte_char_slices)]
1961 const SEPARATOR: ByteSet = ByteSet::new(&[b'.', b'_', b'-']);
1962
1963 fn new(version: &'a [u8]) -> Self {
1965 Parser {
1966 v: version,
1967 i: 0,
1968 epoch: 0,
1969 release: ReleaseNumbers::new(),
1970 pre: None,
1971 post: None,
1972 dev: None,
1973 local: vec![],
1974 wildcard: false,
1975 }
1976 }
1977
1978 fn parse(self) -> Result<Version, VersionParseError> {
1982 match self.parse_pattern() {
1983 Ok(vpat) => {
1984 if vpat.is_wildcard() {
1985 Err(ErrorKind::Wildcard.into())
1986 } else {
1987 Ok(vpat.into_version())
1988 }
1989 }
1990 Err(err) => match *err.kind {
1997 PatternErrorKind::Version(err) => Err(err),
1998 PatternErrorKind::WildcardNotTrailing => Err(ErrorKind::Wildcard.into()),
1999 },
2000 }
2001 }
2002
2003 fn parse_pattern(mut self) -> Result<VersionPattern, VersionPatternParseError> {
2005 if let Some(vpat) = self.parse_fast() {
2006 return Ok(vpat);
2007 }
2008 self.bump_while(|byte| byte.is_ascii_whitespace());
2009 self.bump_if("v");
2010 self.parse_epoch_and_initial_release()?;
2011 self.parse_rest_of_release()?;
2012 if self.parse_wildcard()? {
2013 return Ok(self.into_pattern());
2014 }
2015 self.parse_pre()?;
2016 self.parse_post()?;
2017 self.parse_dev()?;
2018 self.parse_local()?;
2019 self.bump_while(|byte| byte.is_ascii_whitespace());
2020 if !self.is_done() {
2021 let version = String::from_utf8_lossy(&self.v[..self.i]).into_owned();
2022 let remaining = String::from_utf8_lossy(&self.v[self.i..]).into_owned();
2023 return Err(ErrorKind::UnexpectedEnd { version, remaining }.into());
2024 }
2025 Ok(self.into_pattern())
2026 }
2027
2028 fn parse_fast(&self) -> Option<VersionPattern> {
2038 let (mut prev_digit, mut cur, mut release, mut len) = (false, 0u8, [0u8; 4], 0u8);
2039 for &byte in self.v {
2040 if byte == b'.' {
2041 if !prev_digit {
2042 return None;
2043 }
2044 prev_digit = false;
2045 *release.get_mut(usize::from(len))? = cur;
2046 len += 1;
2047 cur = 0;
2048 } else {
2049 let digit = byte.checked_sub(b'0')?;
2050 if digit > 9 {
2051 return None;
2052 }
2053 prev_digit = true;
2054 cur = cur.checked_mul(10)?.checked_add(digit)?;
2055 }
2056 }
2057 if !prev_digit {
2058 return None;
2059 }
2060 *release.get_mut(usize::from(len))? = cur;
2061 len += 1;
2062 let small = VersionSmall {
2063 _force_niche: NonZero::<u8>::MIN,
2064 repr: (u64::from(release[0]) << 48)
2065 | (u64::from(release[1]) << 40)
2066 | (u64::from(release[2]) << 32)
2067 | (u64::from(release[3]) << 24)
2068 | (VersionSmall::SUFFIX_NONE << VersionSmall::SUFFIX_VERSION_BIT_LEN),
2069
2070 len,
2071 };
2072 let inner = VersionInner::Small { small };
2073 let version = Version { inner };
2074 Some(VersionPattern {
2075 version,
2076 wildcard: false,
2077 })
2078 }
2079
2080 fn parse_epoch_and_initial_release(&mut self) -> Result<(), VersionPatternParseError> {
2091 let first_number = self.parse_number()?.ok_or(ErrorKind::NoLeadingNumber)?;
2092 let first_release_number = if self.bump_if("!") {
2093 self.epoch = first_number;
2094 self.parse_number()?
2095 .ok_or(ErrorKind::NoLeadingReleaseNumber)?
2096 } else {
2097 first_number
2098 };
2099 self.release.push(first_release_number);
2100 Ok(())
2101 }
2102
2103 fn parse_rest_of_release(&mut self) -> Result<(), VersionPatternParseError> {
2114 while self.bump_if(".") {
2115 let Some(n) = self.parse_number()? else {
2116 self.unbump();
2117 break;
2118 };
2119 self.release.push(n);
2120 }
2121 Ok(())
2122 }
2123
2124 fn parse_wildcard(&mut self) -> Result<bool, VersionPatternParseError> {
2133 if !self.bump_if(".*") {
2134 return Ok(false);
2135 }
2136 if !self.is_done() {
2137 return Err(PatternErrorKind::WildcardNotTrailing.into());
2138 }
2139 self.wildcard = true;
2140 Ok(true)
2141 }
2142
2143 fn parse_pre(&mut self) -> Result<(), VersionPatternParseError> {
2149 const SPELLINGS: StringSet =
2158 StringSet::new(&["alpha", "beta", "preview", "pre", "rc", "a", "b", "c"]);
2159 const MAP: &[PrereleaseKind] = &[
2160 PrereleaseKind::Alpha,
2161 PrereleaseKind::Beta,
2162 PrereleaseKind::Rc,
2163 PrereleaseKind::Rc,
2164 PrereleaseKind::Rc,
2165 PrereleaseKind::Alpha,
2166 PrereleaseKind::Beta,
2167 PrereleaseKind::Rc,
2168 ];
2169
2170 let oldpos = self.i;
2171 self.bump_if_byte_set(&Parser::SEPARATOR);
2172 let Some(spelling) = self.bump_if_string_set(&SPELLINGS) else {
2173 self.reset(oldpos);
2178 return Ok(());
2179 };
2180 let kind = MAP[spelling];
2181 self.bump_if_byte_set(&Parser::SEPARATOR);
2182 let number = self.parse_number()?.unwrap_or(0);
2185 self.pre = Some(Prerelease { kind, number });
2186 Ok(())
2187 }
2188
2189 fn parse_post(&mut self) -> Result<(), VersionPatternParseError> {
2195 const SPELLINGS: StringSet = StringSet::new(&["post", "rev", "r"]);
2196
2197 let oldpos = self.i;
2198 if self.bump_if("-") {
2199 if let Some(n) = self.parse_number()? {
2200 self.post = Some(n);
2201 return Ok(());
2202 }
2203 self.reset(oldpos);
2204 }
2205 self.bump_if_byte_set(&Parser::SEPARATOR);
2206 if self.bump_if_string_set(&SPELLINGS).is_none() {
2207 self.reset(oldpos);
2211 return Ok(());
2212 }
2213 self.bump_if_byte_set(&Parser::SEPARATOR);
2214 self.post = Some(self.parse_number()?.unwrap_or(0));
2217 Ok(())
2218 }
2219
2220 fn parse_dev(&mut self) -> Result<(), VersionPatternParseError> {
2226 let oldpos = self.i;
2227 self.bump_if_byte_set(&Parser::SEPARATOR);
2228 if !self.bump_if("dev") {
2229 self.reset(oldpos);
2233 return Ok(());
2234 }
2235 self.bump_if_byte_set(&Parser::SEPARATOR);
2236 self.dev = Some(self.parse_number()?.unwrap_or(0));
2239 Ok(())
2240 }
2241
2242 fn parse_local(&mut self) -> Result<(), VersionPatternParseError> {
2250 if !self.bump_if("+") {
2251 return Ok(());
2252 }
2253 let mut precursor = '+';
2254 loop {
2255 let first = self.bump_while(|byte| byte.is_ascii_alphanumeric());
2256 if first.is_empty() {
2257 return Err(ErrorKind::LocalEmpty { precursor }.into());
2258 }
2259 self.local.push(if let Ok(number) = parse_u64(first) {
2260 LocalSegment::Number(number)
2261 } else {
2262 let string = String::from_utf8(first.to_ascii_lowercase())
2263 .expect("ASCII alphanumerics are always valid UTF-8");
2264 LocalSegment::String(string)
2265 });
2266 let Some(byte) = self.bump_if_byte_set(&Parser::SEPARATOR) else {
2267 break;
2268 };
2269 precursor = char::from(byte);
2270 }
2271 Ok(())
2272 }
2273
2274 fn parse_number(&mut self) -> Result<Option<u64>, VersionPatternParseError> {
2282 let digits = self.bump_while(|ch| ch.is_ascii_digit());
2283 if digits.is_empty() {
2284 return Ok(None);
2285 }
2286 let n = parse_u64(digits)?;
2287 if n == u64::MAX {
2293 return Err(ErrorKind::NumberTooBig {
2294 bytes: digits.to_vec(),
2295 }
2296 .into());
2297 }
2298 Ok(Some(n))
2299 }
2300
2301 fn into_pattern(self) -> VersionPattern {
2309 assert!(
2310 self.release.len() > 0,
2311 "version with no release numbers is invalid"
2312 );
2313 let version = Version::new(self.release.as_slice())
2314 .with_epoch(self.epoch)
2315 .with_pre(self.pre)
2316 .with_post(self.post)
2317 .with_dev(self.dev)
2318 .with_local(LocalVersion::Segments(self.local));
2319 VersionPattern {
2320 version,
2321 wildcard: self.wildcard,
2322 }
2323 }
2324
2325 fn bump_while(&mut self, mut predicate: impl FnMut(u8) -> bool) -> &'a [u8] {
2332 let start = self.i;
2333 while !self.is_done() && predicate(self.byte()) {
2334 self.i = self.i.saturating_add(1);
2335 }
2336 &self.v[start..self.i]
2337 }
2338
2339 fn bump_if(&mut self, string: &str) -> bool {
2344 if self.is_done() {
2345 return false;
2346 }
2347 if starts_with_ignore_ascii_case(string.as_bytes(), &self.v[self.i..]) {
2348 self.i = self
2349 .i
2350 .checked_add(string.len())
2351 .expect("valid offset because of prefix");
2352 true
2353 } else {
2354 false
2355 }
2356 }
2357
2358 fn bump_if_string_set(&mut self, set: &StringSet) -> Option<usize> {
2362 let index = set.starts_with(&self.v[self.i..])?;
2363 let found = &set.strings[index];
2364 self.i = self
2365 .i
2366 .checked_add(found.len())
2367 .expect("valid offset because of prefix");
2368 Some(index)
2369 }
2370
2371 fn bump_if_byte_set(&mut self, set: &ByteSet) -> Option<u8> {
2375 let found = set.starts_with(&self.v[self.i..])?;
2376 self.i = self
2377 .i
2378 .checked_add(1)
2379 .expect("valid offset because of prefix");
2380 Some(found)
2381 }
2382
2383 fn unbump(&mut self) {
2392 self.i = self.i.checked_sub(1).expect("not at beginning of input");
2393 }
2394
2395 fn reset(&mut self, offset: usize) {
2401 assert!(offset <= self.v.len());
2402 self.i = offset;
2403 }
2404
2405 fn byte(&self) -> u8 {
2411 self.v[self.i]
2412 }
2413
2414 fn is_done(&self) -> bool {
2416 self.i >= self.v.len()
2417 }
2418}
2419
2420#[derive(Debug)]
2424enum ReleaseNumbers {
2425 Inline { numbers: [u64; 4], len: usize },
2426 Vec(Vec<u64>),
2427}
2428
2429impl ReleaseNumbers {
2430 fn new() -> Self {
2432 Self::Inline {
2433 numbers: [0; 4],
2434 len: 0,
2435 }
2436 }
2437
2438 fn push(&mut self, n: u64) {
2441 match *self {
2442 Self::Inline {
2443 ref mut numbers,
2444 ref mut len,
2445 } => {
2446 assert!(*len <= 4);
2447 if *len == 4 {
2448 let mut numbers = numbers.to_vec();
2449 numbers.push(n);
2450 *self = Self::Vec(numbers.clone());
2451 } else {
2452 numbers[*len] = n;
2453 *len += 1;
2454 }
2455 }
2456 Self::Vec(ref mut numbers) => {
2457 numbers.push(n);
2458 }
2459 }
2460 }
2461
2462 fn len(&self) -> usize {
2464 self.as_slice().len()
2465 }
2466
2467 fn as_slice(&self) -> &[u64] {
2469 match self {
2470 Self::Inline { numbers, len } => &numbers[..*len],
2471 Self::Vec(vec) => vec,
2472 }
2473 }
2474}
2475
2476struct StringSet {
2481 first_byte: ByteSet,
2485 strings: &'static [&'static str],
2487}
2488
2489impl StringSet {
2490 const fn new(strings: &'static [&'static str]) -> Self {
2496 assert!(
2497 strings.len() <= 20,
2498 "only a small number of strings are supported"
2499 );
2500 let (mut firsts, mut firsts_len) = ([0u8; 20], 0);
2501 let mut i = 0;
2502 while i < strings.len() {
2503 assert!(
2504 !strings[i].is_empty(),
2505 "every string in set should be non-empty",
2506 );
2507 firsts[firsts_len] = strings[i].as_bytes()[0];
2508 firsts_len += 1;
2509 i += 1;
2510 }
2511 let first_byte = ByteSet::new(&firsts);
2512 Self {
2513 first_byte,
2514 strings,
2515 }
2516 }
2517
2518 fn starts_with(&self, haystack: &[u8]) -> Option<usize> {
2521 let first_byte = self.first_byte.starts_with(haystack)?;
2522 for (i, &string) in self.strings.iter().enumerate() {
2523 let bytes = string.as_bytes();
2524 if bytes[0].eq_ignore_ascii_case(&first_byte)
2525 && starts_with_ignore_ascii_case(bytes, haystack)
2526 {
2527 return Some(i);
2528 }
2529 }
2530 None
2531 }
2532}
2533
2534struct ByteSet {
2536 set: [bool; 256],
2537}
2538
2539impl ByteSet {
2540 const fn new(bytes: &[u8]) -> Self {
2542 let mut set = [false; 256];
2543 let mut i = 0;
2544 while i < bytes.len() {
2545 set[bytes[i].to_ascii_uppercase() as usize] = true;
2546 set[bytes[i].to_ascii_lowercase() as usize] = true;
2547 i += 1;
2548 }
2549 Self { set }
2550 }
2551
2552 fn starts_with(&self, haystack: &[u8]) -> Option<u8> {
2555 let byte = *haystack.first()?;
2556 if self.contains(byte) {
2557 Some(byte)
2558 } else {
2559 None
2560 }
2561 }
2562
2563 fn contains(&self, byte: u8) -> bool {
2565 self.set[usize::from(byte)]
2566 }
2567}
2568
2569impl std::fmt::Debug for ByteSet {
2570 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2571 let mut set = f.debug_set();
2572 for byte in 0..=255 {
2573 if self.contains(byte) {
2574 set.entry(&char::from(byte));
2575 }
2576 }
2577 set.finish()
2578 }
2579}
2580
2581#[derive(Clone, Debug, Eq, PartialEq)]
2583pub struct VersionParseError {
2584 kind: Box<ErrorKind>,
2585}
2586
2587impl std::error::Error for VersionParseError {}
2588
2589impl std::fmt::Display for VersionParseError {
2590 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2591 match *self.kind {
2592 ErrorKind::Wildcard => write!(f, "wildcards are not allowed in a version"),
2593 ErrorKind::InvalidDigit { got } if got.is_ascii() => {
2594 write!(f, "expected ASCII digit, but found {:?}", char::from(got))
2595 }
2596 ErrorKind::InvalidDigit { got } => {
2597 write!(
2598 f,
2599 "expected ASCII digit, but found non-ASCII byte \\x{got:02X}"
2600 )
2601 }
2602 ErrorKind::NumberTooBig { ref bytes } => {
2603 let string = match std::str::from_utf8(bytes) {
2604 Ok(v) => v,
2605 Err(err) => {
2606 std::str::from_utf8(&bytes[..err.valid_up_to()]).expect("valid UTF-8")
2607 }
2608 };
2609 write!(
2610 f,
2611 "expected number less than or equal to {}, \
2612 but number found in {string:?} exceeds it",
2613 u64::MAX - 1,
2614 )
2615 }
2616 ErrorKind::NoLeadingNumber => {
2617 write!(
2618 f,
2619 "expected version to start with a number, \
2620 but no leading ASCII digits were found"
2621 )
2622 }
2623 ErrorKind::NoLeadingReleaseNumber => {
2624 write!(
2625 f,
2626 "expected version to have a non-empty release component after an epoch, \
2627 but no ASCII digits after the epoch were found"
2628 )
2629 }
2630 ErrorKind::LocalEmpty { precursor } => {
2631 write!(
2632 f,
2633 "found a `{precursor}` indicating the start of a local \
2634 component in a version, but did not find any alphanumeric \
2635 ASCII segment following the `{precursor}`",
2636 )
2637 }
2638 ErrorKind::UnexpectedEnd {
2639 ref version,
2640 ref remaining,
2641 } => {
2642 write!(
2643 f,
2644 "after parsing `{version}`, found `{remaining}`, \
2645 which is not part of a valid version",
2646 )
2647 }
2648 }
2649 }
2650}
2651
2652#[derive(Clone, Debug, Eq, PartialEq)]
2654pub(crate) enum ErrorKind {
2655 Wildcard,
2658 InvalidDigit {
2660 got: u8,
2662 },
2663 NumberTooBig {
2665 bytes: Vec<u8>,
2668 },
2669 NoLeadingNumber,
2671 NoLeadingReleaseNumber,
2673 LocalEmpty {
2677 precursor: char,
2680 },
2681 UnexpectedEnd {
2684 version: String,
2686 remaining: String,
2688 },
2689}
2690
2691impl From<ErrorKind> for VersionParseError {
2692 fn from(kind: ErrorKind) -> Self {
2693 Self {
2694 kind: Box::new(kind),
2695 }
2696 }
2697}
2698
2699#[derive(Clone, Debug, Eq, PartialEq)]
2701pub struct VersionPatternParseError {
2702 kind: Box<PatternErrorKind>,
2703}
2704
2705impl std::error::Error for VersionPatternParseError {}
2706
2707impl std::fmt::Display for VersionPatternParseError {
2708 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2709 match *self.kind {
2710 PatternErrorKind::Version(ref err) => err.fmt(f),
2711 PatternErrorKind::WildcardNotTrailing => {
2712 write!(f, "wildcards in versions must be at the end")
2713 }
2714 }
2715 }
2716}
2717
2718#[derive(Clone, Debug, Eq, PartialEq)]
2720pub(crate) enum PatternErrorKind {
2721 Version(VersionParseError),
2722 WildcardNotTrailing,
2723}
2724
2725impl From<PatternErrorKind> for VersionPatternParseError {
2726 fn from(kind: PatternErrorKind) -> Self {
2727 Self {
2728 kind: Box::new(kind),
2729 }
2730 }
2731}
2732
2733impl From<ErrorKind> for VersionPatternParseError {
2734 fn from(kind: ErrorKind) -> Self {
2735 Self::from(VersionParseError::from(kind))
2736 }
2737}
2738
2739impl From<VersionParseError> for VersionPatternParseError {
2740 fn from(err: VersionParseError) -> Self {
2741 Self {
2742 kind: Box::new(PatternErrorKind::Version(err)),
2743 }
2744 }
2745}
2746
2747pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2750 if this.len() == other.len() {
2751 return this.cmp(other);
2752 }
2753 for (this, other) in this.iter().chain(std::iter::repeat(&0)).zip(
2756 other
2757 .iter()
2758 .chain(std::iter::repeat(&0))
2759 .take(this.len().max(other.len())),
2760 ) {
2761 match this.cmp(other) {
2762 Ordering::Less => {
2763 return Ordering::Less;
2764 }
2765 Ordering::Equal => {}
2766 Ordering::Greater => {
2767 return Ordering::Greater;
2768 }
2769 }
2770 }
2771 Ordering::Equal
2772}
2773
2774fn sortable_tuple(version: &Version) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2790 let post = if version.max().is_some() {
2792 Some(u64::MAX)
2793 } else {
2794 version.post()
2795 };
2796 match (version.pre(), post, version.dev(), version.min()) {
2797 (_pre, post, _dev, Some(n)) => (0, 0, post, n, version.local()),
2799 (None, None, Some(n), None) => (1, 0, None, n, version.local()),
2801 (
2803 Some(Prerelease {
2804 kind: PrereleaseKind::Alpha,
2805 number: n,
2806 }),
2807 post,
2808 dev,
2809 None,
2810 ) => (2, n, post, dev.unwrap_or(u64::MAX), version.local()),
2811 (
2813 Some(Prerelease {
2814 kind: PrereleaseKind::Beta,
2815 number: n,
2816 }),
2817 post,
2818 dev,
2819 None,
2820 ) => (3, n, post, dev.unwrap_or(u64::MAX), version.local()),
2821 (
2823 Some(Prerelease {
2824 kind: PrereleaseKind::Rc,
2825 number: n,
2826 }),
2827 post,
2828 dev,
2829 None,
2830 ) => (4, n, post, dev.unwrap_or(u64::MAX), version.local()),
2831 (None, None, None, None) => (5, 0, None, 0, version.local()),
2833 (None, Some(post), dev, None) => {
2835 (6, 0, Some(post), dev.unwrap_or(u64::MAX), version.local())
2836 }
2837 }
2838}
2839
2840fn starts_with_ignore_ascii_case(needle: &[u8], haystack: &[u8]) -> bool {
2843 needle.len() <= haystack.len()
2844 && std::iter::zip(needle, haystack).all(|(b1, b2)| b1.eq_ignore_ascii_case(b2))
2845}
2846
2847fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
2862 let mut n: u64 = 0;
2863 for &byte in bytes {
2864 let digit = match byte.checked_sub(b'0') {
2865 None => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2866 Some(digit) if digit > 9 => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2867 Some(digit) => {
2868 debug_assert!((0..=9).contains(&digit));
2869 u64::from(digit)
2870 }
2871 };
2872 n = n
2873 .checked_mul(10)
2874 .and_then(|n| n.checked_add(digit))
2875 .ok_or_else(|| ErrorKind::NumberTooBig {
2876 bytes: bytes.to_vec(),
2877 })?;
2878 }
2879 Ok(n)
2880}
2881
2882pub static MIN_VERSION: LazyLock<Version> =
2884 LazyLock::new(|| Version::from_str("0a0.dev0").unwrap());
2885
2886#[cfg(test)]
2887mod tests {
2888 use std::str::FromStr;
2889
2890 use crate::VersionSpecifier;
2891
2892 use super::*;
2893
2894 #[test]
2896 fn test_packaging_versions() {
2897 let versions = [
2898 ("1.0.dev456", Version::new([1, 0]).with_dev(Some(456))),
2900 (
2901 "1.0a1",
2902 Version::new([1, 0]).with_pre(Some(Prerelease {
2903 kind: PrereleaseKind::Alpha,
2904 number: 1,
2905 })),
2906 ),
2907 (
2908 "1.0a2.dev456",
2909 Version::new([1, 0])
2910 .with_pre(Some(Prerelease {
2911 kind: PrereleaseKind::Alpha,
2912 number: 2,
2913 }))
2914 .with_dev(Some(456)),
2915 ),
2916 (
2917 "1.0a12.dev456",
2918 Version::new([1, 0])
2919 .with_pre(Some(Prerelease {
2920 kind: PrereleaseKind::Alpha,
2921 number: 12,
2922 }))
2923 .with_dev(Some(456)),
2924 ),
2925 (
2926 "1.0a12",
2927 Version::new([1, 0]).with_pre(Some(Prerelease {
2928 kind: PrereleaseKind::Alpha,
2929 number: 12,
2930 })),
2931 ),
2932 (
2933 "1.0b1.dev456",
2934 Version::new([1, 0])
2935 .with_pre(Some(Prerelease {
2936 kind: PrereleaseKind::Beta,
2937 number: 1,
2938 }))
2939 .with_dev(Some(456)),
2940 ),
2941 (
2942 "1.0b2",
2943 Version::new([1, 0]).with_pre(Some(Prerelease {
2944 kind: PrereleaseKind::Beta,
2945 number: 2,
2946 })),
2947 ),
2948 (
2949 "1.0b2.post345.dev456",
2950 Version::new([1, 0])
2951 .with_pre(Some(Prerelease {
2952 kind: PrereleaseKind::Beta,
2953 number: 2,
2954 }))
2955 .with_dev(Some(456))
2956 .with_post(Some(345)),
2957 ),
2958 (
2959 "1.0b2.post345",
2960 Version::new([1, 0])
2961 .with_pre(Some(Prerelease {
2962 kind: PrereleaseKind::Beta,
2963 number: 2,
2964 }))
2965 .with_post(Some(345)),
2966 ),
2967 (
2968 "1.0b2-346",
2969 Version::new([1, 0])
2970 .with_pre(Some(Prerelease {
2971 kind: PrereleaseKind::Beta,
2972 number: 2,
2973 }))
2974 .with_post(Some(346)),
2975 ),
2976 (
2977 "1.0c1.dev456",
2978 Version::new([1, 0])
2979 .with_pre(Some(Prerelease {
2980 kind: PrereleaseKind::Rc,
2981 number: 1,
2982 }))
2983 .with_dev(Some(456)),
2984 ),
2985 (
2986 "1.0c1",
2987 Version::new([1, 0]).with_pre(Some(Prerelease {
2988 kind: PrereleaseKind::Rc,
2989 number: 1,
2990 })),
2991 ),
2992 (
2993 "1.0rc2",
2994 Version::new([1, 0]).with_pre(Some(Prerelease {
2995 kind: PrereleaseKind::Rc,
2996 number: 2,
2997 })),
2998 ),
2999 (
3000 "1.0c3",
3001 Version::new([1, 0]).with_pre(Some(Prerelease {
3002 kind: PrereleaseKind::Rc,
3003 number: 3,
3004 })),
3005 ),
3006 ("1.0", Version::new([1, 0])),
3007 (
3008 "1.0.post456.dev34",
3009 Version::new([1, 0]).with_post(Some(456)).with_dev(Some(34)),
3010 ),
3011 ("1.0.post456", Version::new([1, 0]).with_post(Some(456))),
3012 ("1.1.dev1", Version::new([1, 1]).with_dev(Some(1))),
3013 (
3014 "1.2+123abc",
3015 Version::new([1, 2])
3016 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3017 ),
3018 (
3019 "1.2+123abc456",
3020 Version::new([1, 2])
3021 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3022 ),
3023 (
3024 "1.2+abc",
3025 Version::new([1, 2])
3026 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3027 ),
3028 (
3029 "1.2+abc123",
3030 Version::new([1, 2])
3031 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3032 ),
3033 (
3034 "1.2+abc123def",
3035 Version::new([1, 2])
3036 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3037 ),
3038 (
3039 "1.2+1234.abc",
3040 Version::new([1, 2]).with_local_segments(vec![
3041 LocalSegment::Number(1234),
3042 LocalSegment::String("abc".to_string()),
3043 ]),
3044 ),
3045 (
3046 "1.2+123456",
3047 Version::new([1, 2]).with_local_segments(vec![LocalSegment::Number(123_456)]),
3048 ),
3049 (
3050 "1.2.r32+123456",
3051 Version::new([1, 2])
3052 .with_post(Some(32))
3053 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3054 ),
3055 (
3056 "1.2.rev33+123456",
3057 Version::new([1, 2])
3058 .with_post(Some(33))
3059 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3060 ),
3061 (
3063 "1!1.0.dev456",
3064 Version::new([1, 0]).with_epoch(1).with_dev(Some(456)),
3065 ),
3066 (
3067 "1!1.0a1",
3068 Version::new([1, 0])
3069 .with_epoch(1)
3070 .with_pre(Some(Prerelease {
3071 kind: PrereleaseKind::Alpha,
3072 number: 1,
3073 })),
3074 ),
3075 (
3076 "1!1.0a2.dev456",
3077 Version::new([1, 0])
3078 .with_epoch(1)
3079 .with_pre(Some(Prerelease {
3080 kind: PrereleaseKind::Alpha,
3081 number: 2,
3082 }))
3083 .with_dev(Some(456)),
3084 ),
3085 (
3086 "1!1.0a12.dev456",
3087 Version::new([1, 0])
3088 .with_epoch(1)
3089 .with_pre(Some(Prerelease {
3090 kind: PrereleaseKind::Alpha,
3091 number: 12,
3092 }))
3093 .with_dev(Some(456)),
3094 ),
3095 (
3096 "1!1.0a12",
3097 Version::new([1, 0])
3098 .with_epoch(1)
3099 .with_pre(Some(Prerelease {
3100 kind: PrereleaseKind::Alpha,
3101 number: 12,
3102 })),
3103 ),
3104 (
3105 "1!1.0b1.dev456",
3106 Version::new([1, 0])
3107 .with_epoch(1)
3108 .with_pre(Some(Prerelease {
3109 kind: PrereleaseKind::Beta,
3110 number: 1,
3111 }))
3112 .with_dev(Some(456)),
3113 ),
3114 (
3115 "1!1.0b2",
3116 Version::new([1, 0])
3117 .with_epoch(1)
3118 .with_pre(Some(Prerelease {
3119 kind: PrereleaseKind::Beta,
3120 number: 2,
3121 })),
3122 ),
3123 (
3124 "1!1.0b2.post345.dev456",
3125 Version::new([1, 0])
3126 .with_epoch(1)
3127 .with_pre(Some(Prerelease {
3128 kind: PrereleaseKind::Beta,
3129 number: 2,
3130 }))
3131 .with_post(Some(345))
3132 .with_dev(Some(456)),
3133 ),
3134 (
3135 "1!1.0b2.post345",
3136 Version::new([1, 0])
3137 .with_epoch(1)
3138 .with_pre(Some(Prerelease {
3139 kind: PrereleaseKind::Beta,
3140 number: 2,
3141 }))
3142 .with_post(Some(345)),
3143 ),
3144 (
3145 "1!1.0b2-346",
3146 Version::new([1, 0])
3147 .with_epoch(1)
3148 .with_pre(Some(Prerelease {
3149 kind: PrereleaseKind::Beta,
3150 number: 2,
3151 }))
3152 .with_post(Some(346)),
3153 ),
3154 (
3155 "1!1.0c1.dev456",
3156 Version::new([1, 0])
3157 .with_epoch(1)
3158 .with_pre(Some(Prerelease {
3159 kind: PrereleaseKind::Rc,
3160 number: 1,
3161 }))
3162 .with_dev(Some(456)),
3163 ),
3164 (
3165 "1!1.0c1",
3166 Version::new([1, 0])
3167 .with_epoch(1)
3168 .with_pre(Some(Prerelease {
3169 kind: PrereleaseKind::Rc,
3170 number: 1,
3171 })),
3172 ),
3173 (
3174 "1!1.0rc2",
3175 Version::new([1, 0])
3176 .with_epoch(1)
3177 .with_pre(Some(Prerelease {
3178 kind: PrereleaseKind::Rc,
3179 number: 2,
3180 })),
3181 ),
3182 (
3183 "1!1.0c3",
3184 Version::new([1, 0])
3185 .with_epoch(1)
3186 .with_pre(Some(Prerelease {
3187 kind: PrereleaseKind::Rc,
3188 number: 3,
3189 })),
3190 ),
3191 ("1!1.0", Version::new([1, 0]).with_epoch(1)),
3192 (
3193 "1!1.0.post456.dev34",
3194 Version::new([1, 0])
3195 .with_epoch(1)
3196 .with_post(Some(456))
3197 .with_dev(Some(34)),
3198 ),
3199 (
3200 "1!1.0.post456",
3201 Version::new([1, 0]).with_epoch(1).with_post(Some(456)),
3202 ),
3203 (
3204 "1!1.1.dev1",
3205 Version::new([1, 1]).with_epoch(1).with_dev(Some(1)),
3206 ),
3207 (
3208 "1!1.2+123abc",
3209 Version::new([1, 2])
3210 .with_epoch(1)
3211 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3212 ),
3213 (
3214 "1!1.2+123abc456",
3215 Version::new([1, 2])
3216 .with_epoch(1)
3217 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3218 ),
3219 (
3220 "1!1.2+abc",
3221 Version::new([1, 2])
3222 .with_epoch(1)
3223 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3224 ),
3225 (
3226 "1!1.2+abc123",
3227 Version::new([1, 2])
3228 .with_epoch(1)
3229 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3230 ),
3231 (
3232 "1!1.2+abc123def",
3233 Version::new([1, 2])
3234 .with_epoch(1)
3235 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3236 ),
3237 (
3238 "1!1.2+1234.abc",
3239 Version::new([1, 2]).with_epoch(1).with_local_segments(vec![
3240 LocalSegment::Number(1234),
3241 LocalSegment::String("abc".to_string()),
3242 ]),
3243 ),
3244 (
3245 "1!1.2+123456",
3246 Version::new([1, 2])
3247 .with_epoch(1)
3248 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3249 ),
3250 (
3251 "1!1.2.r32+123456",
3252 Version::new([1, 2])
3253 .with_epoch(1)
3254 .with_post(Some(32))
3255 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3256 ),
3257 (
3258 "1!1.2.rev33+123456",
3259 Version::new([1, 2])
3260 .with_epoch(1)
3261 .with_post(Some(33))
3262 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3263 ),
3264 (
3265 "98765!1.2.rev33+123456",
3266 Version::new([1, 2])
3267 .with_epoch(98765)
3268 .with_post(Some(33))
3269 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3270 ),
3271 ];
3272 for (string, structured) in versions {
3273 match Version::from_str(string) {
3274 Err(err) => {
3275 unreachable!(
3276 "expected {string:?} to parse as {structured:?}, but got {err:?}",
3277 structured = structured.as_bloated_debug(),
3278 )
3279 }
3280 Ok(v) => assert!(
3281 v == structured,
3282 "for {string:?}, expected {structured:?} but got {v:?}",
3283 structured = structured.as_bloated_debug(),
3284 v = v.as_bloated_debug(),
3285 ),
3286 }
3287 let spec = format!("=={string}");
3288 match VersionSpecifier::from_str(&spec) {
3289 Err(err) => {
3290 unreachable!(
3291 "expected version in {spec:?} to parse as {structured:?}, but got {err:?}",
3292 structured = structured.as_bloated_debug(),
3293 )
3294 }
3295 Ok(v) => assert!(
3296 v.version() == &structured,
3297 "for {string:?}, expected {structured:?} but got {v:?}",
3298 structured = structured.as_bloated_debug(),
3299 v = v.version.as_bloated_debug(),
3300 ),
3301 }
3302 }
3303 }
3304
3305 #[test]
3307 fn test_packaging_failures() {
3308 let versions = [
3309 "1.0+a+",
3311 "1.0++",
3312 "1.0+_foobar",
3313 "1.0+foo&asd",
3314 "1.0+1+1",
3315 "french toast",
3317 "==french toast",
3318 ];
3319 for version in versions {
3320 assert!(Version::from_str(version).is_err());
3321 assert!(VersionSpecifier::from_str(&format!("=={version}")).is_err());
3322 }
3323 }
3324
3325 #[test]
3326 fn test_equality_and_normalization() {
3327 let versions = [
3328 ("1.0dev", "1.0.dev0"),
3330 ("1.0.dev", "1.0.dev0"),
3331 ("1.0dev1", "1.0.dev1"),
3332 ("1.0dev", "1.0.dev0"),
3333 ("1.0-dev", "1.0.dev0"),
3334 ("1.0-dev1", "1.0.dev1"),
3335 ("1.0DEV", "1.0.dev0"),
3336 ("1.0.DEV", "1.0.dev0"),
3337 ("1.0DEV1", "1.0.dev1"),
3338 ("1.0DEV", "1.0.dev0"),
3339 ("1.0.DEV1", "1.0.dev1"),
3340 ("1.0-DEV", "1.0.dev0"),
3341 ("1.0-DEV1", "1.0.dev1"),
3342 ("1.0a", "1.0a0"),
3344 ("1.0.a", "1.0a0"),
3345 ("1.0.a1", "1.0a1"),
3346 ("1.0-a", "1.0a0"),
3347 ("1.0-a1", "1.0a1"),
3348 ("1.0alpha", "1.0a0"),
3349 ("1.0.alpha", "1.0a0"),
3350 ("1.0.alpha1", "1.0a1"),
3351 ("1.0-alpha", "1.0a0"),
3352 ("1.0-alpha1", "1.0a1"),
3353 ("1.0A", "1.0a0"),
3354 ("1.0.A", "1.0a0"),
3355 ("1.0.A1", "1.0a1"),
3356 ("1.0-A", "1.0a0"),
3357 ("1.0-A1", "1.0a1"),
3358 ("1.0ALPHA", "1.0a0"),
3359 ("1.0.ALPHA", "1.0a0"),
3360 ("1.0.ALPHA1", "1.0a1"),
3361 ("1.0-ALPHA", "1.0a0"),
3362 ("1.0-ALPHA1", "1.0a1"),
3363 ("1.0b", "1.0b0"),
3365 ("1.0.b", "1.0b0"),
3366 ("1.0.b1", "1.0b1"),
3367 ("1.0-b", "1.0b0"),
3368 ("1.0-b1", "1.0b1"),
3369 ("1.0beta", "1.0b0"),
3370 ("1.0.beta", "1.0b0"),
3371 ("1.0.beta1", "1.0b1"),
3372 ("1.0-beta", "1.0b0"),
3373 ("1.0-beta1", "1.0b1"),
3374 ("1.0B", "1.0b0"),
3375 ("1.0.B", "1.0b0"),
3376 ("1.0.B1", "1.0b1"),
3377 ("1.0-B", "1.0b0"),
3378 ("1.0-B1", "1.0b1"),
3379 ("1.0BETA", "1.0b0"),
3380 ("1.0.BETA", "1.0b0"),
3381 ("1.0.BETA1", "1.0b1"),
3382 ("1.0-BETA", "1.0b0"),
3383 ("1.0-BETA1", "1.0b1"),
3384 ("1.0c", "1.0rc0"),
3386 ("1.0.c", "1.0rc0"),
3387 ("1.0.c1", "1.0rc1"),
3388 ("1.0-c", "1.0rc0"),
3389 ("1.0-c1", "1.0rc1"),
3390 ("1.0rc", "1.0rc0"),
3391 ("1.0.rc", "1.0rc0"),
3392 ("1.0.rc1", "1.0rc1"),
3393 ("1.0-rc", "1.0rc0"),
3394 ("1.0-rc1", "1.0rc1"),
3395 ("1.0C", "1.0rc0"),
3396 ("1.0.C", "1.0rc0"),
3397 ("1.0.C1", "1.0rc1"),
3398 ("1.0-C", "1.0rc0"),
3399 ("1.0-C1", "1.0rc1"),
3400 ("1.0RC", "1.0rc0"),
3401 ("1.0.RC", "1.0rc0"),
3402 ("1.0.RC1", "1.0rc1"),
3403 ("1.0-RC", "1.0rc0"),
3404 ("1.0-RC1", "1.0rc1"),
3405 ("1.0post", "1.0.post0"),
3407 ("1.0.post", "1.0.post0"),
3408 ("1.0post1", "1.0.post1"),
3409 ("1.0post", "1.0.post0"),
3410 ("1.0-post", "1.0.post0"),
3411 ("1.0-post1", "1.0.post1"),
3412 ("1.0POST", "1.0.post0"),
3413 ("1.0.POST", "1.0.post0"),
3414 ("1.0POST1", "1.0.post1"),
3415 ("1.0POST", "1.0.post0"),
3416 ("1.0r", "1.0.post0"),
3417 ("1.0rev", "1.0.post0"),
3418 ("1.0.POST1", "1.0.post1"),
3419 ("1.0.r1", "1.0.post1"),
3420 ("1.0.rev1", "1.0.post1"),
3421 ("1.0-POST", "1.0.post0"),
3422 ("1.0-POST1", "1.0.post1"),
3423 ("1.0-5", "1.0.post5"),
3424 ("1.0-r5", "1.0.post5"),
3425 ("1.0-rev5", "1.0.post5"),
3426 ("1.0+AbC", "1.0+abc"),
3428 ("1.01", "1.1"),
3430 ("1.0a05", "1.0a5"),
3431 ("1.0b07", "1.0b7"),
3432 ("1.0c056", "1.0rc56"),
3433 ("1.0rc09", "1.0rc9"),
3434 ("1.0.post000", "1.0.post0"),
3435 ("1.1.dev09000", "1.1.dev9000"),
3436 ("00!1.2", "1.2"),
3437 ("0100!0.0", "100!0.0"),
3438 ("v1.0", "1.0"),
3440 (" v1.0\t\n", "1.0"),
3441 ];
3442 for (version_str, normalized_str) in versions {
3443 let version = Version::from_str(version_str).unwrap();
3444 let normalized = Version::from_str(normalized_str).unwrap();
3445 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3447 assert_eq!(
3449 version.to_string(),
3450 normalized.to_string(),
3451 "{version_str} {normalized_str}"
3452 );
3453 }
3454 }
3455
3456 #[test]
3458 fn test_equality_and_normalization2() {
3459 let versions = [
3460 ("1.0.dev456", "1.0.dev456"),
3461 ("1.0a1", "1.0a1"),
3462 ("1.0a2.dev456", "1.0a2.dev456"),
3463 ("1.0a12.dev456", "1.0a12.dev456"),
3464 ("1.0a12", "1.0a12"),
3465 ("1.0b1.dev456", "1.0b1.dev456"),
3466 ("1.0b2", "1.0b2"),
3467 ("1.0b2.post345.dev456", "1.0b2.post345.dev456"),
3468 ("1.0b2.post345", "1.0b2.post345"),
3469 ("1.0rc1.dev456", "1.0rc1.dev456"),
3470 ("1.0rc1", "1.0rc1"),
3471 ("1.0", "1.0"),
3472 ("1.0.post456.dev34", "1.0.post456.dev34"),
3473 ("1.0.post456", "1.0.post456"),
3474 ("1.0.1", "1.0.1"),
3475 ("0!1.0.2", "1.0.2"),
3476 ("1.0.3+7", "1.0.3+7"),
3477 ("0!1.0.4+8.0", "1.0.4+8.0"),
3478 ("1.0.5+9.5", "1.0.5+9.5"),
3479 ("1.2+1234.abc", "1.2+1234.abc"),
3480 ("1.2+123456", "1.2+123456"),
3481 ("1.2+123abc", "1.2+123abc"),
3482 ("1.2+123abc456", "1.2+123abc456"),
3483 ("1.2+abc", "1.2+abc"),
3484 ("1.2+abc123", "1.2+abc123"),
3485 ("1.2+abc123def", "1.2+abc123def"),
3486 ("1.1.dev1", "1.1.dev1"),
3487 ("7!1.0.dev456", "7!1.0.dev456"),
3488 ("7!1.0a1", "7!1.0a1"),
3489 ("7!1.0a2.dev456", "7!1.0a2.dev456"),
3490 ("7!1.0a12.dev456", "7!1.0a12.dev456"),
3491 ("7!1.0a12", "7!1.0a12"),
3492 ("7!1.0b1.dev456", "7!1.0b1.dev456"),
3493 ("7!1.0b2", "7!1.0b2"),
3494 ("7!1.0b2.post345.dev456", "7!1.0b2.post345.dev456"),
3495 ("7!1.0b2.post345", "7!1.0b2.post345"),
3496 ("7!1.0rc1.dev456", "7!1.0rc1.dev456"),
3497 ("7!1.0rc1", "7!1.0rc1"),
3498 ("7!1.0", "7!1.0"),
3499 ("7!1.0.post456.dev34", "7!1.0.post456.dev34"),
3500 ("7!1.0.post456", "7!1.0.post456"),
3501 ("7!1.0.1", "7!1.0.1"),
3502 ("7!1.0.2", "7!1.0.2"),
3503 ("7!1.0.3+7", "7!1.0.3+7"),
3504 ("7!1.0.4+8.0", "7!1.0.4+8.0"),
3505 ("7!1.0.5+9.5", "7!1.0.5+9.5"),
3506 ("7!1.1.dev1", "7!1.1.dev1"),
3507 ];
3508 for (version_str, normalized_str) in versions {
3509 let version = Version::from_str(version_str).unwrap();
3510 let normalized = Version::from_str(normalized_str).unwrap();
3511 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3512 assert_eq!(
3514 version.to_string(),
3515 normalized_str,
3516 "{version_str} {normalized_str}"
3517 );
3518 assert_eq!(
3520 version.to_string(),
3521 normalized.to_string(),
3522 "{version_str} {normalized_str}"
3523 );
3524 }
3525 }
3526
3527 #[test]
3528 fn test_star_fixed_version() {
3529 let result = Version::from_str("0.9.1.*");
3530 assert_eq!(result.unwrap_err(), ErrorKind::Wildcard.into());
3531 }
3532
3533 #[test]
3534 fn test_invalid_word() {
3535 let result = Version::from_str("blergh");
3536 assert_eq!(result.unwrap_err(), ErrorKind::NoLeadingNumber.into());
3537 }
3538
3539 #[test]
3540 fn test_from_version_star() {
3541 let p = |s: &str| -> Result<VersionPattern, _> { s.parse() };
3542 assert!(!p("1.2.3").unwrap().is_wildcard());
3543 assert!(p("1.2.3.*").unwrap().is_wildcard());
3544 assert_eq!(
3545 p("1.2.*.4.*").unwrap_err(),
3546 PatternErrorKind::WildcardNotTrailing.into(),
3547 );
3548 assert_eq!(
3549 p("1.0-dev1.*").unwrap_err(),
3550 ErrorKind::UnexpectedEnd {
3551 version: "1.0-dev1".to_string(),
3552 remaining: ".*".to_string()
3553 }
3554 .into(),
3555 );
3556 assert_eq!(
3557 p("1.0a1.*").unwrap_err(),
3558 ErrorKind::UnexpectedEnd {
3559 version: "1.0a1".to_string(),
3560 remaining: ".*".to_string()
3561 }
3562 .into(),
3563 );
3564 assert_eq!(
3565 p("1.0.post1.*").unwrap_err(),
3566 ErrorKind::UnexpectedEnd {
3567 version: "1.0.post1".to_string(),
3568 remaining: ".*".to_string()
3569 }
3570 .into(),
3571 );
3572 assert_eq!(
3573 p("1.0+lolwat.*").unwrap_err(),
3574 ErrorKind::LocalEmpty { precursor: '.' }.into(),
3575 );
3576 }
3577
3578 #[test]
3584 fn parse_version_valid() {
3585 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3586 Ok(v) => v,
3587 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3588 };
3589
3590 assert_eq!(p("5"), Version::new([5]));
3592 assert_eq!(p("5.6"), Version::new([5, 6]));
3593 assert_eq!(p("5.6.7"), Version::new([5, 6, 7]));
3594 assert_eq!(p("512.623.734"), Version::new([512, 623, 734]));
3595 assert_eq!(p("1.2.3.4"), Version::new([1, 2, 3, 4]));
3596 assert_eq!(p("1.2.3.4.5"), Version::new([1, 2, 3, 4, 5]));
3597
3598 assert_eq!(p("4!5"), Version::new([5]).with_epoch(4));
3600 assert_eq!(p("4!5.6"), Version::new([5, 6]).with_epoch(4));
3601
3602 assert_eq!(
3604 p("5a1"),
3605 Version::new([5]).with_pre(Some(Prerelease {
3606 kind: PrereleaseKind::Alpha,
3607 number: 1
3608 }))
3609 );
3610 assert_eq!(
3611 p("5alpha1"),
3612 Version::new([5]).with_pre(Some(Prerelease {
3613 kind: PrereleaseKind::Alpha,
3614 number: 1
3615 }))
3616 );
3617 assert_eq!(
3618 p("5b1"),
3619 Version::new([5]).with_pre(Some(Prerelease {
3620 kind: PrereleaseKind::Beta,
3621 number: 1
3622 }))
3623 );
3624 assert_eq!(
3625 p("5beta1"),
3626 Version::new([5]).with_pre(Some(Prerelease {
3627 kind: PrereleaseKind::Beta,
3628 number: 1
3629 }))
3630 );
3631 assert_eq!(
3632 p("5rc1"),
3633 Version::new([5]).with_pre(Some(Prerelease {
3634 kind: PrereleaseKind::Rc,
3635 number: 1
3636 }))
3637 );
3638 assert_eq!(
3639 p("5c1"),
3640 Version::new([5]).with_pre(Some(Prerelease {
3641 kind: PrereleaseKind::Rc,
3642 number: 1
3643 }))
3644 );
3645 assert_eq!(
3646 p("5preview1"),
3647 Version::new([5]).with_pre(Some(Prerelease {
3648 kind: PrereleaseKind::Rc,
3649 number: 1
3650 }))
3651 );
3652 assert_eq!(
3653 p("5pre1"),
3654 Version::new([5]).with_pre(Some(Prerelease {
3655 kind: PrereleaseKind::Rc,
3656 number: 1
3657 }))
3658 );
3659 assert_eq!(
3660 p("5.6.7pre1"),
3661 Version::new([5, 6, 7]).with_pre(Some(Prerelease {
3662 kind: PrereleaseKind::Rc,
3663 number: 1
3664 }))
3665 );
3666 assert_eq!(
3667 p("5alpha789"),
3668 Version::new([5]).with_pre(Some(Prerelease {
3669 kind: PrereleaseKind::Alpha,
3670 number: 789
3671 }))
3672 );
3673 assert_eq!(
3674 p("5.alpha789"),
3675 Version::new([5]).with_pre(Some(Prerelease {
3676 kind: PrereleaseKind::Alpha,
3677 number: 789
3678 }))
3679 );
3680 assert_eq!(
3681 p("5-alpha789"),
3682 Version::new([5]).with_pre(Some(Prerelease {
3683 kind: PrereleaseKind::Alpha,
3684 number: 789
3685 }))
3686 );
3687 assert_eq!(
3688 p("5_alpha789"),
3689 Version::new([5]).with_pre(Some(Prerelease {
3690 kind: PrereleaseKind::Alpha,
3691 number: 789
3692 }))
3693 );
3694 assert_eq!(
3695 p("5alpha.789"),
3696 Version::new([5]).with_pre(Some(Prerelease {
3697 kind: PrereleaseKind::Alpha,
3698 number: 789
3699 }))
3700 );
3701 assert_eq!(
3702 p("5alpha-789"),
3703 Version::new([5]).with_pre(Some(Prerelease {
3704 kind: PrereleaseKind::Alpha,
3705 number: 789
3706 }))
3707 );
3708 assert_eq!(
3709 p("5alpha_789"),
3710 Version::new([5]).with_pre(Some(Prerelease {
3711 kind: PrereleaseKind::Alpha,
3712 number: 789
3713 }))
3714 );
3715 assert_eq!(
3716 p("5ALPHA789"),
3717 Version::new([5]).with_pre(Some(Prerelease {
3718 kind: PrereleaseKind::Alpha,
3719 number: 789
3720 }))
3721 );
3722 assert_eq!(
3723 p("5aLpHa789"),
3724 Version::new([5]).with_pre(Some(Prerelease {
3725 kind: PrereleaseKind::Alpha,
3726 number: 789
3727 }))
3728 );
3729 assert_eq!(
3730 p("5alpha"),
3731 Version::new([5]).with_pre(Some(Prerelease {
3732 kind: PrereleaseKind::Alpha,
3733 number: 0
3734 }))
3735 );
3736
3737 assert_eq!(p("5post2"), Version::new([5]).with_post(Some(2)));
3739 assert_eq!(p("5rev2"), Version::new([5]).with_post(Some(2)));
3740 assert_eq!(p("5r2"), Version::new([5]).with_post(Some(2)));
3741 assert_eq!(p("5.post2"), Version::new([5]).with_post(Some(2)));
3742 assert_eq!(p("5-post2"), Version::new([5]).with_post(Some(2)));
3743 assert_eq!(p("5_post2"), Version::new([5]).with_post(Some(2)));
3744 assert_eq!(p("5.post.2"), Version::new([5]).with_post(Some(2)));
3745 assert_eq!(p("5.post-2"), Version::new([5]).with_post(Some(2)));
3746 assert_eq!(p("5.post_2"), Version::new([5]).with_post(Some(2)));
3747 assert_eq!(
3748 p("5.6.7.post_2"),
3749 Version::new([5, 6, 7]).with_post(Some(2))
3750 );
3751 assert_eq!(p("5-2"), Version::new([5]).with_post(Some(2)));
3752 assert_eq!(p("5.6.7-2"), Version::new([5, 6, 7]).with_post(Some(2)));
3753 assert_eq!(p("5POST2"), Version::new([5]).with_post(Some(2)));
3754 assert_eq!(p("5PoSt2"), Version::new([5]).with_post(Some(2)));
3755 assert_eq!(p("5post"), Version::new([5]).with_post(Some(0)));
3756
3757 assert_eq!(p("5dev2"), Version::new([5]).with_dev(Some(2)));
3759 assert_eq!(p("5.dev2"), Version::new([5]).with_dev(Some(2)));
3760 assert_eq!(p("5-dev2"), Version::new([5]).with_dev(Some(2)));
3761 assert_eq!(p("5_dev2"), Version::new([5]).with_dev(Some(2)));
3762 assert_eq!(p("5.dev.2"), Version::new([5]).with_dev(Some(2)));
3763 assert_eq!(p("5.dev-2"), Version::new([5]).with_dev(Some(2)));
3764 assert_eq!(p("5.dev_2"), Version::new([5]).with_dev(Some(2)));
3765 assert_eq!(p("5.6.7.dev_2"), Version::new([5, 6, 7]).with_dev(Some(2)));
3766 assert_eq!(p("5DEV2"), Version::new([5]).with_dev(Some(2)));
3767 assert_eq!(p("5dEv2"), Version::new([5]).with_dev(Some(2)));
3768 assert_eq!(p("5DeV2"), Version::new([5]).with_dev(Some(2)));
3769 assert_eq!(p("5dev"), Version::new([5]).with_dev(Some(0)));
3770
3771 assert_eq!(
3773 p("5+2"),
3774 Version::new([5]).with_local_segments(vec![LocalSegment::Number(2)])
3775 );
3776 assert_eq!(
3777 p("5+a"),
3778 Version::new([5]).with_local_segments(vec![LocalSegment::String("a".to_string())])
3779 );
3780 assert_eq!(
3781 p("5+abc.123"),
3782 Version::new([5]).with_local_segments(vec![
3783 LocalSegment::String("abc".to_string()),
3784 LocalSegment::Number(123),
3785 ])
3786 );
3787 assert_eq!(
3788 p("5+123.abc"),
3789 Version::new([5]).with_local_segments(vec![
3790 LocalSegment::Number(123),
3791 LocalSegment::String("abc".to_string()),
3792 ])
3793 );
3794 assert_eq!(
3795 p("5+18446744073709551615.abc"),
3796 Version::new([5]).with_local_segments(vec![
3797 LocalSegment::Number(18_446_744_073_709_551_615),
3798 LocalSegment::String("abc".to_string()),
3799 ])
3800 );
3801 assert_eq!(
3802 p("5+18446744073709551616.abc"),
3803 Version::new([5]).with_local_segments(vec![
3804 LocalSegment::String("18446744073709551616".to_string()),
3805 LocalSegment::String("abc".to_string()),
3806 ])
3807 );
3808 assert_eq!(
3809 p("5+ABC.123"),
3810 Version::new([5]).with_local_segments(vec![
3811 LocalSegment::String("abc".to_string()),
3812 LocalSegment::Number(123),
3813 ])
3814 );
3815 assert_eq!(
3816 p("5+ABC-123.4_5_xyz-MNO"),
3817 Version::new([5]).with_local_segments(vec![
3818 LocalSegment::String("abc".to_string()),
3819 LocalSegment::Number(123),
3820 LocalSegment::Number(4),
3821 LocalSegment::Number(5),
3822 LocalSegment::String("xyz".to_string()),
3823 LocalSegment::String("mno".to_string()),
3824 ])
3825 );
3826 assert_eq!(
3827 p("5.6.7+abc-00123"),
3828 Version::new([5, 6, 7]).with_local_segments(vec![
3829 LocalSegment::String("abc".to_string()),
3830 LocalSegment::Number(123),
3831 ])
3832 );
3833 assert_eq!(
3834 p("5.6.7+abc-foo00123"),
3835 Version::new([5, 6, 7]).with_local_segments(vec![
3836 LocalSegment::String("abc".to_string()),
3837 LocalSegment::String("foo00123".to_string()),
3838 ])
3839 );
3840 assert_eq!(
3841 p("5.6.7+abc-00123a"),
3842 Version::new([5, 6, 7]).with_local_segments(vec![
3843 LocalSegment::String("abc".to_string()),
3844 LocalSegment::String("00123a".to_string()),
3845 ])
3846 );
3847
3848 assert_eq!(
3850 p("5a2post3"),
3851 Version::new([5])
3852 .with_pre(Some(Prerelease {
3853 kind: PrereleaseKind::Alpha,
3854 number: 2
3855 }))
3856 .with_post(Some(3))
3857 );
3858 assert_eq!(
3859 p("5.a-2_post-3"),
3860 Version::new([5])
3861 .with_pre(Some(Prerelease {
3862 kind: PrereleaseKind::Alpha,
3863 number: 2
3864 }))
3865 .with_post(Some(3))
3866 );
3867 assert_eq!(
3868 p("5a2-3"),
3869 Version::new([5])
3870 .with_pre(Some(Prerelease {
3871 kind: PrereleaseKind::Alpha,
3872 number: 2
3873 }))
3874 .with_post(Some(3))
3875 );
3876
3877 assert_eq!(p("v5"), Version::new([5]));
3879 assert_eq!(p("V5"), Version::new([5]));
3880 assert_eq!(p("v5.6.7"), Version::new([5, 6, 7]));
3881
3882 assert_eq!(p(" v5 "), Version::new([5]));
3884 assert_eq!(p(" 5 "), Version::new([5]));
3885 assert_eq!(
3886 p(" 5.6.7+abc.123.xyz "),
3887 Version::new([5, 6, 7]).with_local_segments(vec![
3888 LocalSegment::String("abc".to_string()),
3889 LocalSegment::Number(123),
3890 LocalSegment::String("xyz".to_string())
3891 ])
3892 );
3893 assert_eq!(p(" \n5\n \t"), Version::new([5]));
3894
3895 assert!(Parser::new("1.min0".as_bytes()).parse().is_err());
3897 }
3898
3899 #[test]
3907 fn parse_version_invalid() {
3908 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3909 Err(err) => err,
3910 Ok(v) => unreachable!(
3911 "expected version parser error, but got: {v:?}",
3912 v = v.as_bloated_debug()
3913 ),
3914 };
3915
3916 assert_eq!(p(""), ErrorKind::NoLeadingNumber.into());
3917 assert_eq!(p("a"), ErrorKind::NoLeadingNumber.into());
3918 assert_eq!(p("v 5"), ErrorKind::NoLeadingNumber.into());
3919 assert_eq!(p("V 5"), ErrorKind::NoLeadingNumber.into());
3920 assert_eq!(p("x 5"), ErrorKind::NoLeadingNumber.into());
3921 assert_eq!(
3922 p("18446744073709551616"),
3923 ErrorKind::NumberTooBig {
3924 bytes: b"18446744073709551616".to_vec()
3925 }
3926 .into()
3927 );
3928 assert_eq!(p("5!"), ErrorKind::NoLeadingReleaseNumber.into());
3929 assert_eq!(
3930 p("5.6./"),
3931 ErrorKind::UnexpectedEnd {
3932 version: "5.6".to_string(),
3933 remaining: "./".to_string()
3934 }
3935 .into()
3936 );
3937 assert_eq!(
3938 p("5.6.-alpha2"),
3939 ErrorKind::UnexpectedEnd {
3940 version: "5.6".to_string(),
3941 remaining: ".-alpha2".to_string()
3942 }
3943 .into()
3944 );
3945 assert_eq!(
3946 p("1.2.3a18446744073709551616"),
3947 ErrorKind::NumberTooBig {
3948 bytes: b"18446744073709551616".to_vec()
3949 }
3950 .into()
3951 );
3952 assert_eq!(p("5+"), ErrorKind::LocalEmpty { precursor: '+' }.into());
3953 assert_eq!(p("5+ "), ErrorKind::LocalEmpty { precursor: '+' }.into());
3954 assert_eq!(p("5+abc."), ErrorKind::LocalEmpty { precursor: '.' }.into());
3955 assert_eq!(p("5+abc-"), ErrorKind::LocalEmpty { precursor: '-' }.into());
3956 assert_eq!(p("5+abc_"), ErrorKind::LocalEmpty { precursor: '_' }.into());
3957 assert_eq!(
3958 p("5+abc. "),
3959 ErrorKind::LocalEmpty { precursor: '.' }.into()
3960 );
3961 assert_eq!(
3962 p("5.6-"),
3963 ErrorKind::UnexpectedEnd {
3964 version: "5.6".to_string(),
3965 remaining: "-".to_string()
3966 }
3967 .into()
3968 );
3969 }
3970
3971 #[test]
3972 fn parse_version_pattern_valid() {
3973 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3974 Ok(v) => v,
3975 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3976 };
3977
3978 assert_eq!(p("5.*"), VersionPattern::wildcard(Version::new([5])));
3979 assert_eq!(p("5.6.*"), VersionPattern::wildcard(Version::new([5, 6])));
3980 assert_eq!(
3981 p("2!5.6.*"),
3982 VersionPattern::wildcard(Version::new([5, 6]).with_epoch(2))
3983 );
3984 }
3985
3986 #[test]
3987 fn parse_version_pattern_invalid() {
3988 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3989 Err(err) => err,
3990 Ok(vpat) => unreachable!("expected version pattern parser error, but got: {vpat:?}"),
3991 };
3992
3993 assert_eq!(p("*"), ErrorKind::NoLeadingNumber.into());
3994 assert_eq!(p("2!*"), ErrorKind::NoLeadingReleaseNumber.into());
3995 }
3996
3997 #[test]
4002 fn ordering() {
4003 let versions = &[
4004 "1.dev0",
4005 "1.0.dev456",
4006 "1.0a1",
4007 "1.0a2.dev456",
4008 "1.0a12.dev456",
4009 "1.0a12",
4010 "1.0b1.dev456",
4011 "1.0b2",
4012 "1.0b2.post345.dev456",
4013 "1.0b2.post345",
4014 "1.0rc1.dev456",
4015 "1.0rc1",
4016 "1.0",
4017 "1.0+abc.5",
4018 "1.0+abc.7",
4019 "1.0+5",
4020 "1.0.post456.dev34",
4021 "1.0.post456",
4022 "1.0.15",
4023 "1.1.dev1",
4024 ];
4025 for (i, v1) in versions.iter().enumerate() {
4026 for v2 in &versions[i + 1..] {
4027 let less = v1.parse::<Version>().unwrap();
4028 let greater = v2.parse::<Version>().unwrap();
4029 assert_eq!(
4030 less.cmp(&greater),
4031 Ordering::Less,
4032 "less: {:?}\ngreater: {:?}",
4033 less.as_bloated_debug(),
4034 greater.as_bloated_debug()
4035 );
4036 }
4037 }
4038 }
4039
4040 #[test]
4041 fn local_sentinel_version() {
4042 let sentinel = Version::new([1, 0]).with_local(LocalVersion::Max);
4043
4044 let versions = &["1.0.post0", "1.1"];
4046
4047 for greater in versions {
4048 let greater = greater.parse::<Version>().unwrap();
4049 assert_eq!(
4050 sentinel.cmp(&greater),
4051 Ordering::Less,
4052 "less: {:?}\ngreater: {:?}",
4053 greater.as_bloated_debug(),
4054 sentinel.as_bloated_debug(),
4055 );
4056 }
4057
4058 let versions = &["1.0", "1.0.a0", "1.0+local"];
4060
4061 for less in versions {
4062 let less = less.parse::<Version>().unwrap();
4063 assert_eq!(
4064 sentinel.cmp(&less),
4065 Ordering::Greater,
4066 "less: {:?}\ngreater: {:?}",
4067 sentinel.as_bloated_debug(),
4068 less.as_bloated_debug()
4069 );
4070 }
4071 }
4072
4073 #[test]
4074 fn min_version() {
4075 let less = Version::new([1, 0]).with_min(Some(0));
4077
4078 let versions = &[
4079 "1.dev0",
4080 "1.0.dev456",
4081 "1.0a1",
4082 "1.0a2.dev456",
4083 "1.0a12.dev456",
4084 "1.0a12",
4085 "1.0b1.dev456",
4086 "1.0b2",
4087 "1.0b2.post345.dev456",
4088 "1.0b2.post345",
4089 "1.0rc1.dev456",
4090 "1.0rc1",
4091 "1.0",
4092 "1.0+abc.5",
4093 "1.0+abc.7",
4094 "1.0+5",
4095 "1.0.post456.dev34",
4096 "1.0.post456",
4097 "1.0.15",
4098 "1.1.dev1",
4099 ];
4100
4101 for greater in versions {
4102 let greater = greater.parse::<Version>().unwrap();
4103 assert_eq!(
4104 less.cmp(&greater),
4105 Ordering::Less,
4106 "less: {:?}\ngreater: {:?}",
4107 less.as_bloated_debug(),
4108 greater.as_bloated_debug()
4109 );
4110 }
4111 }
4112
4113 #[test]
4114 fn max_version() {
4115 let greater = Version::new([1, 0]).with_max(Some(0));
4117
4118 let versions = &[
4119 "1.dev0",
4120 "1.0.dev456",
4121 "1.0a1",
4122 "1.0a2.dev456",
4123 "1.0a12.dev456",
4124 "1.0a12",
4125 "1.0b1.dev456",
4126 "1.0b2",
4127 "1.0b2.post345.dev456",
4128 "1.0b2.post345",
4129 "1.0rc1.dev456",
4130 "1.0rc1",
4131 "1.0",
4132 "1.0+abc.5",
4133 "1.0+abc.7",
4134 "1.0+5",
4135 "1.0.post456.dev34",
4136 "1.0.post456",
4137 "1.0",
4138 ];
4139
4140 for less in versions {
4141 let less = less.parse::<Version>().unwrap();
4142 assert_eq!(
4143 less.cmp(&greater),
4144 Ordering::Less,
4145 "less: {:?}\ngreater: {:?}",
4146 less.as_bloated_debug(),
4147 greater.as_bloated_debug()
4148 );
4149 }
4150
4151 let greater = Version::new([1, 0])
4153 .with_pre(Some(Prerelease {
4154 kind: PrereleaseKind::Alpha,
4155 number: 1,
4156 }))
4157 .with_max(Some(0));
4158
4159 let versions = &["1.0a1", "1.0a1+local", "1.0a1.post1"];
4160
4161 for less in versions {
4162 let less = less.parse::<Version>().unwrap();
4163 assert_eq!(
4164 less.cmp(&greater),
4165 Ordering::Less,
4166 "less: {:?}\ngreater: {:?}",
4167 less.as_bloated_debug(),
4168 greater.as_bloated_debug()
4169 );
4170 }
4171
4172 let less = Version::new([1, 0])
4174 .with_pre(Some(Prerelease {
4175 kind: PrereleaseKind::Alpha,
4176 number: 1,
4177 }))
4178 .with_max(Some(0));
4179
4180 let versions = &["1.0b1", "1.0b1+local", "1.0b1.post1", "1.0"];
4181
4182 for greater in versions {
4183 let greater = greater.parse::<Version>().unwrap();
4184 assert_eq!(
4185 less.cmp(&greater),
4186 Ordering::Less,
4187 "less: {:?}\ngreater: {:?}",
4188 less.as_bloated_debug(),
4189 greater.as_bloated_debug()
4190 );
4191 }
4192 }
4193
4194 #[test]
4196 fn parse_number_u64() {
4197 let p = |s: &str| parse_u64(s.as_bytes());
4198 assert_eq!(p("0"), Ok(0));
4199 assert_eq!(p("00"), Ok(0));
4200 assert_eq!(p("1"), Ok(1));
4201 assert_eq!(p("01"), Ok(1));
4202 assert_eq!(p("9"), Ok(9));
4203 assert_eq!(p("10"), Ok(10));
4204 assert_eq!(p("18446744073709551615"), Ok(18_446_744_073_709_551_615));
4205 assert_eq!(p("018446744073709551615"), Ok(18_446_744_073_709_551_615));
4206 assert_eq!(
4207 p("000000018446744073709551615"),
4208 Ok(18_446_744_073_709_551_615)
4209 );
4210
4211 assert_eq!(p("10a"), Err(ErrorKind::InvalidDigit { got: b'a' }.into()));
4212 assert_eq!(p("10["), Err(ErrorKind::InvalidDigit { got: b'[' }.into()));
4213 assert_eq!(p("10/"), Err(ErrorKind::InvalidDigit { got: b'/' }.into()));
4214 assert_eq!(
4216 p("18446744073709551616"),
4217 Err(ErrorKind::NumberTooBig {
4218 bytes: b"18446744073709551616".to_vec()
4219 }
4220 .into())
4221 );
4222 assert_eq!(
4223 p("18446744073799551615abc"),
4224 Err(ErrorKind::NumberTooBig {
4225 bytes: b"18446744073799551615abc".to_vec()
4226 }
4227 .into())
4228 );
4229 assert_eq!(
4230 parse_u64(b"18446744073799551615\xFF"),
4231 Err(ErrorKind::NumberTooBig {
4232 bytes: b"18446744073799551615\xFF".to_vec()
4233 }
4234 .into())
4235 );
4236 }
4237
4238 impl Version {
4239 pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4249 std::fmt::from_fn(|f| {
4250 f.debug_struct("Version")
4251 .field("epoch", &self.epoch())
4252 .field("release", &&*self.release())
4253 .field("pre", &self.pre())
4254 .field("post", &self.post())
4255 .field("dev", &self.dev())
4256 .field("local", &self.local())
4257 .field("min", &self.min())
4258 .field("max", &self.max())
4259 .finish()
4260 })
4261 }
4262 }
4263
4264 #[test]
4268 fn preserve_trailing_zeros() {
4269 let v1: Version = "1.2.0".parse().unwrap();
4270 assert_eq!(&*v1.release(), &[1, 2, 0]);
4271 assert_eq!(v1.to_string(), "1.2.0");
4272
4273 let v2: Version = "1.2".parse().unwrap();
4274 assert_eq!(&*v2.release(), &[1, 2]);
4275 assert_eq!(v2.to_string(), "1.2");
4276 }
4277
4278 #[test]
4279 fn only_release_at_precision_preserves_epoch_and_discards_suffixes() {
4280 let version = "1!2.3rc1.post2.dev3+local"
4281 .parse::<Version>()
4282 .expect("valid version");
4283 assert_eq!(
4284 version
4285 .only_release_at_precision(4)
4286 .expect("non-zero precision")
4287 .to_string(),
4288 "1!2.3.0.0"
4289 );
4290 assert_eq!(version.only_release_at_precision(0), None);
4291 }
4292
4293 #[test]
4294 fn only_release_trimmed_discards_non_release_segments() {
4295 for version in ["1.2a1", "1.2.post1", "1!1.2", "1.2+local", "1.2.dev1"] {
4296 let version = version.parse::<Version>().unwrap();
4297 assert_eq!(version.only_release_trimmed(), Version::new([1, 2]));
4298 }
4299
4300 assert_eq!(
4301 Version::new([1, 2])
4302 .with_min(Some(0))
4303 .only_release_trimmed(),
4304 Version::new([1, 2])
4305 );
4306 assert_eq!(
4307 Version::new([1, 2])
4308 .with_max(Some(0))
4309 .only_release_trimmed(),
4310 Version::new([1, 2])
4311 );
4312 assert_eq!(
4313 Version::new([1, 2, 0]).only_release_trimmed(),
4314 Version::new([1, 2])
4315 );
4316 assert_eq!(
4317 Version::new([1, 2]).only_release_trimmed(),
4318 Version::new([1, 2])
4319 );
4320 }
4321
4322 #[test]
4323 fn type_size() {
4324 assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4325 assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4326 }
4327
4328 #[test]
4331 fn bump_major() {
4332 let mut version = "0".parse::<Version>().unwrap();
4334 version.bump(BumpCommand::BumpRelease {
4335 index: 0,
4336 value: None,
4337 });
4338 assert_eq!(version.to_string().as_str(), "1");
4339
4340 let mut version = "1.5".parse::<Version>().unwrap();
4342 version.bump(BumpCommand::BumpRelease {
4343 index: 0,
4344 value: None,
4345 });
4346 assert_eq!(version.to_string().as_str(), "2.0");
4347
4348 let mut version = "0.1.2".parse::<Version>().unwrap();
4350 version.bump(BumpCommand::BumpRelease {
4351 index: 0,
4352 value: None,
4353 });
4354 assert_eq!(version.to_string().as_str(), "1.0.0");
4355
4356 let mut version = "1.2.3".parse::<Version>().unwrap();
4358 version.bump(BumpCommand::BumpRelease {
4359 index: 0,
4360 value: None,
4361 });
4362 assert_eq!(version.to_string().as_str(), "2.0.0");
4363
4364 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4366 version.bump(BumpCommand::BumpRelease {
4367 index: 0,
4368 value: None,
4369 });
4370 assert_eq!(version.to_string().as_str(), "2.0.0.0");
4371
4372 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4374 .parse::<Version>()
4375 .unwrap();
4376 version.bump(BumpCommand::BumpRelease {
4377 index: 0,
4378 value: None,
4379 });
4380 assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4381 version.bump(BumpCommand::BumpRelease {
4382 index: 0,
4383 value: None,
4384 });
4385 assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4386 }
4387
4388 #[test]
4391 fn bump_minor() {
4392 let mut version = "0".parse::<Version>().unwrap();
4394 version.bump(BumpCommand::BumpRelease {
4395 index: 1,
4396 value: None,
4397 });
4398 assert_eq!(version.to_string().as_str(), "0.1");
4399
4400 let mut version = "1.5".parse::<Version>().unwrap();
4402 version.bump(BumpCommand::BumpRelease {
4403 index: 1,
4404 value: None,
4405 });
4406 assert_eq!(version.to_string().as_str(), "1.6");
4407
4408 let mut version = "5.3.6".parse::<Version>().unwrap();
4410 version.bump(BumpCommand::BumpRelease {
4411 index: 1,
4412 value: None,
4413 });
4414 assert_eq!(version.to_string().as_str(), "5.4.0");
4415
4416 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4418 version.bump(BumpCommand::BumpRelease {
4419 index: 1,
4420 value: None,
4421 });
4422 assert_eq!(version.to_string().as_str(), "1.3.0.0");
4423
4424 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4426 .parse::<Version>()
4427 .unwrap();
4428 version.bump(BumpCommand::BumpRelease {
4429 index: 1,
4430 value: None,
4431 });
4432 assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4433 version.bump(BumpCommand::BumpRelease {
4434 index: 1,
4435 value: None,
4436 });
4437 assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4438 }
4439
4440 #[test]
4443 fn bump_patch() {
4444 let mut version = "0".parse::<Version>().unwrap();
4446 version.bump(BumpCommand::BumpRelease {
4447 index: 2,
4448 value: None,
4449 });
4450 assert_eq!(version.to_string().as_str(), "0.0.1");
4451
4452 let mut version = "1.5".parse::<Version>().unwrap();
4454 version.bump(BumpCommand::BumpRelease {
4455 index: 2,
4456 value: None,
4457 });
4458 assert_eq!(version.to_string().as_str(), "1.5.1");
4459
4460 let mut version = "5.3.6".parse::<Version>().unwrap();
4462 version.bump(BumpCommand::BumpRelease {
4463 index: 2,
4464 value: None,
4465 });
4466 assert_eq!(version.to_string().as_str(), "5.3.7");
4467
4468 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4470 version.bump(BumpCommand::BumpRelease {
4471 index: 2,
4472 value: None,
4473 });
4474 assert_eq!(version.to_string().as_str(), "1.2.4.0");
4475
4476 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4478 .parse::<Version>()
4479 .unwrap();
4480 version.bump(BumpCommand::BumpRelease {
4481 index: 2,
4482 value: None,
4483 });
4484 assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4485 version.bump(BumpCommand::BumpRelease {
4486 index: 2,
4487 value: None,
4488 });
4489 assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4490 }
4491
4492 #[test]
4495 fn bump_alpha() {
4496 let mut version = "0".parse::<Version>().unwrap();
4498 version.bump(BumpCommand::BumpPrerelease {
4499 kind: PrereleaseKind::Alpha,
4500 value: None,
4501 });
4502 assert_eq!(version.to_string().as_str(), "0a1");
4503
4504 let mut version = "1.5".parse::<Version>().unwrap();
4506 version.bump(BumpCommand::BumpPrerelease {
4507 kind: PrereleaseKind::Alpha,
4508 value: None,
4509 });
4510 assert_eq!(version.to_string().as_str(), "1.5a1");
4511
4512 let mut version = "5.3.6".parse::<Version>().unwrap();
4514 version.bump(BumpCommand::BumpPrerelease {
4515 kind: PrereleaseKind::Alpha,
4516 value: None,
4517 });
4518 assert_eq!(version.to_string().as_str(), "5.3.6a1");
4519
4520 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4522 version.bump(BumpCommand::BumpPrerelease {
4523 kind: PrereleaseKind::Alpha,
4524 value: None,
4525 });
4526 assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4527
4528 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4530 .parse::<Version>()
4531 .unwrap();
4532 version.bump(BumpCommand::BumpPrerelease {
4533 kind: PrereleaseKind::Alpha,
4534 value: None,
4535 });
4536 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4537 version.bump(BumpCommand::BumpPrerelease {
4538 kind: PrereleaseKind::Alpha,
4539 value: None,
4540 });
4541 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4542 }
4543
4544 #[test]
4547 fn bump_beta() {
4548 let mut version = "0".parse::<Version>().unwrap();
4550 version.bump(BumpCommand::BumpPrerelease {
4551 kind: PrereleaseKind::Beta,
4552 value: None,
4553 });
4554 assert_eq!(version.to_string().as_str(), "0b1");
4555
4556 let mut version = "1.5".parse::<Version>().unwrap();
4558 version.bump(BumpCommand::BumpPrerelease {
4559 kind: PrereleaseKind::Beta,
4560 value: None,
4561 });
4562 assert_eq!(version.to_string().as_str(), "1.5b1");
4563
4564 let mut version = "5.3.6".parse::<Version>().unwrap();
4566 version.bump(BumpCommand::BumpPrerelease {
4567 kind: PrereleaseKind::Beta,
4568 value: None,
4569 });
4570 assert_eq!(version.to_string().as_str(), "5.3.6b1");
4571
4572 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4574 version.bump(BumpCommand::BumpPrerelease {
4575 kind: PrereleaseKind::Beta,
4576 value: None,
4577 });
4578 assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4579
4580 let mut version = "5!1.7.3.5a2.post345.dev456+local"
4582 .parse::<Version>()
4583 .unwrap();
4584 version.bump(BumpCommand::BumpPrerelease {
4585 kind: PrereleaseKind::Beta,
4586 value: None,
4587 });
4588 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4589 version.bump(BumpCommand::BumpPrerelease {
4590 kind: PrereleaseKind::Beta,
4591 value: None,
4592 });
4593 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4594 }
4595
4596 #[test]
4599 fn bump_rc() {
4600 let mut version = "0".parse::<Version>().unwrap();
4602 version.bump(BumpCommand::BumpPrerelease {
4603 kind: PrereleaseKind::Rc,
4604 value: None,
4605 });
4606 assert_eq!(version.to_string().as_str(), "0rc1");
4607
4608 let mut version = "1.5".parse::<Version>().unwrap();
4610 version.bump(BumpCommand::BumpPrerelease {
4611 kind: PrereleaseKind::Rc,
4612 value: None,
4613 });
4614 assert_eq!(version.to_string().as_str(), "1.5rc1");
4615
4616 let mut version = "5.3.6".parse::<Version>().unwrap();
4618 version.bump(BumpCommand::BumpPrerelease {
4619 kind: PrereleaseKind::Rc,
4620 value: None,
4621 });
4622 assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4623
4624 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4626 version.bump(BumpCommand::BumpPrerelease {
4627 kind: PrereleaseKind::Rc,
4628 value: None,
4629 });
4630 assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4631
4632 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4634 .parse::<Version>()
4635 .unwrap();
4636 version.bump(BumpCommand::BumpPrerelease {
4637 kind: PrereleaseKind::Rc,
4638 value: None,
4639 });
4640 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4641 version.bump(BumpCommand::BumpPrerelease {
4642 kind: PrereleaseKind::Rc,
4643 value: None,
4644 });
4645 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4646 }
4647
4648 #[test]
4651 fn bump_post() {
4652 let mut version = "0".parse::<Version>().unwrap();
4654 version.bump(BumpCommand::BumpPost { value: None });
4655 assert_eq!(version.to_string().as_str(), "0.post1");
4656
4657 let mut version = "1.5".parse::<Version>().unwrap();
4659 version.bump(BumpCommand::BumpPost { value: None });
4660 assert_eq!(version.to_string().as_str(), "1.5.post1");
4661
4662 let mut version = "5.3.6".parse::<Version>().unwrap();
4664 version.bump(BumpCommand::BumpPost { value: None });
4665 assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4666
4667 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4669 version.bump(BumpCommand::BumpPost { value: None });
4670 assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4671
4672 let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4674 version.bump(BumpCommand::BumpPost { value: None });
4675 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4676 version.bump(BumpCommand::BumpPost { value: None });
4677 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4678 }
4679
4680 #[test]
4683 fn bump_dev() {
4684 let mut version = "0".parse::<Version>().unwrap();
4686 version.bump(BumpCommand::BumpDev { value: None });
4687 assert_eq!(version.to_string().as_str(), "0.dev1");
4688
4689 let mut version = "1.5".parse::<Version>().unwrap();
4691 version.bump(BumpCommand::BumpDev { value: None });
4692 assert_eq!(version.to_string().as_str(), "1.5.dev1");
4693
4694 let mut version = "5.3.6".parse::<Version>().unwrap();
4696 version.bump(BumpCommand::BumpDev { value: None });
4697 assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4698
4699 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4701 version.bump(BumpCommand::BumpDev { value: None });
4702 assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4703
4704 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4706 version.bump(BumpCommand::BumpDev { value: None });
4707 assert_eq!(
4708 version.to_string().as_str(),
4709 "5!1.7.3.5b2.post345.dev1+local"
4710 );
4711 version.bump(BumpCommand::BumpDev { value: None });
4712 assert_eq!(
4713 version.to_string().as_str(),
4714 "5!1.7.3.5b2.post345.dev2+local"
4715 );
4716 }
4717
4718 #[test]
4721 fn make_stable() {
4722 let mut version = "0".parse::<Version>().unwrap();
4724 version.bump(BumpCommand::MakeStable);
4725 assert_eq!(version.to_string().as_str(), "0");
4726
4727 let mut version = "1.5".parse::<Version>().unwrap();
4729 version.bump(BumpCommand::MakeStable);
4730 assert_eq!(version.to_string().as_str(), "1.5");
4731
4732 let mut version = "5.3.6".parse::<Version>().unwrap();
4734 version.bump(BumpCommand::MakeStable);
4735 assert_eq!(version.to_string().as_str(), "5.3.6");
4736
4737 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4739 version.bump(BumpCommand::MakeStable);
4740 assert_eq!(version.to_string().as_str(), "1.2.3.4");
4741
4742 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4744 version.bump(BumpCommand::MakeStable);
4745 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4746 version.bump(BumpCommand::MakeStable);
4747 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4748 }
4749}