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 pub fn min(&self) -> Option<u64> {
440 match self.inner {
441 VersionInner::Small { ref small } => small.min(),
442 VersionInner::Full { ref full } => full.min,
443 }
444 }
445
446 #[inline]
452 pub fn max(&self) -> Option<u64> {
453 match self.inner {
454 VersionInner::Small { ref small } => small.max(),
455 VersionInner::Full { ref full } => full.max,
456 }
457 }
458
459 #[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]
490 fn push_release(&mut self, n: u64) {
491 if let VersionInner::Small { small } = &mut self.inner {
492 if small.push_release(n) {
493 return;
494 }
495 }
496 self.make_full().release.push(n);
497 }
498
499 #[inline]
504 fn clear_release(&mut self) {
505 match &mut self.inner {
506 VersionInner::Small { small } => small.clear_release(),
507 VersionInner::Full { full } => {
508 Arc::make_mut(full).release.clear();
509 }
510 }
511 }
512
513 #[inline]
515 #[must_use]
516 pub fn with_epoch(mut self, value: u64) -> Self {
517 if let VersionInner::Small { small } = &mut self.inner {
518 if small.set_epoch(value) {
519 return self;
520 }
521 }
522 self.make_full().epoch = value;
523 self
524 }
525
526 #[inline]
528 #[must_use]
529 pub fn with_pre(mut self, value: Option<Prerelease>) -> Self {
530 if let VersionInner::Small { small } = &mut self.inner {
531 if small.set_pre(value) {
532 return self;
533 }
534 }
535 self.make_full().pre = value;
536 self
537 }
538
539 #[inline]
541 #[must_use]
542 pub fn with_post(mut self, value: Option<u64>) -> Self {
543 if let VersionInner::Small { small } = &mut self.inner {
544 if small.set_post(value) {
545 return self;
546 }
547 }
548 self.make_full().post = value;
549 self
550 }
551
552 #[inline]
554 #[must_use]
555 pub fn with_dev(mut self, value: Option<u64>) -> Self {
556 if let VersionInner::Small { small } = &mut self.inner {
557 if small.set_dev(value) {
558 return self;
559 }
560 }
561 self.make_full().dev = value;
562 self
563 }
564
565 #[inline]
567 #[must_use]
568 pub fn with_local_segments(mut self, value: Vec<LocalSegment>) -> Self {
569 if value.is_empty() {
570 self.without_local()
571 } else {
572 self.make_full().local = LocalVersion::Segments(value);
573 self
574 }
575 }
576
577 #[inline]
579 #[must_use]
580 pub fn with_local(mut self, value: LocalVersion) -> Self {
581 match value {
582 LocalVersion::Segments(segments) => self.with_local_segments(segments),
583 LocalVersion::Max => {
584 if let VersionInner::Small { small } = &mut self.inner {
585 if small.set_local(LocalVersion::Max) {
586 return self;
587 }
588 }
589 self.make_full().local = value;
590 self
591 }
592 }
593 }
594
595 #[inline]
600 #[must_use]
601 pub fn without_local(mut self) -> Self {
602 if let VersionInner::Small { small } = &mut self.inner {
603 if small.set_local(LocalVersion::empty()) {
604 return self;
605 }
606 }
607 self.make_full().local = LocalVersion::empty();
608 self
609 }
610
611 #[inline]
613 #[must_use]
614 pub fn only_release(&self) -> Self {
615 Self::new(self.release().iter().copied())
616 }
617
618 #[inline]
620 #[must_use]
621 pub fn only_minor_release(&self) -> Self {
622 Self::new(self.release().iter().take(2).copied())
623 }
624
625 #[inline]
628 #[must_use]
629 pub fn only_release_trimmed(&self) -> Self {
630 if let Some(last_non_zero) = self.release().iter().rposition(|segment| *segment != 0) {
631 if last_non_zero == self.release().len() {
632 self.clone()
634 } else {
635 Self::new(self.release().iter().take(last_non_zero + 1).copied())
636 }
637 } else {
638 Self::new([0])
640 }
641 }
642
643 #[inline]
649 #[must_use]
650 pub fn without_trailing_zeros(self) -> Self {
651 let mut release = self.release().to_vec();
652 while let Some(0) = release.last() {
653 release.pop();
654 }
655 self.with_release(release)
656 }
657
658 pub fn bump(&mut self, bump: BumpCommand) {
660 let full = self.make_full();
677
678 match bump {
679 BumpCommand::BumpRelease { index, value } => {
680 full.pre = None;
682 full.post = None;
683 full.dev = None;
684
685 let old_parts = &full.release;
687 let len = old_parts.len().max(index + 1);
688 let new_release_vec = (0..len)
689 .map(|i| match i.cmp(&index) {
690 Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
692 Ordering::Equal => {
694 value.unwrap_or_else(|| old_parts.get(i).copied().unwrap_or(0) + 1)
695 }
696 Ordering::Greater => 0,
698 })
699 .collect::<Vec<u64>>();
700 full.release = new_release_vec;
701 }
702 BumpCommand::MakeStable => {
703 full.pre = None;
705 full.post = None;
706 full.dev = None;
707 }
708 BumpCommand::BumpPrerelease { kind, value } => {
709 full.post = None;
711 full.dev = None;
712 if let Some(value) = value {
713 full.pre = Some(Prerelease {
714 kind,
715 number: value,
716 });
717 } else {
718 if let Some(prerelease) = &mut full.pre {
720 if prerelease.kind == kind {
721 prerelease.number += 1;
722 return;
723 }
724 }
725 full.pre = Some(Prerelease { kind, number: 1 });
726 }
727 }
728 BumpCommand::BumpPost { value } => {
729 full.dev = None;
731 if let Some(value) = value {
732 full.post = Some(value);
733 } else {
734 if let Some(post) = &mut full.post {
736 *post += 1;
737 } else {
738 full.post = Some(1);
739 }
740 }
741 }
742 BumpCommand::BumpDev { value } => {
743 if let Some(value) = value {
744 full.dev = Some(value);
745 } else {
746 if let Some(dev) = &mut full.dev {
748 *dev += 1;
749 } else {
750 full.dev = Some(1);
751 }
752 }
753 }
754 }
755 }
756
757 #[inline]
763 #[must_use]
764 pub fn with_min(mut self, value: Option<u64>) -> Self {
765 debug_assert!(!self.is_pre(), "min is not allowed on pre-release versions");
766 debug_assert!(!self.is_dev(), "min is not allowed on dev versions");
767 if let VersionInner::Small { small } = &mut self.inner {
768 if small.set_min(value) {
769 return self;
770 }
771 }
772 self.make_full().min = value;
773 self
774 }
775
776 #[inline]
782 #[must_use]
783 pub fn with_max(mut self, value: Option<u64>) -> Self {
784 debug_assert!(
785 !self.is_post(),
786 "max is not allowed on post-release versions"
787 );
788 debug_assert!(!self.is_dev(), "max is not allowed on dev versions");
789 if let VersionInner::Small { small } = &mut self.inner {
790 if small.set_max(value) {
791 return self;
792 }
793 }
794 self.make_full().max = value;
795 self
796 }
797
798 fn make_full(&mut self) -> &mut VersionFull {
801 if let VersionInner::Small { ref small } = self.inner {
802 let full = VersionFull {
803 epoch: small.epoch(),
804 release: self.release().to_vec(),
805 min: small.min(),
806 max: small.max(),
807 pre: small.pre(),
808 post: small.post(),
809 dev: small.dev(),
810 local: small.local(),
811 };
812 *self = Self {
813 inner: VersionInner::Full {
814 full: Arc::new(full),
815 },
816 };
817 }
818 match &mut self.inner {
819 VersionInner::Full { full } => Arc::make_mut(full),
820 VersionInner::Small { .. } => unreachable!(),
821 }
822 }
823
824 #[cold]
831 #[inline(never)]
832 fn cmp_slow(&self, other: &Self) -> Ordering {
833 match self.epoch().cmp(&other.epoch()) {
834 Ordering::Less => {
835 return Ordering::Less;
836 }
837 Ordering::Equal => {}
838 Ordering::Greater => {
839 return Ordering::Greater;
840 }
841 }
842
843 match compare_release(&self.release(), &other.release()) {
844 Ordering::Less => {
845 return Ordering::Less;
846 }
847 Ordering::Equal => {}
848 Ordering::Greater => {
849 return Ordering::Greater;
850 }
851 }
852
853 sortable_tuple(self).cmp(&sortable_tuple(other))
855 }
856}
857
858impl<'de> Deserialize<'de> for Version {
859 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
860 where
861 D: Deserializer<'de>,
862 {
863 struct Visitor;
864
865 impl de::Visitor<'_> for Visitor {
866 type Value = Version;
867
868 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
869 f.write_str("a string")
870 }
871
872 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
873 Version::from_str(v).map_err(de::Error::custom)
874 }
875 }
876
877 deserializer.deserialize_str(Visitor)
878 }
879}
880
881impl Serialize for Version {
883 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
884 where
885 S: Serializer,
886 {
887 serializer.collect_str(self)
888 }
889}
890
891impl std::fmt::Display for Version {
893 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
894 if self.epoch() != 0 {
895 write!(f, "{}!", self.epoch())?;
896 }
897 let release = self.release();
898 let mut release_iter = release.iter();
899 if let Some(first) = release_iter.next() {
900 write!(f, "{first}")?;
901 for n in release_iter {
902 write!(f, ".{n}")?;
903 }
904 }
905
906 if let Some(Prerelease { kind, number }) = self.pre() {
907 write!(f, "{kind}{number}")?;
908 }
909 if let Some(post) = self.post() {
910 write!(f, ".post{post}")?;
911 }
912 if let Some(dev) = self.dev() {
913 write!(f, ".dev{dev}")?;
914 }
915 if !self.local().is_empty() {
916 match self.local() {
917 LocalVersionSlice::Segments(_) => {
918 write!(f, "+{}", self.local())?;
919 }
920 LocalVersionSlice::Max => {
921 write!(f, "+")?;
922 }
923 }
924 }
925 Ok(())
926 }
927}
928
929impl std::fmt::Debug for Version {
930 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
931 write!(f, "\"{self}\"")
932 }
933}
934
935impl PartialEq<Self> for Version {
936 #[inline]
937 fn eq(&self, other: &Self) -> bool {
938 self.cmp(other) == Ordering::Equal
939 }
940}
941
942impl Eq for Version {}
943
944impl Hash for Version {
945 #[inline]
947 fn hash<H: Hasher>(&self, state: &mut H) {
948 self.epoch().hash(state);
949 for i in self.release().iter().rev().skip_while(|x| **x == 0) {
951 i.hash(state);
952 }
953 self.pre().hash(state);
954 self.dev().hash(state);
955 self.post().hash(state);
956 self.local().hash(state);
957 }
958}
959
960impl CacheKey for Version {
961 fn cache_key(&self, state: &mut CacheKeyHasher) {
962 self.epoch().cache_key(state);
963
964 let release = self.release();
965 release.len().cache_key(state);
966 for segment in release.iter() {
967 segment.cache_key(state);
968 }
969
970 if let Some(pre) = self.pre() {
971 1u8.cache_key(state);
972 match pre.kind {
973 PrereleaseKind::Alpha => 0u8.cache_key(state),
974 PrereleaseKind::Beta => 1u8.cache_key(state),
975 PrereleaseKind::Rc => 2u8.cache_key(state),
976 }
977 pre.number.cache_key(state);
978 } else {
979 0u8.cache_key(state);
980 }
981
982 if let Some(post) = self.post() {
983 1u8.cache_key(state);
984 post.cache_key(state);
985 } else {
986 0u8.cache_key(state);
987 }
988
989 if let Some(dev) = self.dev() {
990 1u8.cache_key(state);
991 dev.cache_key(state);
992 } else {
993 0u8.cache_key(state);
994 }
995
996 self.local().cache_key(state);
997 }
998}
999
1000impl PartialOrd<Self> for Version {
1001 #[inline]
1002 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1003 Some(self.cmp(other))
1004 }
1005}
1006
1007impl Ord for Version {
1008 #[inline]
1012 fn cmp(&self, other: &Self) -> Ordering {
1013 match (&self.inner, &other.inner) {
1014 (VersionInner::Small { small: small1 }, VersionInner::Small { small: small2 }) => {
1015 small1.repr.cmp(&small2.repr)
1016 }
1017 _ => self.cmp_slow(other),
1018 }
1019 }
1020}
1021
1022impl FromStr for Version {
1023 type Err = VersionParseError;
1024
1025 fn from_str(version: &str) -> Result<Self, Self::Err> {
1029 Parser::new(version.as_bytes()).parse()
1030 }
1031}
1032
1033#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
1035pub enum BumpCommand {
1036 BumpRelease {
1038 index: usize,
1040 value: Option<u64>,
1042 },
1043 BumpPrerelease {
1045 kind: PrereleaseKind,
1047 value: Option<u64>,
1049 },
1050 MakeStable,
1052 BumpPost {
1054 value: Option<u64>,
1056 },
1057 BumpDev {
1059 value: Option<u64>,
1061 },
1062}
1063
1064#[derive(Clone, Debug)]
1139#[cfg_attr(
1140 feature = "rkyv",
1141 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1142)]
1143#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1144struct VersionSmall {
1145 len: u8,
1150 repr: u64,
1152 _force_niche: NonZero<u8>,
1154}
1155
1156impl VersionSmall {
1157 const SUFFIX_MIN: u64 = 0;
1172 const SUFFIX_DEV: u64 = 1;
1173 const SUFFIX_PRE_ALPHA: u64 = 2;
1174 const SUFFIX_PRE_BETA: u64 = 3;
1175 const SUFFIX_PRE_RC: u64 = 4;
1176 const SUFFIX_NONE: u64 = 5;
1177 const SUFFIX_LOCAL: u64 = 6;
1178 const SUFFIX_POST: u64 = 7;
1179 const SUFFIX_MAX: u64 = 8;
1180
1181 const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
1187 const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
1189 const SUFFIX_VERSION_BIT_LEN: u64 = 20;
1193 const SUFFIX_KIND_MASK: u64 = 0b1111;
1198
1199 #[inline]
1200 fn new() -> Self {
1201 Self {
1202 _force_niche: NonZero::<u8>::MIN,
1203 repr: Self::SUFFIX_NONE << Self::SUFFIX_VERSION_BIT_LEN,
1204 len: 0,
1205 }
1206 }
1207
1208 #[inline]
1209 #[expect(clippy::unused_self)]
1210 fn epoch(&self) -> u64 {
1211 0
1212 }
1213
1214 #[inline]
1215 #[expect(clippy::unused_self)]
1216 fn set_epoch(&mut self, value: u64) -> bool {
1217 if value != 0 {
1218 return false;
1219 }
1220 true
1221 }
1222
1223 #[inline]
1224 fn clear_release(&mut self) {
1225 self.repr &= !Self::SUFFIX_RELEASE_MASK;
1226 self.len = 0;
1227 }
1228
1229 #[inline]
1230 fn push_release(&mut self, n: u64) -> bool {
1231 if self.len == 0 {
1232 if n > u64::from(u16::MAX) {
1233 return false;
1234 }
1235 self.repr |= n << 48;
1236 self.len = 1;
1237 true
1238 } else {
1239 if n > u64::from(u8::MAX) {
1240 return false;
1241 }
1242 if self.len >= 4 {
1243 return false;
1244 }
1245 let shift = 48 - (usize::from(self.len) * 8);
1246 self.repr |= n << shift;
1247 self.len += 1;
1248 true
1249 }
1250 }
1251
1252 #[inline]
1253 fn post(&self) -> Option<u64> {
1254 if self.suffix_kind() == Self::SUFFIX_POST {
1255 Some(self.suffix_version())
1256 } else {
1257 None
1258 }
1259 }
1260
1261 #[inline]
1262 fn set_post(&mut self, value: Option<u64>) -> bool {
1263 let suffix_kind = self.suffix_kind();
1264 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1265 return value.is_none();
1266 }
1267 match value {
1268 None => {
1269 self.set_suffix_kind(Self::SUFFIX_NONE);
1270 }
1271 Some(number) => {
1272 if number > Self::SUFFIX_VERSION_MASK {
1273 return false;
1274 }
1275 self.set_suffix_kind(Self::SUFFIX_POST);
1276 self.set_suffix_version(number);
1277 }
1278 }
1279 true
1280 }
1281
1282 #[inline]
1283 fn pre(&self) -> Option<Prerelease> {
1284 let (kind, number) = (self.suffix_kind(), self.suffix_version());
1285 if kind == Self::SUFFIX_PRE_ALPHA {
1286 Some(Prerelease {
1287 kind: PrereleaseKind::Alpha,
1288 number,
1289 })
1290 } else if kind == Self::SUFFIX_PRE_BETA {
1291 Some(Prerelease {
1292 kind: PrereleaseKind::Beta,
1293 number,
1294 })
1295 } else if kind == Self::SUFFIX_PRE_RC {
1296 Some(Prerelease {
1297 kind: PrereleaseKind::Rc,
1298 number,
1299 })
1300 } else {
1301 None
1302 }
1303 }
1304
1305 #[inline]
1306 fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1307 let suffix_kind = self.suffix_kind();
1308 if !(suffix_kind == Self::SUFFIX_NONE
1309 || suffix_kind == Self::SUFFIX_PRE_ALPHA
1310 || suffix_kind == Self::SUFFIX_PRE_BETA
1311 || suffix_kind == Self::SUFFIX_PRE_RC)
1312 {
1313 return value.is_none();
1314 }
1315 match value {
1316 None => {
1317 self.set_suffix_kind(Self::SUFFIX_NONE);
1318 }
1319 Some(Prerelease { kind, number }) => {
1320 if number > Self::SUFFIX_VERSION_MASK {
1321 return false;
1322 }
1323 match kind {
1324 PrereleaseKind::Alpha => {
1325 self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1326 }
1327 PrereleaseKind::Beta => {
1328 self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1329 }
1330 PrereleaseKind::Rc => {
1331 self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1332 }
1333 }
1334 self.set_suffix_version(number);
1335 }
1336 }
1337 true
1338 }
1339
1340 #[inline]
1341 fn dev(&self) -> Option<u64> {
1342 if self.suffix_kind() == Self::SUFFIX_DEV {
1343 Some(self.suffix_version())
1344 } else {
1345 None
1346 }
1347 }
1348
1349 #[inline]
1350 fn set_dev(&mut self, value: Option<u64>) -> bool {
1351 let suffix_kind = self.suffix_kind();
1352 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1353 return value.is_none();
1354 }
1355 match value {
1356 None => {
1357 self.set_suffix_kind(Self::SUFFIX_NONE);
1358 }
1359 Some(number) => {
1360 if number > Self::SUFFIX_VERSION_MASK {
1361 return false;
1362 }
1363 self.set_suffix_kind(Self::SUFFIX_DEV);
1364 self.set_suffix_version(number);
1365 }
1366 }
1367 true
1368 }
1369
1370 #[inline]
1371 fn min(&self) -> Option<u64> {
1372 if self.suffix_kind() == Self::SUFFIX_MIN {
1373 Some(self.suffix_version())
1374 } else {
1375 None
1376 }
1377 }
1378
1379 #[inline]
1380 fn set_min(&mut self, value: Option<u64>) -> bool {
1381 let suffix_kind = self.suffix_kind();
1382 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1383 return value.is_none();
1384 }
1385 match value {
1386 None => {
1387 self.set_suffix_kind(Self::SUFFIX_NONE);
1388 }
1389 Some(number) => {
1390 if number > Self::SUFFIX_VERSION_MASK {
1391 return false;
1392 }
1393 self.set_suffix_kind(Self::SUFFIX_MIN);
1394 self.set_suffix_version(number);
1395 }
1396 }
1397 true
1398 }
1399
1400 #[inline]
1401 fn max(&self) -> Option<u64> {
1402 if self.suffix_kind() == Self::SUFFIX_MAX {
1403 Some(self.suffix_version())
1404 } else {
1405 None
1406 }
1407 }
1408
1409 #[inline]
1410 fn set_max(&mut self, value: Option<u64>) -> bool {
1411 let suffix_kind = self.suffix_kind();
1412 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1413 return value.is_none();
1414 }
1415 match value {
1416 None => {
1417 self.set_suffix_kind(Self::SUFFIX_NONE);
1418 }
1419 Some(number) => {
1420 if number > Self::SUFFIX_VERSION_MASK {
1421 return false;
1422 }
1423 self.set_suffix_kind(Self::SUFFIX_MAX);
1424 self.set_suffix_version(number);
1425 }
1426 }
1427 true
1428 }
1429
1430 #[inline]
1431 fn local(&self) -> LocalVersion {
1432 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1433 LocalVersion::Max
1434 } else {
1435 LocalVersion::empty()
1436 }
1437 }
1438
1439 #[inline]
1440 fn local_slice(&self) -> LocalVersionSlice<'_> {
1441 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1442 LocalVersionSlice::Max
1443 } else {
1444 LocalVersionSlice::empty()
1445 }
1446 }
1447
1448 #[inline]
1449 fn set_local(&mut self, value: LocalVersion) -> bool {
1450 let suffix_kind = self.suffix_kind();
1451 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1452 return value.is_empty();
1453 }
1454 match value {
1455 LocalVersion::Max => {
1456 self.set_suffix_kind(Self::SUFFIX_LOCAL);
1457 true
1458 }
1459 LocalVersion::Segments(segments) if segments.is_empty() => {
1460 self.set_suffix_kind(Self::SUFFIX_NONE);
1461 true
1462 }
1463 LocalVersion::Segments(_) => false,
1464 }
1465 }
1466
1467 #[inline]
1468 fn suffix_kind(&self) -> u64 {
1469 let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1470 debug_assert!(kind <= Self::SUFFIX_MAX);
1471 kind
1472 }
1473
1474 #[inline]
1475 fn set_suffix_kind(&mut self, kind: u64) {
1476 debug_assert!(kind <= Self::SUFFIX_MAX);
1477 self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1478 self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1479 if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1480 self.set_suffix_version(0);
1481 }
1482 }
1483
1484 #[inline]
1485 fn suffix_version(&self) -> u64 {
1486 self.repr & Self::SUFFIX_VERSION_MASK
1487 }
1488
1489 #[inline]
1490 fn set_suffix_version(&mut self, value: u64) {
1491 debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1492 self.repr &= !Self::SUFFIX_VERSION_MASK;
1493 self.repr |= value;
1494 }
1495}
1496
1497#[derive(Clone, Debug)]
1506#[cfg_attr(
1507 feature = "rkyv",
1508 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1509)]
1510#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1511struct VersionFull {
1512 epoch: u64,
1517 release: Vec<u64>,
1523 pre: Option<Prerelease>,
1529 post: Option<u64>,
1533 dev: Option<u64>,
1537 local: LocalVersion,
1550 min: Option<u64>,
1554 max: Option<u64>,
1558}
1559
1560#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1579pub struct VersionPattern {
1580 version: Version,
1581 wildcard: bool,
1582}
1583
1584impl VersionPattern {
1585 #[inline]
1588 pub fn verbatim(version: Version) -> Self {
1589 Self {
1590 version,
1591 wildcard: false,
1592 }
1593 }
1594
1595 #[inline]
1598 pub fn wildcard(version: Version) -> Self {
1599 Self {
1600 version,
1601 wildcard: true,
1602 }
1603 }
1604
1605 #[inline]
1607 pub fn version(&self) -> &Version {
1608 &self.version
1609 }
1610
1611 #[inline]
1613 pub fn into_version(self) -> Version {
1614 self.version
1615 }
1616
1617 #[inline]
1619 pub fn is_wildcard(&self) -> bool {
1620 self.wildcard
1621 }
1622}
1623
1624impl FromStr for VersionPattern {
1625 type Err = VersionPatternParseError;
1626
1627 fn from_str(version: &str) -> Result<Self, VersionPatternParseError> {
1628 Parser::new(version.as_bytes()).parse_pattern()
1629 }
1630}
1631
1632pub struct Release<'a> {
1637 inner: ReleaseInner<'a>,
1638}
1639
1640enum ReleaseInner<'a> {
1641 Small0([u64; 0]),
1645 Small1([u64; 1]),
1646 Small2([u64; 2]),
1647 Small3([u64; 3]),
1648 Small4([u64; 4]),
1649 Full(&'a [u64]),
1650}
1651
1652impl Deref for Release<'_> {
1653 type Target = [u64];
1654
1655 fn deref(&self) -> &Self::Target {
1656 match &self.inner {
1657 ReleaseInner::Small0(v) => v,
1658 ReleaseInner::Small1(v) => v,
1659 ReleaseInner::Small2(v) => v,
1660 ReleaseInner::Small3(v) => v,
1661 ReleaseInner::Small4(v) => v,
1662 ReleaseInner::Full(v) => v,
1663 }
1664 }
1665}
1666
1667#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1669#[cfg_attr(
1670 feature = "rkyv",
1671 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1672)]
1673#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1674pub struct Prerelease {
1675 pub kind: PrereleaseKind,
1677 pub number: u64,
1679}
1680
1681#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1685#[cfg_attr(
1686 feature = "rkyv",
1687 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1688)]
1689#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1690pub enum PrereleaseKind {
1691 Alpha,
1693 Beta,
1695 Rc,
1697}
1698
1699impl std::fmt::Display for PrereleaseKind {
1700 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1701 match self {
1702 Self::Alpha => write!(f, "a"),
1703 Self::Beta => write!(f, "b"),
1704 Self::Rc => write!(f, "rc"),
1705 }
1706 }
1707}
1708
1709impl std::fmt::Display for Prerelease {
1710 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1711 write!(f, "{}{}", self.kind, self.number)
1712 }
1713}
1714
1715#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1718#[cfg_attr(
1719 feature = "rkyv",
1720 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1721)]
1722#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1723pub enum LocalVersion {
1724 Segments(Vec<LocalSegment>),
1726 Max,
1728}
1729
1730#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1732pub enum LocalVersionSlice<'a> {
1733 Segments(&'a [LocalSegment]),
1735 Max,
1737}
1738
1739impl LocalVersion {
1740 pub fn empty() -> Self {
1742 Self::Segments(Vec::new())
1743 }
1744
1745 pub fn is_empty(&self) -> bool {
1747 match self {
1748 Self::Segments(segments) => segments.is_empty(),
1749 Self::Max => false,
1750 }
1751 }
1752
1753 pub fn as_slice(&self) -> LocalVersionSlice<'_> {
1755 match self {
1756 Self::Segments(segments) => LocalVersionSlice::Segments(segments),
1757 Self::Max => LocalVersionSlice::Max,
1758 }
1759 }
1760
1761 pub fn clear(&mut self) {
1763 match self {
1764 Self::Segments(segments) => segments.clear(),
1765 Self::Max => *self = Self::Segments(Vec::new()),
1766 }
1767 }
1768}
1769
1770impl std::fmt::Display for LocalVersionSlice<'_> {
1775 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1776 match self {
1777 Self::Segments(segments) => {
1778 for (i, segment) in segments.iter().enumerate() {
1779 if i > 0 {
1780 write!(f, ".")?;
1781 }
1782 write!(f, "{segment}")?;
1783 }
1784 Ok(())
1785 }
1786 Self::Max => write!(f, "[max]"),
1787 }
1788 }
1789}
1790
1791impl CacheKey for LocalVersionSlice<'_> {
1792 fn cache_key(&self, state: &mut CacheKeyHasher) {
1793 match self {
1794 Self::Segments(segments) => {
1795 0u8.cache_key(state);
1796 segments.len().cache_key(state);
1797 for segment in *segments {
1798 segment.cache_key(state);
1799 }
1800 }
1801 Self::Max => {
1802 1u8.cache_key(state);
1803 }
1804 }
1805 }
1806}
1807
1808impl PartialOrd for LocalVersionSlice<'_> {
1809 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1810 Some(self.cmp(other))
1811 }
1812}
1813
1814impl Ord for LocalVersionSlice<'_> {
1815 fn cmp(&self, other: &Self) -> Ordering {
1816 match (self, other) {
1817 (LocalVersionSlice::Segments(lv1), LocalVersionSlice::Segments(lv2)) => lv1.cmp(lv2),
1818 (LocalVersionSlice::Segments(_), LocalVersionSlice::Max) => Ordering::Less,
1819 (LocalVersionSlice::Max, LocalVersionSlice::Segments(_)) => Ordering::Greater,
1820 (LocalVersionSlice::Max, LocalVersionSlice::Max) => Ordering::Equal,
1821 }
1822 }
1823}
1824
1825impl LocalVersionSlice<'_> {
1826 pub const fn empty() -> Self {
1828 Self::Segments(&[])
1829 }
1830
1831 pub fn is_empty(&self) -> bool {
1833 matches!(self, &Self::Segments(&[]))
1834 }
1835}
1836
1837#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1853#[cfg_attr(
1854 feature = "rkyv",
1855 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1856)]
1857#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1858pub enum LocalSegment {
1859 String(String),
1861 Number(u64),
1863}
1864
1865impl std::fmt::Display for LocalSegment {
1866 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1867 match self {
1868 Self::String(string) => write!(f, "{string}"),
1869 Self::Number(number) => write!(f, "{number}"),
1870 }
1871 }
1872}
1873
1874impl CacheKey for LocalSegment {
1875 fn cache_key(&self, state: &mut CacheKeyHasher) {
1876 match self {
1877 Self::String(string) => {
1878 0u8.cache_key(state);
1879 string.cache_key(state);
1880 }
1881 Self::Number(number) => {
1882 1u8.cache_key(state);
1883 number.cache_key(state);
1884 }
1885 }
1886 }
1887}
1888
1889impl PartialOrd for LocalSegment {
1890 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1891 Some(self.cmp(other))
1892 }
1893}
1894
1895impl Ord for LocalSegment {
1896 fn cmp(&self, other: &Self) -> Ordering {
1897 match (self, other) {
1899 (Self::Number(n1), Self::Number(n2)) => n1.cmp(n2),
1900 (Self::String(s1), Self::String(s2)) => s1.cmp(s2),
1901 (Self::Number(_), Self::String(_)) => Ordering::Greater,
1902 (Self::String(_), Self::Number(_)) => Ordering::Less,
1903 }
1904 }
1905}
1906
1907#[derive(Debug)]
1917struct Parser<'a> {
1918 v: &'a [u8],
1920 i: usize,
1922 epoch: u64,
1924 release: ReleaseNumbers,
1926 pre: Option<Prerelease>,
1928 post: Option<u64>,
1930 dev: Option<u64>,
1932 local: Vec<LocalSegment>,
1934 wildcard: bool,
1938}
1939
1940impl<'a> Parser<'a> {
1941 #[expect(clippy::byte_char_slices)]
1944 const SEPARATOR: ByteSet = ByteSet::new(&[b'.', b'_', b'-']);
1945
1946 fn new(version: &'a [u8]) -> Self {
1948 Parser {
1949 v: version,
1950 i: 0,
1951 epoch: 0,
1952 release: ReleaseNumbers::new(),
1953 pre: None,
1954 post: None,
1955 dev: None,
1956 local: vec![],
1957 wildcard: false,
1958 }
1959 }
1960
1961 fn parse(self) -> Result<Version, VersionParseError> {
1965 match self.parse_pattern() {
1966 Ok(vpat) => {
1967 if vpat.is_wildcard() {
1968 Err(ErrorKind::Wildcard.into())
1969 } else {
1970 Ok(vpat.into_version())
1971 }
1972 }
1973 Err(err) => match *err.kind {
1980 PatternErrorKind::Version(err) => Err(err),
1981 PatternErrorKind::WildcardNotTrailing => Err(ErrorKind::Wildcard.into()),
1982 },
1983 }
1984 }
1985
1986 fn parse_pattern(mut self) -> Result<VersionPattern, VersionPatternParseError> {
1988 if let Some(vpat) = self.parse_fast() {
1989 return Ok(vpat);
1990 }
1991 self.bump_while(|byte| byte.is_ascii_whitespace());
1992 self.bump_if("v");
1993 self.parse_epoch_and_initial_release()?;
1994 self.parse_rest_of_release()?;
1995 if self.parse_wildcard()? {
1996 return Ok(self.into_pattern());
1997 }
1998 self.parse_pre()?;
1999 self.parse_post()?;
2000 self.parse_dev()?;
2001 self.parse_local()?;
2002 self.bump_while(|byte| byte.is_ascii_whitespace());
2003 if !self.is_done() {
2004 let version = String::from_utf8_lossy(&self.v[..self.i]).into_owned();
2005 let remaining = String::from_utf8_lossy(&self.v[self.i..]).into_owned();
2006 return Err(ErrorKind::UnexpectedEnd { version, remaining }.into());
2007 }
2008 Ok(self.into_pattern())
2009 }
2010
2011 fn parse_fast(&self) -> Option<VersionPattern> {
2021 let (mut prev_digit, mut cur, mut release, mut len) = (false, 0u8, [0u8; 4], 0u8);
2022 for &byte in self.v {
2023 if byte == b'.' {
2024 if !prev_digit {
2025 return None;
2026 }
2027 prev_digit = false;
2028 *release.get_mut(usize::from(len))? = cur;
2029 len += 1;
2030 cur = 0;
2031 } else {
2032 let digit = byte.checked_sub(b'0')?;
2033 if digit > 9 {
2034 return None;
2035 }
2036 prev_digit = true;
2037 cur = cur.checked_mul(10)?.checked_add(digit)?;
2038 }
2039 }
2040 if !prev_digit {
2041 return None;
2042 }
2043 *release.get_mut(usize::from(len))? = cur;
2044 len += 1;
2045 let small = VersionSmall {
2046 _force_niche: NonZero::<u8>::MIN,
2047 repr: (u64::from(release[0]) << 48)
2048 | (u64::from(release[1]) << 40)
2049 | (u64::from(release[2]) << 32)
2050 | (u64::from(release[3]) << 24)
2051 | (VersionSmall::SUFFIX_NONE << VersionSmall::SUFFIX_VERSION_BIT_LEN),
2052
2053 len,
2054 };
2055 let inner = VersionInner::Small { small };
2056 let version = Version { inner };
2057 Some(VersionPattern {
2058 version,
2059 wildcard: false,
2060 })
2061 }
2062
2063 fn parse_epoch_and_initial_release(&mut self) -> Result<(), VersionPatternParseError> {
2074 let first_number = self.parse_number()?.ok_or(ErrorKind::NoLeadingNumber)?;
2075 let first_release_number = if self.bump_if("!") {
2076 self.epoch = first_number;
2077 self.parse_number()?
2078 .ok_or(ErrorKind::NoLeadingReleaseNumber)?
2079 } else {
2080 first_number
2081 };
2082 self.release.push(first_release_number);
2083 Ok(())
2084 }
2085
2086 fn parse_rest_of_release(&mut self) -> Result<(), VersionPatternParseError> {
2097 while self.bump_if(".") {
2098 let Some(n) = self.parse_number()? else {
2099 self.unbump();
2100 break;
2101 };
2102 self.release.push(n);
2103 }
2104 Ok(())
2105 }
2106
2107 fn parse_wildcard(&mut self) -> Result<bool, VersionPatternParseError> {
2116 if !self.bump_if(".*") {
2117 return Ok(false);
2118 }
2119 if !self.is_done() {
2120 return Err(PatternErrorKind::WildcardNotTrailing.into());
2121 }
2122 self.wildcard = true;
2123 Ok(true)
2124 }
2125
2126 fn parse_pre(&mut self) -> Result<(), VersionPatternParseError> {
2132 const SPELLINGS: StringSet =
2141 StringSet::new(&["alpha", "beta", "preview", "pre", "rc", "a", "b", "c"]);
2142 const MAP: &[PrereleaseKind] = &[
2143 PrereleaseKind::Alpha,
2144 PrereleaseKind::Beta,
2145 PrereleaseKind::Rc,
2146 PrereleaseKind::Rc,
2147 PrereleaseKind::Rc,
2148 PrereleaseKind::Alpha,
2149 PrereleaseKind::Beta,
2150 PrereleaseKind::Rc,
2151 ];
2152
2153 let oldpos = self.i;
2154 self.bump_if_byte_set(&Parser::SEPARATOR);
2155 let Some(spelling) = self.bump_if_string_set(&SPELLINGS) else {
2156 self.reset(oldpos);
2161 return Ok(());
2162 };
2163 let kind = MAP[spelling];
2164 self.bump_if_byte_set(&Parser::SEPARATOR);
2165 let number = self.parse_number()?.unwrap_or(0);
2168 self.pre = Some(Prerelease { kind, number });
2169 Ok(())
2170 }
2171
2172 fn parse_post(&mut self) -> Result<(), VersionPatternParseError> {
2178 const SPELLINGS: StringSet = StringSet::new(&["post", "rev", "r"]);
2179
2180 let oldpos = self.i;
2181 if self.bump_if("-") {
2182 if let Some(n) = self.parse_number()? {
2183 self.post = Some(n);
2184 return Ok(());
2185 }
2186 self.reset(oldpos);
2187 }
2188 self.bump_if_byte_set(&Parser::SEPARATOR);
2189 if self.bump_if_string_set(&SPELLINGS).is_none() {
2190 self.reset(oldpos);
2194 return Ok(());
2195 }
2196 self.bump_if_byte_set(&Parser::SEPARATOR);
2197 self.post = Some(self.parse_number()?.unwrap_or(0));
2200 Ok(())
2201 }
2202
2203 fn parse_dev(&mut self) -> Result<(), VersionPatternParseError> {
2209 let oldpos = self.i;
2210 self.bump_if_byte_set(&Parser::SEPARATOR);
2211 if !self.bump_if("dev") {
2212 self.reset(oldpos);
2216 return Ok(());
2217 }
2218 self.bump_if_byte_set(&Parser::SEPARATOR);
2219 self.dev = Some(self.parse_number()?.unwrap_or(0));
2222 Ok(())
2223 }
2224
2225 fn parse_local(&mut self) -> Result<(), VersionPatternParseError> {
2233 if !self.bump_if("+") {
2234 return Ok(());
2235 }
2236 let mut precursor = '+';
2237 loop {
2238 let first = self.bump_while(|byte| byte.is_ascii_alphanumeric());
2239 if first.is_empty() {
2240 return Err(ErrorKind::LocalEmpty { precursor }.into());
2241 }
2242 self.local.push(if let Ok(number) = parse_u64(first) {
2243 LocalSegment::Number(number)
2244 } else {
2245 let string = String::from_utf8(first.to_ascii_lowercase())
2246 .expect("ASCII alphanumerics are always valid UTF-8");
2247 LocalSegment::String(string)
2248 });
2249 let Some(byte) = self.bump_if_byte_set(&Parser::SEPARATOR) else {
2250 break;
2251 };
2252 precursor = char::from(byte);
2253 }
2254 Ok(())
2255 }
2256
2257 fn parse_number(&mut self) -> Result<Option<u64>, VersionPatternParseError> {
2265 let digits = self.bump_while(|ch| ch.is_ascii_digit());
2266 if digits.is_empty() {
2267 return Ok(None);
2268 }
2269 let n = parse_u64(digits)?;
2270 if n == u64::MAX {
2276 return Err(ErrorKind::NumberTooBig {
2277 bytes: digits.to_vec(),
2278 }
2279 .into());
2280 }
2281 Ok(Some(n))
2282 }
2283
2284 fn into_pattern(self) -> VersionPattern {
2292 assert!(
2293 self.release.len() > 0,
2294 "version with no release numbers is invalid"
2295 );
2296 let version = Version::new(self.release.as_slice())
2297 .with_epoch(self.epoch)
2298 .with_pre(self.pre)
2299 .with_post(self.post)
2300 .with_dev(self.dev)
2301 .with_local(LocalVersion::Segments(self.local));
2302 VersionPattern {
2303 version,
2304 wildcard: self.wildcard,
2305 }
2306 }
2307
2308 fn bump_while(&mut self, mut predicate: impl FnMut(u8) -> bool) -> &'a [u8] {
2315 let start = self.i;
2316 while !self.is_done() && predicate(self.byte()) {
2317 self.i = self.i.saturating_add(1);
2318 }
2319 &self.v[start..self.i]
2320 }
2321
2322 fn bump_if(&mut self, string: &str) -> bool {
2327 if self.is_done() {
2328 return false;
2329 }
2330 if starts_with_ignore_ascii_case(string.as_bytes(), &self.v[self.i..]) {
2331 self.i = self
2332 .i
2333 .checked_add(string.len())
2334 .expect("valid offset because of prefix");
2335 true
2336 } else {
2337 false
2338 }
2339 }
2340
2341 fn bump_if_string_set(&mut self, set: &StringSet) -> Option<usize> {
2345 let index = set.starts_with(&self.v[self.i..])?;
2346 let found = &set.strings[index];
2347 self.i = self
2348 .i
2349 .checked_add(found.len())
2350 .expect("valid offset because of prefix");
2351 Some(index)
2352 }
2353
2354 fn bump_if_byte_set(&mut self, set: &ByteSet) -> Option<u8> {
2358 let found = set.starts_with(&self.v[self.i..])?;
2359 self.i = self
2360 .i
2361 .checked_add(1)
2362 .expect("valid offset because of prefix");
2363 Some(found)
2364 }
2365
2366 fn unbump(&mut self) {
2375 self.i = self.i.checked_sub(1).expect("not at beginning of input");
2376 }
2377
2378 fn reset(&mut self, offset: usize) {
2384 assert!(offset <= self.v.len());
2385 self.i = offset;
2386 }
2387
2388 fn byte(&self) -> u8 {
2394 self.v[self.i]
2395 }
2396
2397 fn is_done(&self) -> bool {
2399 self.i >= self.v.len()
2400 }
2401}
2402
2403#[derive(Debug)]
2407enum ReleaseNumbers {
2408 Inline { numbers: [u64; 4], len: usize },
2409 Vec(Vec<u64>),
2410}
2411
2412impl ReleaseNumbers {
2413 fn new() -> Self {
2415 Self::Inline {
2416 numbers: [0; 4],
2417 len: 0,
2418 }
2419 }
2420
2421 fn push(&mut self, n: u64) {
2424 match *self {
2425 Self::Inline {
2426 ref mut numbers,
2427 ref mut len,
2428 } => {
2429 assert!(*len <= 4);
2430 if *len == 4 {
2431 let mut numbers = numbers.to_vec();
2432 numbers.push(n);
2433 *self = Self::Vec(numbers.clone());
2434 } else {
2435 numbers[*len] = n;
2436 *len += 1;
2437 }
2438 }
2439 Self::Vec(ref mut numbers) => {
2440 numbers.push(n);
2441 }
2442 }
2443 }
2444
2445 fn len(&self) -> usize {
2447 self.as_slice().len()
2448 }
2449
2450 fn as_slice(&self) -> &[u64] {
2452 match self {
2453 Self::Inline { numbers, len } => &numbers[..*len],
2454 Self::Vec(vec) => vec,
2455 }
2456 }
2457}
2458
2459struct StringSet {
2464 first_byte: ByteSet,
2468 strings: &'static [&'static str],
2470}
2471
2472impl StringSet {
2473 const fn new(strings: &'static [&'static str]) -> Self {
2479 assert!(
2480 strings.len() <= 20,
2481 "only a small number of strings are supported"
2482 );
2483 let (mut firsts, mut firsts_len) = ([0u8; 20], 0);
2484 let mut i = 0;
2485 while i < strings.len() {
2486 assert!(
2487 !strings[i].is_empty(),
2488 "every string in set should be non-empty",
2489 );
2490 firsts[firsts_len] = strings[i].as_bytes()[0];
2491 firsts_len += 1;
2492 i += 1;
2493 }
2494 let first_byte = ByteSet::new(&firsts);
2495 Self {
2496 first_byte,
2497 strings,
2498 }
2499 }
2500
2501 fn starts_with(&self, haystack: &[u8]) -> Option<usize> {
2504 let first_byte = self.first_byte.starts_with(haystack)?;
2505 for (i, &string) in self.strings.iter().enumerate() {
2506 let bytes = string.as_bytes();
2507 if bytes[0].eq_ignore_ascii_case(&first_byte)
2508 && starts_with_ignore_ascii_case(bytes, haystack)
2509 {
2510 return Some(i);
2511 }
2512 }
2513 None
2514 }
2515}
2516
2517struct ByteSet {
2519 set: [bool; 256],
2520}
2521
2522impl ByteSet {
2523 const fn new(bytes: &[u8]) -> Self {
2525 let mut set = [false; 256];
2526 let mut i = 0;
2527 while i < bytes.len() {
2528 set[bytes[i].to_ascii_uppercase() as usize] = true;
2529 set[bytes[i].to_ascii_lowercase() as usize] = true;
2530 i += 1;
2531 }
2532 Self { set }
2533 }
2534
2535 fn starts_with(&self, haystack: &[u8]) -> Option<u8> {
2538 let byte = *haystack.first()?;
2539 if self.contains(byte) {
2540 Some(byte)
2541 } else {
2542 None
2543 }
2544 }
2545
2546 fn contains(&self, byte: u8) -> bool {
2548 self.set[usize::from(byte)]
2549 }
2550}
2551
2552impl std::fmt::Debug for ByteSet {
2553 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2554 let mut set = f.debug_set();
2555 for byte in 0..=255 {
2556 if self.contains(byte) {
2557 set.entry(&char::from(byte));
2558 }
2559 }
2560 set.finish()
2561 }
2562}
2563
2564#[derive(Clone, Debug, Eq, PartialEq)]
2566pub struct VersionParseError {
2567 kind: Box<ErrorKind>,
2568}
2569
2570impl std::error::Error for VersionParseError {}
2571
2572impl std::fmt::Display for VersionParseError {
2573 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2574 match *self.kind {
2575 ErrorKind::Wildcard => write!(f, "wildcards are not allowed in a version"),
2576 ErrorKind::InvalidDigit { got } if got.is_ascii() => {
2577 write!(f, "expected ASCII digit, but found {:?}", char::from(got))
2578 }
2579 ErrorKind::InvalidDigit { got } => {
2580 write!(
2581 f,
2582 "expected ASCII digit, but found non-ASCII byte \\x{got:02X}"
2583 )
2584 }
2585 ErrorKind::NumberTooBig { ref bytes } => {
2586 let string = match std::str::from_utf8(bytes) {
2587 Ok(v) => v,
2588 Err(err) => {
2589 std::str::from_utf8(&bytes[..err.valid_up_to()]).expect("valid UTF-8")
2590 }
2591 };
2592 write!(
2593 f,
2594 "expected number less than or equal to {}, \
2595 but number found in {string:?} exceeds it",
2596 u64::MAX - 1,
2597 )
2598 }
2599 ErrorKind::NoLeadingNumber => {
2600 write!(
2601 f,
2602 "expected version to start with a number, \
2603 but no leading ASCII digits were found"
2604 )
2605 }
2606 ErrorKind::NoLeadingReleaseNumber => {
2607 write!(
2608 f,
2609 "expected version to have a non-empty release component after an epoch, \
2610 but no ASCII digits after the epoch were found"
2611 )
2612 }
2613 ErrorKind::LocalEmpty { precursor } => {
2614 write!(
2615 f,
2616 "found a `{precursor}` indicating the start of a local \
2617 component in a version, but did not find any alphanumeric \
2618 ASCII segment following the `{precursor}`",
2619 )
2620 }
2621 ErrorKind::UnexpectedEnd {
2622 ref version,
2623 ref remaining,
2624 } => {
2625 write!(
2626 f,
2627 "after parsing `{version}`, found `{remaining}`, \
2628 which is not part of a valid version",
2629 )
2630 }
2631 }
2632 }
2633}
2634
2635#[derive(Clone, Debug, Eq, PartialEq)]
2637pub(crate) enum ErrorKind {
2638 Wildcard,
2641 InvalidDigit {
2643 got: u8,
2645 },
2646 NumberTooBig {
2648 bytes: Vec<u8>,
2651 },
2652 NoLeadingNumber,
2654 NoLeadingReleaseNumber,
2656 LocalEmpty {
2660 precursor: char,
2663 },
2664 UnexpectedEnd {
2667 version: String,
2669 remaining: String,
2671 },
2672}
2673
2674impl From<ErrorKind> for VersionParseError {
2675 fn from(kind: ErrorKind) -> Self {
2676 Self {
2677 kind: Box::new(kind),
2678 }
2679 }
2680}
2681
2682#[derive(Clone, Debug, Eq, PartialEq)]
2684pub struct VersionPatternParseError {
2685 kind: Box<PatternErrorKind>,
2686}
2687
2688impl std::error::Error for VersionPatternParseError {}
2689
2690impl std::fmt::Display for VersionPatternParseError {
2691 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2692 match *self.kind {
2693 PatternErrorKind::Version(ref err) => err.fmt(f),
2694 PatternErrorKind::WildcardNotTrailing => {
2695 write!(f, "wildcards in versions must be at the end")
2696 }
2697 }
2698 }
2699}
2700
2701#[derive(Clone, Debug, Eq, PartialEq)]
2703pub(crate) enum PatternErrorKind {
2704 Version(VersionParseError),
2705 WildcardNotTrailing,
2706}
2707
2708impl From<PatternErrorKind> for VersionPatternParseError {
2709 fn from(kind: PatternErrorKind) -> Self {
2710 Self {
2711 kind: Box::new(kind),
2712 }
2713 }
2714}
2715
2716impl From<ErrorKind> for VersionPatternParseError {
2717 fn from(kind: ErrorKind) -> Self {
2718 Self::from(VersionParseError::from(kind))
2719 }
2720}
2721
2722impl From<VersionParseError> for VersionPatternParseError {
2723 fn from(err: VersionParseError) -> Self {
2724 Self {
2725 kind: Box::new(PatternErrorKind::Version(err)),
2726 }
2727 }
2728}
2729
2730pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2733 if this.len() == other.len() {
2734 return this.cmp(other);
2735 }
2736 for (this, other) in this.iter().chain(std::iter::repeat(&0)).zip(
2739 other
2740 .iter()
2741 .chain(std::iter::repeat(&0))
2742 .take(this.len().max(other.len())),
2743 ) {
2744 match this.cmp(other) {
2745 Ordering::Less => {
2746 return Ordering::Less;
2747 }
2748 Ordering::Equal => {}
2749 Ordering::Greater => {
2750 return Ordering::Greater;
2751 }
2752 }
2753 }
2754 Ordering::Equal
2755}
2756
2757fn sortable_tuple(version: &Version) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2773 let post = if version.max().is_some() {
2775 Some(u64::MAX)
2776 } else {
2777 version.post()
2778 };
2779 match (version.pre(), post, version.dev(), version.min()) {
2780 (_pre, post, _dev, Some(n)) => (0, 0, post, n, version.local()),
2782 (None, None, Some(n), None) => (1, 0, None, n, version.local()),
2784 (
2786 Some(Prerelease {
2787 kind: PrereleaseKind::Alpha,
2788 number: n,
2789 }),
2790 post,
2791 dev,
2792 None,
2793 ) => (2, n, post, dev.unwrap_or(u64::MAX), version.local()),
2794 (
2796 Some(Prerelease {
2797 kind: PrereleaseKind::Beta,
2798 number: n,
2799 }),
2800 post,
2801 dev,
2802 None,
2803 ) => (3, n, post, dev.unwrap_or(u64::MAX), version.local()),
2804 (
2806 Some(Prerelease {
2807 kind: PrereleaseKind::Rc,
2808 number: n,
2809 }),
2810 post,
2811 dev,
2812 None,
2813 ) => (4, n, post, dev.unwrap_or(u64::MAX), version.local()),
2814 (None, None, None, None) => (5, 0, None, 0, version.local()),
2816 (None, Some(post), dev, None) => {
2818 (6, 0, Some(post), dev.unwrap_or(u64::MAX), version.local())
2819 }
2820 }
2821}
2822
2823fn starts_with_ignore_ascii_case(needle: &[u8], haystack: &[u8]) -> bool {
2826 needle.len() <= haystack.len()
2827 && std::iter::zip(needle, haystack).all(|(b1, b2)| b1.eq_ignore_ascii_case(b2))
2828}
2829
2830fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
2845 let mut n: u64 = 0;
2846 for &byte in bytes {
2847 let digit = match byte.checked_sub(b'0') {
2848 None => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2849 Some(digit) if digit > 9 => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2850 Some(digit) => {
2851 debug_assert!((0..=9).contains(&digit));
2852 u64::from(digit)
2853 }
2854 };
2855 n = n
2856 .checked_mul(10)
2857 .and_then(|n| n.checked_add(digit))
2858 .ok_or_else(|| ErrorKind::NumberTooBig {
2859 bytes: bytes.to_vec(),
2860 })?;
2861 }
2862 Ok(n)
2863}
2864
2865pub static MIN_VERSION: LazyLock<Version> =
2867 LazyLock::new(|| Version::from_str("0a0.dev0").unwrap());
2868
2869#[cfg(test)]
2870mod tests {
2871 use std::str::FromStr;
2872
2873 use crate::VersionSpecifier;
2874
2875 use super::*;
2876
2877 #[test]
2879 fn test_packaging_versions() {
2880 let versions = [
2881 ("1.0.dev456", Version::new([1, 0]).with_dev(Some(456))),
2883 (
2884 "1.0a1",
2885 Version::new([1, 0]).with_pre(Some(Prerelease {
2886 kind: PrereleaseKind::Alpha,
2887 number: 1,
2888 })),
2889 ),
2890 (
2891 "1.0a2.dev456",
2892 Version::new([1, 0])
2893 .with_pre(Some(Prerelease {
2894 kind: PrereleaseKind::Alpha,
2895 number: 2,
2896 }))
2897 .with_dev(Some(456)),
2898 ),
2899 (
2900 "1.0a12.dev456",
2901 Version::new([1, 0])
2902 .with_pre(Some(Prerelease {
2903 kind: PrereleaseKind::Alpha,
2904 number: 12,
2905 }))
2906 .with_dev(Some(456)),
2907 ),
2908 (
2909 "1.0a12",
2910 Version::new([1, 0]).with_pre(Some(Prerelease {
2911 kind: PrereleaseKind::Alpha,
2912 number: 12,
2913 })),
2914 ),
2915 (
2916 "1.0b1.dev456",
2917 Version::new([1, 0])
2918 .with_pre(Some(Prerelease {
2919 kind: PrereleaseKind::Beta,
2920 number: 1,
2921 }))
2922 .with_dev(Some(456)),
2923 ),
2924 (
2925 "1.0b2",
2926 Version::new([1, 0]).with_pre(Some(Prerelease {
2927 kind: PrereleaseKind::Beta,
2928 number: 2,
2929 })),
2930 ),
2931 (
2932 "1.0b2.post345.dev456",
2933 Version::new([1, 0])
2934 .with_pre(Some(Prerelease {
2935 kind: PrereleaseKind::Beta,
2936 number: 2,
2937 }))
2938 .with_dev(Some(456))
2939 .with_post(Some(345)),
2940 ),
2941 (
2942 "1.0b2.post345",
2943 Version::new([1, 0])
2944 .with_pre(Some(Prerelease {
2945 kind: PrereleaseKind::Beta,
2946 number: 2,
2947 }))
2948 .with_post(Some(345)),
2949 ),
2950 (
2951 "1.0b2-346",
2952 Version::new([1, 0])
2953 .with_pre(Some(Prerelease {
2954 kind: PrereleaseKind::Beta,
2955 number: 2,
2956 }))
2957 .with_post(Some(346)),
2958 ),
2959 (
2960 "1.0c1.dev456",
2961 Version::new([1, 0])
2962 .with_pre(Some(Prerelease {
2963 kind: PrereleaseKind::Rc,
2964 number: 1,
2965 }))
2966 .with_dev(Some(456)),
2967 ),
2968 (
2969 "1.0c1",
2970 Version::new([1, 0]).with_pre(Some(Prerelease {
2971 kind: PrereleaseKind::Rc,
2972 number: 1,
2973 })),
2974 ),
2975 (
2976 "1.0rc2",
2977 Version::new([1, 0]).with_pre(Some(Prerelease {
2978 kind: PrereleaseKind::Rc,
2979 number: 2,
2980 })),
2981 ),
2982 (
2983 "1.0c3",
2984 Version::new([1, 0]).with_pre(Some(Prerelease {
2985 kind: PrereleaseKind::Rc,
2986 number: 3,
2987 })),
2988 ),
2989 ("1.0", Version::new([1, 0])),
2990 (
2991 "1.0.post456.dev34",
2992 Version::new([1, 0]).with_post(Some(456)).with_dev(Some(34)),
2993 ),
2994 ("1.0.post456", Version::new([1, 0]).with_post(Some(456))),
2995 ("1.1.dev1", Version::new([1, 1]).with_dev(Some(1))),
2996 (
2997 "1.2+123abc",
2998 Version::new([1, 2])
2999 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3000 ),
3001 (
3002 "1.2+123abc456",
3003 Version::new([1, 2])
3004 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3005 ),
3006 (
3007 "1.2+abc",
3008 Version::new([1, 2])
3009 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3010 ),
3011 (
3012 "1.2+abc123",
3013 Version::new([1, 2])
3014 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3015 ),
3016 (
3017 "1.2+abc123def",
3018 Version::new([1, 2])
3019 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3020 ),
3021 (
3022 "1.2+1234.abc",
3023 Version::new([1, 2]).with_local_segments(vec![
3024 LocalSegment::Number(1234),
3025 LocalSegment::String("abc".to_string()),
3026 ]),
3027 ),
3028 (
3029 "1.2+123456",
3030 Version::new([1, 2]).with_local_segments(vec![LocalSegment::Number(123_456)]),
3031 ),
3032 (
3033 "1.2.r32+123456",
3034 Version::new([1, 2])
3035 .with_post(Some(32))
3036 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3037 ),
3038 (
3039 "1.2.rev33+123456",
3040 Version::new([1, 2])
3041 .with_post(Some(33))
3042 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3043 ),
3044 (
3046 "1!1.0.dev456",
3047 Version::new([1, 0]).with_epoch(1).with_dev(Some(456)),
3048 ),
3049 (
3050 "1!1.0a1",
3051 Version::new([1, 0])
3052 .with_epoch(1)
3053 .with_pre(Some(Prerelease {
3054 kind: PrereleaseKind::Alpha,
3055 number: 1,
3056 })),
3057 ),
3058 (
3059 "1!1.0a2.dev456",
3060 Version::new([1, 0])
3061 .with_epoch(1)
3062 .with_pre(Some(Prerelease {
3063 kind: PrereleaseKind::Alpha,
3064 number: 2,
3065 }))
3066 .with_dev(Some(456)),
3067 ),
3068 (
3069 "1!1.0a12.dev456",
3070 Version::new([1, 0])
3071 .with_epoch(1)
3072 .with_pre(Some(Prerelease {
3073 kind: PrereleaseKind::Alpha,
3074 number: 12,
3075 }))
3076 .with_dev(Some(456)),
3077 ),
3078 (
3079 "1!1.0a12",
3080 Version::new([1, 0])
3081 .with_epoch(1)
3082 .with_pre(Some(Prerelease {
3083 kind: PrereleaseKind::Alpha,
3084 number: 12,
3085 })),
3086 ),
3087 (
3088 "1!1.0b1.dev456",
3089 Version::new([1, 0])
3090 .with_epoch(1)
3091 .with_pre(Some(Prerelease {
3092 kind: PrereleaseKind::Beta,
3093 number: 1,
3094 }))
3095 .with_dev(Some(456)),
3096 ),
3097 (
3098 "1!1.0b2",
3099 Version::new([1, 0])
3100 .with_epoch(1)
3101 .with_pre(Some(Prerelease {
3102 kind: PrereleaseKind::Beta,
3103 number: 2,
3104 })),
3105 ),
3106 (
3107 "1!1.0b2.post345.dev456",
3108 Version::new([1, 0])
3109 .with_epoch(1)
3110 .with_pre(Some(Prerelease {
3111 kind: PrereleaseKind::Beta,
3112 number: 2,
3113 }))
3114 .with_post(Some(345))
3115 .with_dev(Some(456)),
3116 ),
3117 (
3118 "1!1.0b2.post345",
3119 Version::new([1, 0])
3120 .with_epoch(1)
3121 .with_pre(Some(Prerelease {
3122 kind: PrereleaseKind::Beta,
3123 number: 2,
3124 }))
3125 .with_post(Some(345)),
3126 ),
3127 (
3128 "1!1.0b2-346",
3129 Version::new([1, 0])
3130 .with_epoch(1)
3131 .with_pre(Some(Prerelease {
3132 kind: PrereleaseKind::Beta,
3133 number: 2,
3134 }))
3135 .with_post(Some(346)),
3136 ),
3137 (
3138 "1!1.0c1.dev456",
3139 Version::new([1, 0])
3140 .with_epoch(1)
3141 .with_pre(Some(Prerelease {
3142 kind: PrereleaseKind::Rc,
3143 number: 1,
3144 }))
3145 .with_dev(Some(456)),
3146 ),
3147 (
3148 "1!1.0c1",
3149 Version::new([1, 0])
3150 .with_epoch(1)
3151 .with_pre(Some(Prerelease {
3152 kind: PrereleaseKind::Rc,
3153 number: 1,
3154 })),
3155 ),
3156 (
3157 "1!1.0rc2",
3158 Version::new([1, 0])
3159 .with_epoch(1)
3160 .with_pre(Some(Prerelease {
3161 kind: PrereleaseKind::Rc,
3162 number: 2,
3163 })),
3164 ),
3165 (
3166 "1!1.0c3",
3167 Version::new([1, 0])
3168 .with_epoch(1)
3169 .with_pre(Some(Prerelease {
3170 kind: PrereleaseKind::Rc,
3171 number: 3,
3172 })),
3173 ),
3174 ("1!1.0", Version::new([1, 0]).with_epoch(1)),
3175 (
3176 "1!1.0.post456.dev34",
3177 Version::new([1, 0])
3178 .with_epoch(1)
3179 .with_post(Some(456))
3180 .with_dev(Some(34)),
3181 ),
3182 (
3183 "1!1.0.post456",
3184 Version::new([1, 0]).with_epoch(1).with_post(Some(456)),
3185 ),
3186 (
3187 "1!1.1.dev1",
3188 Version::new([1, 1]).with_epoch(1).with_dev(Some(1)),
3189 ),
3190 (
3191 "1!1.2+123abc",
3192 Version::new([1, 2])
3193 .with_epoch(1)
3194 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3195 ),
3196 (
3197 "1!1.2+123abc456",
3198 Version::new([1, 2])
3199 .with_epoch(1)
3200 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3201 ),
3202 (
3203 "1!1.2+abc",
3204 Version::new([1, 2])
3205 .with_epoch(1)
3206 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3207 ),
3208 (
3209 "1!1.2+abc123",
3210 Version::new([1, 2])
3211 .with_epoch(1)
3212 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3213 ),
3214 (
3215 "1!1.2+abc123def",
3216 Version::new([1, 2])
3217 .with_epoch(1)
3218 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3219 ),
3220 (
3221 "1!1.2+1234.abc",
3222 Version::new([1, 2]).with_epoch(1).with_local_segments(vec![
3223 LocalSegment::Number(1234),
3224 LocalSegment::String("abc".to_string()),
3225 ]),
3226 ),
3227 (
3228 "1!1.2+123456",
3229 Version::new([1, 2])
3230 .with_epoch(1)
3231 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3232 ),
3233 (
3234 "1!1.2.r32+123456",
3235 Version::new([1, 2])
3236 .with_epoch(1)
3237 .with_post(Some(32))
3238 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3239 ),
3240 (
3241 "1!1.2.rev33+123456",
3242 Version::new([1, 2])
3243 .with_epoch(1)
3244 .with_post(Some(33))
3245 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3246 ),
3247 (
3248 "98765!1.2.rev33+123456",
3249 Version::new([1, 2])
3250 .with_epoch(98765)
3251 .with_post(Some(33))
3252 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3253 ),
3254 ];
3255 for (string, structured) in versions {
3256 match Version::from_str(string) {
3257 Err(err) => {
3258 unreachable!(
3259 "expected {string:?} to parse as {structured:?}, but got {err:?}",
3260 structured = structured.as_bloated_debug(),
3261 )
3262 }
3263 Ok(v) => assert!(
3264 v == structured,
3265 "for {string:?}, expected {structured:?} but got {v:?}",
3266 structured = structured.as_bloated_debug(),
3267 v = v.as_bloated_debug(),
3268 ),
3269 }
3270 let spec = format!("=={string}");
3271 match VersionSpecifier::from_str(&spec) {
3272 Err(err) => {
3273 unreachable!(
3274 "expected version in {spec:?} to parse as {structured:?}, but got {err:?}",
3275 structured = structured.as_bloated_debug(),
3276 )
3277 }
3278 Ok(v) => assert!(
3279 v.version() == &structured,
3280 "for {string:?}, expected {structured:?} but got {v:?}",
3281 structured = structured.as_bloated_debug(),
3282 v = v.version.as_bloated_debug(),
3283 ),
3284 }
3285 }
3286 }
3287
3288 #[test]
3290 fn test_packaging_failures() {
3291 let versions = [
3292 "1.0+a+",
3294 "1.0++",
3295 "1.0+_foobar",
3296 "1.0+foo&asd",
3297 "1.0+1+1",
3298 "french toast",
3300 "==french toast",
3301 ];
3302 for version in versions {
3303 assert!(Version::from_str(version).is_err());
3304 assert!(VersionSpecifier::from_str(&format!("=={version}")).is_err());
3305 }
3306 }
3307
3308 #[test]
3309 fn test_equality_and_normalization() {
3310 let versions = [
3311 ("1.0dev", "1.0.dev0"),
3313 ("1.0.dev", "1.0.dev0"),
3314 ("1.0dev1", "1.0.dev1"),
3315 ("1.0dev", "1.0.dev0"),
3316 ("1.0-dev", "1.0.dev0"),
3317 ("1.0-dev1", "1.0.dev1"),
3318 ("1.0DEV", "1.0.dev0"),
3319 ("1.0.DEV", "1.0.dev0"),
3320 ("1.0DEV1", "1.0.dev1"),
3321 ("1.0DEV", "1.0.dev0"),
3322 ("1.0.DEV1", "1.0.dev1"),
3323 ("1.0-DEV", "1.0.dev0"),
3324 ("1.0-DEV1", "1.0.dev1"),
3325 ("1.0a", "1.0a0"),
3327 ("1.0.a", "1.0a0"),
3328 ("1.0.a1", "1.0a1"),
3329 ("1.0-a", "1.0a0"),
3330 ("1.0-a1", "1.0a1"),
3331 ("1.0alpha", "1.0a0"),
3332 ("1.0.alpha", "1.0a0"),
3333 ("1.0.alpha1", "1.0a1"),
3334 ("1.0-alpha", "1.0a0"),
3335 ("1.0-alpha1", "1.0a1"),
3336 ("1.0A", "1.0a0"),
3337 ("1.0.A", "1.0a0"),
3338 ("1.0.A1", "1.0a1"),
3339 ("1.0-A", "1.0a0"),
3340 ("1.0-A1", "1.0a1"),
3341 ("1.0ALPHA", "1.0a0"),
3342 ("1.0.ALPHA", "1.0a0"),
3343 ("1.0.ALPHA1", "1.0a1"),
3344 ("1.0-ALPHA", "1.0a0"),
3345 ("1.0-ALPHA1", "1.0a1"),
3346 ("1.0b", "1.0b0"),
3348 ("1.0.b", "1.0b0"),
3349 ("1.0.b1", "1.0b1"),
3350 ("1.0-b", "1.0b0"),
3351 ("1.0-b1", "1.0b1"),
3352 ("1.0beta", "1.0b0"),
3353 ("1.0.beta", "1.0b0"),
3354 ("1.0.beta1", "1.0b1"),
3355 ("1.0-beta", "1.0b0"),
3356 ("1.0-beta1", "1.0b1"),
3357 ("1.0B", "1.0b0"),
3358 ("1.0.B", "1.0b0"),
3359 ("1.0.B1", "1.0b1"),
3360 ("1.0-B", "1.0b0"),
3361 ("1.0-B1", "1.0b1"),
3362 ("1.0BETA", "1.0b0"),
3363 ("1.0.BETA", "1.0b0"),
3364 ("1.0.BETA1", "1.0b1"),
3365 ("1.0-BETA", "1.0b0"),
3366 ("1.0-BETA1", "1.0b1"),
3367 ("1.0c", "1.0rc0"),
3369 ("1.0.c", "1.0rc0"),
3370 ("1.0.c1", "1.0rc1"),
3371 ("1.0-c", "1.0rc0"),
3372 ("1.0-c1", "1.0rc1"),
3373 ("1.0rc", "1.0rc0"),
3374 ("1.0.rc", "1.0rc0"),
3375 ("1.0.rc1", "1.0rc1"),
3376 ("1.0-rc", "1.0rc0"),
3377 ("1.0-rc1", "1.0rc1"),
3378 ("1.0C", "1.0rc0"),
3379 ("1.0.C", "1.0rc0"),
3380 ("1.0.C1", "1.0rc1"),
3381 ("1.0-C", "1.0rc0"),
3382 ("1.0-C1", "1.0rc1"),
3383 ("1.0RC", "1.0rc0"),
3384 ("1.0.RC", "1.0rc0"),
3385 ("1.0.RC1", "1.0rc1"),
3386 ("1.0-RC", "1.0rc0"),
3387 ("1.0-RC1", "1.0rc1"),
3388 ("1.0post", "1.0.post0"),
3390 ("1.0.post", "1.0.post0"),
3391 ("1.0post1", "1.0.post1"),
3392 ("1.0post", "1.0.post0"),
3393 ("1.0-post", "1.0.post0"),
3394 ("1.0-post1", "1.0.post1"),
3395 ("1.0POST", "1.0.post0"),
3396 ("1.0.POST", "1.0.post0"),
3397 ("1.0POST1", "1.0.post1"),
3398 ("1.0POST", "1.0.post0"),
3399 ("1.0r", "1.0.post0"),
3400 ("1.0rev", "1.0.post0"),
3401 ("1.0.POST1", "1.0.post1"),
3402 ("1.0.r1", "1.0.post1"),
3403 ("1.0.rev1", "1.0.post1"),
3404 ("1.0-POST", "1.0.post0"),
3405 ("1.0-POST1", "1.0.post1"),
3406 ("1.0-5", "1.0.post5"),
3407 ("1.0-r5", "1.0.post5"),
3408 ("1.0-rev5", "1.0.post5"),
3409 ("1.0+AbC", "1.0+abc"),
3411 ("1.01", "1.1"),
3413 ("1.0a05", "1.0a5"),
3414 ("1.0b07", "1.0b7"),
3415 ("1.0c056", "1.0rc56"),
3416 ("1.0rc09", "1.0rc9"),
3417 ("1.0.post000", "1.0.post0"),
3418 ("1.1.dev09000", "1.1.dev9000"),
3419 ("00!1.2", "1.2"),
3420 ("0100!0.0", "100!0.0"),
3421 ("v1.0", "1.0"),
3423 (" v1.0\t\n", "1.0"),
3424 ];
3425 for (version_str, normalized_str) in versions {
3426 let version = Version::from_str(version_str).unwrap();
3427 let normalized = Version::from_str(normalized_str).unwrap();
3428 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3430 assert_eq!(
3432 version.to_string(),
3433 normalized.to_string(),
3434 "{version_str} {normalized_str}"
3435 );
3436 }
3437 }
3438
3439 #[test]
3441 fn test_equality_and_normalization2() {
3442 let versions = [
3443 ("1.0.dev456", "1.0.dev456"),
3444 ("1.0a1", "1.0a1"),
3445 ("1.0a2.dev456", "1.0a2.dev456"),
3446 ("1.0a12.dev456", "1.0a12.dev456"),
3447 ("1.0a12", "1.0a12"),
3448 ("1.0b1.dev456", "1.0b1.dev456"),
3449 ("1.0b2", "1.0b2"),
3450 ("1.0b2.post345.dev456", "1.0b2.post345.dev456"),
3451 ("1.0b2.post345", "1.0b2.post345"),
3452 ("1.0rc1.dev456", "1.0rc1.dev456"),
3453 ("1.0rc1", "1.0rc1"),
3454 ("1.0", "1.0"),
3455 ("1.0.post456.dev34", "1.0.post456.dev34"),
3456 ("1.0.post456", "1.0.post456"),
3457 ("1.0.1", "1.0.1"),
3458 ("0!1.0.2", "1.0.2"),
3459 ("1.0.3+7", "1.0.3+7"),
3460 ("0!1.0.4+8.0", "1.0.4+8.0"),
3461 ("1.0.5+9.5", "1.0.5+9.5"),
3462 ("1.2+1234.abc", "1.2+1234.abc"),
3463 ("1.2+123456", "1.2+123456"),
3464 ("1.2+123abc", "1.2+123abc"),
3465 ("1.2+123abc456", "1.2+123abc456"),
3466 ("1.2+abc", "1.2+abc"),
3467 ("1.2+abc123", "1.2+abc123"),
3468 ("1.2+abc123def", "1.2+abc123def"),
3469 ("1.1.dev1", "1.1.dev1"),
3470 ("7!1.0.dev456", "7!1.0.dev456"),
3471 ("7!1.0a1", "7!1.0a1"),
3472 ("7!1.0a2.dev456", "7!1.0a2.dev456"),
3473 ("7!1.0a12.dev456", "7!1.0a12.dev456"),
3474 ("7!1.0a12", "7!1.0a12"),
3475 ("7!1.0b1.dev456", "7!1.0b1.dev456"),
3476 ("7!1.0b2", "7!1.0b2"),
3477 ("7!1.0b2.post345.dev456", "7!1.0b2.post345.dev456"),
3478 ("7!1.0b2.post345", "7!1.0b2.post345"),
3479 ("7!1.0rc1.dev456", "7!1.0rc1.dev456"),
3480 ("7!1.0rc1", "7!1.0rc1"),
3481 ("7!1.0", "7!1.0"),
3482 ("7!1.0.post456.dev34", "7!1.0.post456.dev34"),
3483 ("7!1.0.post456", "7!1.0.post456"),
3484 ("7!1.0.1", "7!1.0.1"),
3485 ("7!1.0.2", "7!1.0.2"),
3486 ("7!1.0.3+7", "7!1.0.3+7"),
3487 ("7!1.0.4+8.0", "7!1.0.4+8.0"),
3488 ("7!1.0.5+9.5", "7!1.0.5+9.5"),
3489 ("7!1.1.dev1", "7!1.1.dev1"),
3490 ];
3491 for (version_str, normalized_str) in versions {
3492 let version = Version::from_str(version_str).unwrap();
3493 let normalized = Version::from_str(normalized_str).unwrap();
3494 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3495 assert_eq!(
3497 version.to_string(),
3498 normalized_str,
3499 "{version_str} {normalized_str}"
3500 );
3501 assert_eq!(
3503 version.to_string(),
3504 normalized.to_string(),
3505 "{version_str} {normalized_str}"
3506 );
3507 }
3508 }
3509
3510 #[test]
3511 fn test_star_fixed_version() {
3512 let result = Version::from_str("0.9.1.*");
3513 assert_eq!(result.unwrap_err(), ErrorKind::Wildcard.into());
3514 }
3515
3516 #[test]
3517 fn test_invalid_word() {
3518 let result = Version::from_str("blergh");
3519 assert_eq!(result.unwrap_err(), ErrorKind::NoLeadingNumber.into());
3520 }
3521
3522 #[test]
3523 fn test_from_version_star() {
3524 let p = |s: &str| -> Result<VersionPattern, _> { s.parse() };
3525 assert!(!p("1.2.3").unwrap().is_wildcard());
3526 assert!(p("1.2.3.*").unwrap().is_wildcard());
3527 assert_eq!(
3528 p("1.2.*.4.*").unwrap_err(),
3529 PatternErrorKind::WildcardNotTrailing.into(),
3530 );
3531 assert_eq!(
3532 p("1.0-dev1.*").unwrap_err(),
3533 ErrorKind::UnexpectedEnd {
3534 version: "1.0-dev1".to_string(),
3535 remaining: ".*".to_string()
3536 }
3537 .into(),
3538 );
3539 assert_eq!(
3540 p("1.0a1.*").unwrap_err(),
3541 ErrorKind::UnexpectedEnd {
3542 version: "1.0a1".to_string(),
3543 remaining: ".*".to_string()
3544 }
3545 .into(),
3546 );
3547 assert_eq!(
3548 p("1.0.post1.*").unwrap_err(),
3549 ErrorKind::UnexpectedEnd {
3550 version: "1.0.post1".to_string(),
3551 remaining: ".*".to_string()
3552 }
3553 .into(),
3554 );
3555 assert_eq!(
3556 p("1.0+lolwat.*").unwrap_err(),
3557 ErrorKind::LocalEmpty { precursor: '.' }.into(),
3558 );
3559 }
3560
3561 #[test]
3567 fn parse_version_valid() {
3568 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3569 Ok(v) => v,
3570 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3571 };
3572
3573 assert_eq!(p("5"), Version::new([5]));
3575 assert_eq!(p("5.6"), Version::new([5, 6]));
3576 assert_eq!(p("5.6.7"), Version::new([5, 6, 7]));
3577 assert_eq!(p("512.623.734"), Version::new([512, 623, 734]));
3578 assert_eq!(p("1.2.3.4"), Version::new([1, 2, 3, 4]));
3579 assert_eq!(p("1.2.3.4.5"), Version::new([1, 2, 3, 4, 5]));
3580
3581 assert_eq!(p("4!5"), Version::new([5]).with_epoch(4));
3583 assert_eq!(p("4!5.6"), Version::new([5, 6]).with_epoch(4));
3584
3585 assert_eq!(
3587 p("5a1"),
3588 Version::new([5]).with_pre(Some(Prerelease {
3589 kind: PrereleaseKind::Alpha,
3590 number: 1
3591 }))
3592 );
3593 assert_eq!(
3594 p("5alpha1"),
3595 Version::new([5]).with_pre(Some(Prerelease {
3596 kind: PrereleaseKind::Alpha,
3597 number: 1
3598 }))
3599 );
3600 assert_eq!(
3601 p("5b1"),
3602 Version::new([5]).with_pre(Some(Prerelease {
3603 kind: PrereleaseKind::Beta,
3604 number: 1
3605 }))
3606 );
3607 assert_eq!(
3608 p("5beta1"),
3609 Version::new([5]).with_pre(Some(Prerelease {
3610 kind: PrereleaseKind::Beta,
3611 number: 1
3612 }))
3613 );
3614 assert_eq!(
3615 p("5rc1"),
3616 Version::new([5]).with_pre(Some(Prerelease {
3617 kind: PrereleaseKind::Rc,
3618 number: 1
3619 }))
3620 );
3621 assert_eq!(
3622 p("5c1"),
3623 Version::new([5]).with_pre(Some(Prerelease {
3624 kind: PrereleaseKind::Rc,
3625 number: 1
3626 }))
3627 );
3628 assert_eq!(
3629 p("5preview1"),
3630 Version::new([5]).with_pre(Some(Prerelease {
3631 kind: PrereleaseKind::Rc,
3632 number: 1
3633 }))
3634 );
3635 assert_eq!(
3636 p("5pre1"),
3637 Version::new([5]).with_pre(Some(Prerelease {
3638 kind: PrereleaseKind::Rc,
3639 number: 1
3640 }))
3641 );
3642 assert_eq!(
3643 p("5.6.7pre1"),
3644 Version::new([5, 6, 7]).with_pre(Some(Prerelease {
3645 kind: PrereleaseKind::Rc,
3646 number: 1
3647 }))
3648 );
3649 assert_eq!(
3650 p("5alpha789"),
3651 Version::new([5]).with_pre(Some(Prerelease {
3652 kind: PrereleaseKind::Alpha,
3653 number: 789
3654 }))
3655 );
3656 assert_eq!(
3657 p("5.alpha789"),
3658 Version::new([5]).with_pre(Some(Prerelease {
3659 kind: PrereleaseKind::Alpha,
3660 number: 789
3661 }))
3662 );
3663 assert_eq!(
3664 p("5-alpha789"),
3665 Version::new([5]).with_pre(Some(Prerelease {
3666 kind: PrereleaseKind::Alpha,
3667 number: 789
3668 }))
3669 );
3670 assert_eq!(
3671 p("5_alpha789"),
3672 Version::new([5]).with_pre(Some(Prerelease {
3673 kind: PrereleaseKind::Alpha,
3674 number: 789
3675 }))
3676 );
3677 assert_eq!(
3678 p("5alpha.789"),
3679 Version::new([5]).with_pre(Some(Prerelease {
3680 kind: PrereleaseKind::Alpha,
3681 number: 789
3682 }))
3683 );
3684 assert_eq!(
3685 p("5alpha-789"),
3686 Version::new([5]).with_pre(Some(Prerelease {
3687 kind: PrereleaseKind::Alpha,
3688 number: 789
3689 }))
3690 );
3691 assert_eq!(
3692 p("5alpha_789"),
3693 Version::new([5]).with_pre(Some(Prerelease {
3694 kind: PrereleaseKind::Alpha,
3695 number: 789
3696 }))
3697 );
3698 assert_eq!(
3699 p("5ALPHA789"),
3700 Version::new([5]).with_pre(Some(Prerelease {
3701 kind: PrereleaseKind::Alpha,
3702 number: 789
3703 }))
3704 );
3705 assert_eq!(
3706 p("5aLpHa789"),
3707 Version::new([5]).with_pre(Some(Prerelease {
3708 kind: PrereleaseKind::Alpha,
3709 number: 789
3710 }))
3711 );
3712 assert_eq!(
3713 p("5alpha"),
3714 Version::new([5]).with_pre(Some(Prerelease {
3715 kind: PrereleaseKind::Alpha,
3716 number: 0
3717 }))
3718 );
3719
3720 assert_eq!(p("5post2"), Version::new([5]).with_post(Some(2)));
3722 assert_eq!(p("5rev2"), Version::new([5]).with_post(Some(2)));
3723 assert_eq!(p("5r2"), Version::new([5]).with_post(Some(2)));
3724 assert_eq!(p("5.post2"), Version::new([5]).with_post(Some(2)));
3725 assert_eq!(p("5-post2"), Version::new([5]).with_post(Some(2)));
3726 assert_eq!(p("5_post2"), Version::new([5]).with_post(Some(2)));
3727 assert_eq!(p("5.post.2"), Version::new([5]).with_post(Some(2)));
3728 assert_eq!(p("5.post-2"), Version::new([5]).with_post(Some(2)));
3729 assert_eq!(p("5.post_2"), Version::new([5]).with_post(Some(2)));
3730 assert_eq!(
3731 p("5.6.7.post_2"),
3732 Version::new([5, 6, 7]).with_post(Some(2))
3733 );
3734 assert_eq!(p("5-2"), Version::new([5]).with_post(Some(2)));
3735 assert_eq!(p("5.6.7-2"), Version::new([5, 6, 7]).with_post(Some(2)));
3736 assert_eq!(p("5POST2"), Version::new([5]).with_post(Some(2)));
3737 assert_eq!(p("5PoSt2"), Version::new([5]).with_post(Some(2)));
3738 assert_eq!(p("5post"), Version::new([5]).with_post(Some(0)));
3739
3740 assert_eq!(p("5dev2"), Version::new([5]).with_dev(Some(2)));
3742 assert_eq!(p("5.dev2"), Version::new([5]).with_dev(Some(2)));
3743 assert_eq!(p("5-dev2"), Version::new([5]).with_dev(Some(2)));
3744 assert_eq!(p("5_dev2"), Version::new([5]).with_dev(Some(2)));
3745 assert_eq!(p("5.dev.2"), Version::new([5]).with_dev(Some(2)));
3746 assert_eq!(p("5.dev-2"), Version::new([5]).with_dev(Some(2)));
3747 assert_eq!(p("5.dev_2"), Version::new([5]).with_dev(Some(2)));
3748 assert_eq!(p("5.6.7.dev_2"), Version::new([5, 6, 7]).with_dev(Some(2)));
3749 assert_eq!(p("5DEV2"), Version::new([5]).with_dev(Some(2)));
3750 assert_eq!(p("5dEv2"), Version::new([5]).with_dev(Some(2)));
3751 assert_eq!(p("5DeV2"), Version::new([5]).with_dev(Some(2)));
3752 assert_eq!(p("5dev"), Version::new([5]).with_dev(Some(0)));
3753
3754 assert_eq!(
3756 p("5+2"),
3757 Version::new([5]).with_local_segments(vec![LocalSegment::Number(2)])
3758 );
3759 assert_eq!(
3760 p("5+a"),
3761 Version::new([5]).with_local_segments(vec![LocalSegment::String("a".to_string())])
3762 );
3763 assert_eq!(
3764 p("5+abc.123"),
3765 Version::new([5]).with_local_segments(vec![
3766 LocalSegment::String("abc".to_string()),
3767 LocalSegment::Number(123),
3768 ])
3769 );
3770 assert_eq!(
3771 p("5+123.abc"),
3772 Version::new([5]).with_local_segments(vec![
3773 LocalSegment::Number(123),
3774 LocalSegment::String("abc".to_string()),
3775 ])
3776 );
3777 assert_eq!(
3778 p("5+18446744073709551615.abc"),
3779 Version::new([5]).with_local_segments(vec![
3780 LocalSegment::Number(18_446_744_073_709_551_615),
3781 LocalSegment::String("abc".to_string()),
3782 ])
3783 );
3784 assert_eq!(
3785 p("5+18446744073709551616.abc"),
3786 Version::new([5]).with_local_segments(vec![
3787 LocalSegment::String("18446744073709551616".to_string()),
3788 LocalSegment::String("abc".to_string()),
3789 ])
3790 );
3791 assert_eq!(
3792 p("5+ABC.123"),
3793 Version::new([5]).with_local_segments(vec![
3794 LocalSegment::String("abc".to_string()),
3795 LocalSegment::Number(123),
3796 ])
3797 );
3798 assert_eq!(
3799 p("5+ABC-123.4_5_xyz-MNO"),
3800 Version::new([5]).with_local_segments(vec![
3801 LocalSegment::String("abc".to_string()),
3802 LocalSegment::Number(123),
3803 LocalSegment::Number(4),
3804 LocalSegment::Number(5),
3805 LocalSegment::String("xyz".to_string()),
3806 LocalSegment::String("mno".to_string()),
3807 ])
3808 );
3809 assert_eq!(
3810 p("5.6.7+abc-00123"),
3811 Version::new([5, 6, 7]).with_local_segments(vec![
3812 LocalSegment::String("abc".to_string()),
3813 LocalSegment::Number(123),
3814 ])
3815 );
3816 assert_eq!(
3817 p("5.6.7+abc-foo00123"),
3818 Version::new([5, 6, 7]).with_local_segments(vec![
3819 LocalSegment::String("abc".to_string()),
3820 LocalSegment::String("foo00123".to_string()),
3821 ])
3822 );
3823 assert_eq!(
3824 p("5.6.7+abc-00123a"),
3825 Version::new([5, 6, 7]).with_local_segments(vec![
3826 LocalSegment::String("abc".to_string()),
3827 LocalSegment::String("00123a".to_string()),
3828 ])
3829 );
3830
3831 assert_eq!(
3833 p("5a2post3"),
3834 Version::new([5])
3835 .with_pre(Some(Prerelease {
3836 kind: PrereleaseKind::Alpha,
3837 number: 2
3838 }))
3839 .with_post(Some(3))
3840 );
3841 assert_eq!(
3842 p("5.a-2_post-3"),
3843 Version::new([5])
3844 .with_pre(Some(Prerelease {
3845 kind: PrereleaseKind::Alpha,
3846 number: 2
3847 }))
3848 .with_post(Some(3))
3849 );
3850 assert_eq!(
3851 p("5a2-3"),
3852 Version::new([5])
3853 .with_pre(Some(Prerelease {
3854 kind: PrereleaseKind::Alpha,
3855 number: 2
3856 }))
3857 .with_post(Some(3))
3858 );
3859
3860 assert_eq!(p("v5"), Version::new([5]));
3862 assert_eq!(p("V5"), Version::new([5]));
3863 assert_eq!(p("v5.6.7"), Version::new([5, 6, 7]));
3864
3865 assert_eq!(p(" v5 "), Version::new([5]));
3867 assert_eq!(p(" 5 "), Version::new([5]));
3868 assert_eq!(
3869 p(" 5.6.7+abc.123.xyz "),
3870 Version::new([5, 6, 7]).with_local_segments(vec![
3871 LocalSegment::String("abc".to_string()),
3872 LocalSegment::Number(123),
3873 LocalSegment::String("xyz".to_string())
3874 ])
3875 );
3876 assert_eq!(p(" \n5\n \t"), Version::new([5]));
3877
3878 assert!(Parser::new("1.min0".as_bytes()).parse().is_err());
3880 }
3881
3882 #[test]
3890 fn parse_version_invalid() {
3891 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3892 Err(err) => err,
3893 Ok(v) => unreachable!(
3894 "expected version parser error, but got: {v:?}",
3895 v = v.as_bloated_debug()
3896 ),
3897 };
3898
3899 assert_eq!(p(""), ErrorKind::NoLeadingNumber.into());
3900 assert_eq!(p("a"), ErrorKind::NoLeadingNumber.into());
3901 assert_eq!(p("v 5"), ErrorKind::NoLeadingNumber.into());
3902 assert_eq!(p("V 5"), ErrorKind::NoLeadingNumber.into());
3903 assert_eq!(p("x 5"), ErrorKind::NoLeadingNumber.into());
3904 assert_eq!(
3905 p("18446744073709551616"),
3906 ErrorKind::NumberTooBig {
3907 bytes: b"18446744073709551616".to_vec()
3908 }
3909 .into()
3910 );
3911 assert_eq!(p("5!"), ErrorKind::NoLeadingReleaseNumber.into());
3912 assert_eq!(
3913 p("5.6./"),
3914 ErrorKind::UnexpectedEnd {
3915 version: "5.6".to_string(),
3916 remaining: "./".to_string()
3917 }
3918 .into()
3919 );
3920 assert_eq!(
3921 p("5.6.-alpha2"),
3922 ErrorKind::UnexpectedEnd {
3923 version: "5.6".to_string(),
3924 remaining: ".-alpha2".to_string()
3925 }
3926 .into()
3927 );
3928 assert_eq!(
3929 p("1.2.3a18446744073709551616"),
3930 ErrorKind::NumberTooBig {
3931 bytes: b"18446744073709551616".to_vec()
3932 }
3933 .into()
3934 );
3935 assert_eq!(p("5+"), ErrorKind::LocalEmpty { precursor: '+' }.into());
3936 assert_eq!(p("5+ "), ErrorKind::LocalEmpty { precursor: '+' }.into());
3937 assert_eq!(p("5+abc."), ErrorKind::LocalEmpty { precursor: '.' }.into());
3938 assert_eq!(p("5+abc-"), ErrorKind::LocalEmpty { precursor: '-' }.into());
3939 assert_eq!(p("5+abc_"), ErrorKind::LocalEmpty { precursor: '_' }.into());
3940 assert_eq!(
3941 p("5+abc. "),
3942 ErrorKind::LocalEmpty { precursor: '.' }.into()
3943 );
3944 assert_eq!(
3945 p("5.6-"),
3946 ErrorKind::UnexpectedEnd {
3947 version: "5.6".to_string(),
3948 remaining: "-".to_string()
3949 }
3950 .into()
3951 );
3952 }
3953
3954 #[test]
3955 fn parse_version_pattern_valid() {
3956 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3957 Ok(v) => v,
3958 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3959 };
3960
3961 assert_eq!(p("5.*"), VersionPattern::wildcard(Version::new([5])));
3962 assert_eq!(p("5.6.*"), VersionPattern::wildcard(Version::new([5, 6])));
3963 assert_eq!(
3964 p("2!5.6.*"),
3965 VersionPattern::wildcard(Version::new([5, 6]).with_epoch(2))
3966 );
3967 }
3968
3969 #[test]
3970 fn parse_version_pattern_invalid() {
3971 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3972 Err(err) => err,
3973 Ok(vpat) => unreachable!("expected version pattern parser error, but got: {vpat:?}"),
3974 };
3975
3976 assert_eq!(p("*"), ErrorKind::NoLeadingNumber.into());
3977 assert_eq!(p("2!*"), ErrorKind::NoLeadingReleaseNumber.into());
3978 }
3979
3980 #[test]
3985 fn ordering() {
3986 let versions = &[
3987 "1.dev0",
3988 "1.0.dev456",
3989 "1.0a1",
3990 "1.0a2.dev456",
3991 "1.0a12.dev456",
3992 "1.0a12",
3993 "1.0b1.dev456",
3994 "1.0b2",
3995 "1.0b2.post345.dev456",
3996 "1.0b2.post345",
3997 "1.0rc1.dev456",
3998 "1.0rc1",
3999 "1.0",
4000 "1.0+abc.5",
4001 "1.0+abc.7",
4002 "1.0+5",
4003 "1.0.post456.dev34",
4004 "1.0.post456",
4005 "1.0.15",
4006 "1.1.dev1",
4007 ];
4008 for (i, v1) in versions.iter().enumerate() {
4009 for v2 in &versions[i + 1..] {
4010 let less = v1.parse::<Version>().unwrap();
4011 let greater = v2.parse::<Version>().unwrap();
4012 assert_eq!(
4013 less.cmp(&greater),
4014 Ordering::Less,
4015 "less: {:?}\ngreater: {:?}",
4016 less.as_bloated_debug(),
4017 greater.as_bloated_debug()
4018 );
4019 }
4020 }
4021 }
4022
4023 #[test]
4024 fn local_sentinel_version() {
4025 let sentinel = Version::new([1, 0]).with_local(LocalVersion::Max);
4026
4027 let versions = &["1.0.post0", "1.1"];
4029
4030 for greater in versions {
4031 let greater = greater.parse::<Version>().unwrap();
4032 assert_eq!(
4033 sentinel.cmp(&greater),
4034 Ordering::Less,
4035 "less: {:?}\ngreater: {:?}",
4036 greater.as_bloated_debug(),
4037 sentinel.as_bloated_debug(),
4038 );
4039 }
4040
4041 let versions = &["1.0", "1.0.a0", "1.0+local"];
4043
4044 for less in versions {
4045 let less = less.parse::<Version>().unwrap();
4046 assert_eq!(
4047 sentinel.cmp(&less),
4048 Ordering::Greater,
4049 "less: {:?}\ngreater: {:?}",
4050 sentinel.as_bloated_debug(),
4051 less.as_bloated_debug()
4052 );
4053 }
4054 }
4055
4056 #[test]
4057 fn min_version() {
4058 let less = Version::new([1, 0]).with_min(Some(0));
4060
4061 let versions = &[
4062 "1.dev0",
4063 "1.0.dev456",
4064 "1.0a1",
4065 "1.0a2.dev456",
4066 "1.0a12.dev456",
4067 "1.0a12",
4068 "1.0b1.dev456",
4069 "1.0b2",
4070 "1.0b2.post345.dev456",
4071 "1.0b2.post345",
4072 "1.0rc1.dev456",
4073 "1.0rc1",
4074 "1.0",
4075 "1.0+abc.5",
4076 "1.0+abc.7",
4077 "1.0+5",
4078 "1.0.post456.dev34",
4079 "1.0.post456",
4080 "1.0.15",
4081 "1.1.dev1",
4082 ];
4083
4084 for greater in versions {
4085 let greater = greater.parse::<Version>().unwrap();
4086 assert_eq!(
4087 less.cmp(&greater),
4088 Ordering::Less,
4089 "less: {:?}\ngreater: {:?}",
4090 less.as_bloated_debug(),
4091 greater.as_bloated_debug()
4092 );
4093 }
4094 }
4095
4096 #[test]
4097 fn max_version() {
4098 let greater = Version::new([1, 0]).with_max(Some(0));
4100
4101 let versions = &[
4102 "1.dev0",
4103 "1.0.dev456",
4104 "1.0a1",
4105 "1.0a2.dev456",
4106 "1.0a12.dev456",
4107 "1.0a12",
4108 "1.0b1.dev456",
4109 "1.0b2",
4110 "1.0b2.post345.dev456",
4111 "1.0b2.post345",
4112 "1.0rc1.dev456",
4113 "1.0rc1",
4114 "1.0",
4115 "1.0+abc.5",
4116 "1.0+abc.7",
4117 "1.0+5",
4118 "1.0.post456.dev34",
4119 "1.0.post456",
4120 "1.0",
4121 ];
4122
4123 for less in versions {
4124 let less = less.parse::<Version>().unwrap();
4125 assert_eq!(
4126 less.cmp(&greater),
4127 Ordering::Less,
4128 "less: {:?}\ngreater: {:?}",
4129 less.as_bloated_debug(),
4130 greater.as_bloated_debug()
4131 );
4132 }
4133
4134 let greater = Version::new([1, 0])
4136 .with_pre(Some(Prerelease {
4137 kind: PrereleaseKind::Alpha,
4138 number: 1,
4139 }))
4140 .with_max(Some(0));
4141
4142 let versions = &["1.0a1", "1.0a1+local", "1.0a1.post1"];
4143
4144 for less in versions {
4145 let less = less.parse::<Version>().unwrap();
4146 assert_eq!(
4147 less.cmp(&greater),
4148 Ordering::Less,
4149 "less: {:?}\ngreater: {:?}",
4150 less.as_bloated_debug(),
4151 greater.as_bloated_debug()
4152 );
4153 }
4154
4155 let less = Version::new([1, 0])
4157 .with_pre(Some(Prerelease {
4158 kind: PrereleaseKind::Alpha,
4159 number: 1,
4160 }))
4161 .with_max(Some(0));
4162
4163 let versions = &["1.0b1", "1.0b1+local", "1.0b1.post1", "1.0"];
4164
4165 for greater in versions {
4166 let greater = greater.parse::<Version>().unwrap();
4167 assert_eq!(
4168 less.cmp(&greater),
4169 Ordering::Less,
4170 "less: {:?}\ngreater: {:?}",
4171 less.as_bloated_debug(),
4172 greater.as_bloated_debug()
4173 );
4174 }
4175 }
4176
4177 #[test]
4179 fn parse_number_u64() {
4180 let p = |s: &str| parse_u64(s.as_bytes());
4181 assert_eq!(p("0"), Ok(0));
4182 assert_eq!(p("00"), Ok(0));
4183 assert_eq!(p("1"), Ok(1));
4184 assert_eq!(p("01"), Ok(1));
4185 assert_eq!(p("9"), Ok(9));
4186 assert_eq!(p("10"), Ok(10));
4187 assert_eq!(p("18446744073709551615"), Ok(18_446_744_073_709_551_615));
4188 assert_eq!(p("018446744073709551615"), Ok(18_446_744_073_709_551_615));
4189 assert_eq!(
4190 p("000000018446744073709551615"),
4191 Ok(18_446_744_073_709_551_615)
4192 );
4193
4194 assert_eq!(p("10a"), Err(ErrorKind::InvalidDigit { got: b'a' }.into()));
4195 assert_eq!(p("10["), Err(ErrorKind::InvalidDigit { got: b'[' }.into()));
4196 assert_eq!(p("10/"), Err(ErrorKind::InvalidDigit { got: b'/' }.into()));
4197 assert_eq!(
4199 p("18446744073709551616"),
4200 Err(ErrorKind::NumberTooBig {
4201 bytes: b"18446744073709551616".to_vec()
4202 }
4203 .into())
4204 );
4205 assert_eq!(
4206 p("18446744073799551615abc"),
4207 Err(ErrorKind::NumberTooBig {
4208 bytes: b"18446744073799551615abc".to_vec()
4209 }
4210 .into())
4211 );
4212 assert_eq!(
4213 parse_u64(b"18446744073799551615\xFF"),
4214 Err(ErrorKind::NumberTooBig {
4215 bytes: b"18446744073799551615\xFF".to_vec()
4216 }
4217 .into())
4218 );
4219 }
4220
4221 struct VersionBloatedDebug<'a>(&'a Version);
4232
4233 impl std::fmt::Debug for VersionBloatedDebug<'_> {
4234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4235 f.debug_struct("Version")
4236 .field("epoch", &self.0.epoch())
4237 .field("release", &&*self.0.release())
4238 .field("pre", &self.0.pre())
4239 .field("post", &self.0.post())
4240 .field("dev", &self.0.dev())
4241 .field("local", &self.0.local())
4242 .field("min", &self.0.min())
4243 .field("max", &self.0.max())
4244 .finish()
4245 }
4246 }
4247
4248 impl Version {
4249 pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4250 VersionBloatedDebug(self)
4251 }
4252 }
4253
4254 #[test]
4258 fn preserve_trailing_zeros() {
4259 let v1: Version = "1.2.0".parse().unwrap();
4260 assert_eq!(&*v1.release(), &[1, 2, 0]);
4261 assert_eq!(v1.to_string(), "1.2.0");
4262
4263 let v2: Version = "1.2".parse().unwrap();
4264 assert_eq!(&*v2.release(), &[1, 2]);
4265 assert_eq!(v2.to_string(), "1.2");
4266 }
4267
4268 #[test]
4269 fn type_size() {
4270 assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4271 assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4272 }
4273
4274 #[test]
4277 fn bump_major() {
4278 let mut version = "0".parse::<Version>().unwrap();
4280 version.bump(BumpCommand::BumpRelease {
4281 index: 0,
4282 value: None,
4283 });
4284 assert_eq!(version.to_string().as_str(), "1");
4285
4286 let mut version = "1.5".parse::<Version>().unwrap();
4288 version.bump(BumpCommand::BumpRelease {
4289 index: 0,
4290 value: None,
4291 });
4292 assert_eq!(version.to_string().as_str(), "2.0");
4293
4294 let mut version = "0.1.2".parse::<Version>().unwrap();
4296 version.bump(BumpCommand::BumpRelease {
4297 index: 0,
4298 value: None,
4299 });
4300 assert_eq!(version.to_string().as_str(), "1.0.0");
4301
4302 let mut version = "1.2.3".parse::<Version>().unwrap();
4304 version.bump(BumpCommand::BumpRelease {
4305 index: 0,
4306 value: None,
4307 });
4308 assert_eq!(version.to_string().as_str(), "2.0.0");
4309
4310 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4312 version.bump(BumpCommand::BumpRelease {
4313 index: 0,
4314 value: None,
4315 });
4316 assert_eq!(version.to_string().as_str(), "2.0.0.0");
4317
4318 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4320 .parse::<Version>()
4321 .unwrap();
4322 version.bump(BumpCommand::BumpRelease {
4323 index: 0,
4324 value: None,
4325 });
4326 assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4327 version.bump(BumpCommand::BumpRelease {
4328 index: 0,
4329 value: None,
4330 });
4331 assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4332 }
4333
4334 #[test]
4337 fn bump_minor() {
4338 let mut version = "0".parse::<Version>().unwrap();
4340 version.bump(BumpCommand::BumpRelease {
4341 index: 1,
4342 value: None,
4343 });
4344 assert_eq!(version.to_string().as_str(), "0.1");
4345
4346 let mut version = "1.5".parse::<Version>().unwrap();
4348 version.bump(BumpCommand::BumpRelease {
4349 index: 1,
4350 value: None,
4351 });
4352 assert_eq!(version.to_string().as_str(), "1.6");
4353
4354 let mut version = "5.3.6".parse::<Version>().unwrap();
4356 version.bump(BumpCommand::BumpRelease {
4357 index: 1,
4358 value: None,
4359 });
4360 assert_eq!(version.to_string().as_str(), "5.4.0");
4361
4362 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4364 version.bump(BumpCommand::BumpRelease {
4365 index: 1,
4366 value: None,
4367 });
4368 assert_eq!(version.to_string().as_str(), "1.3.0.0");
4369
4370 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4372 .parse::<Version>()
4373 .unwrap();
4374 version.bump(BumpCommand::BumpRelease {
4375 index: 1,
4376 value: None,
4377 });
4378 assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4379 version.bump(BumpCommand::BumpRelease {
4380 index: 1,
4381 value: None,
4382 });
4383 assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4384 }
4385
4386 #[test]
4389 fn bump_patch() {
4390 let mut version = "0".parse::<Version>().unwrap();
4392 version.bump(BumpCommand::BumpRelease {
4393 index: 2,
4394 value: None,
4395 });
4396 assert_eq!(version.to_string().as_str(), "0.0.1");
4397
4398 let mut version = "1.5".parse::<Version>().unwrap();
4400 version.bump(BumpCommand::BumpRelease {
4401 index: 2,
4402 value: None,
4403 });
4404 assert_eq!(version.to_string().as_str(), "1.5.1");
4405
4406 let mut version = "5.3.6".parse::<Version>().unwrap();
4408 version.bump(BumpCommand::BumpRelease {
4409 index: 2,
4410 value: None,
4411 });
4412 assert_eq!(version.to_string().as_str(), "5.3.7");
4413
4414 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4416 version.bump(BumpCommand::BumpRelease {
4417 index: 2,
4418 value: None,
4419 });
4420 assert_eq!(version.to_string().as_str(), "1.2.4.0");
4421
4422 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4424 .parse::<Version>()
4425 .unwrap();
4426 version.bump(BumpCommand::BumpRelease {
4427 index: 2,
4428 value: None,
4429 });
4430 assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4431 version.bump(BumpCommand::BumpRelease {
4432 index: 2,
4433 value: None,
4434 });
4435 assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4436 }
4437
4438 #[test]
4441 fn bump_alpha() {
4442 let mut version = "0".parse::<Version>().unwrap();
4444 version.bump(BumpCommand::BumpPrerelease {
4445 kind: PrereleaseKind::Alpha,
4446 value: None,
4447 });
4448 assert_eq!(version.to_string().as_str(), "0a1");
4449
4450 let mut version = "1.5".parse::<Version>().unwrap();
4452 version.bump(BumpCommand::BumpPrerelease {
4453 kind: PrereleaseKind::Alpha,
4454 value: None,
4455 });
4456 assert_eq!(version.to_string().as_str(), "1.5a1");
4457
4458 let mut version = "5.3.6".parse::<Version>().unwrap();
4460 version.bump(BumpCommand::BumpPrerelease {
4461 kind: PrereleaseKind::Alpha,
4462 value: None,
4463 });
4464 assert_eq!(version.to_string().as_str(), "5.3.6a1");
4465
4466 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4468 version.bump(BumpCommand::BumpPrerelease {
4469 kind: PrereleaseKind::Alpha,
4470 value: None,
4471 });
4472 assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4473
4474 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4476 .parse::<Version>()
4477 .unwrap();
4478 version.bump(BumpCommand::BumpPrerelease {
4479 kind: PrereleaseKind::Alpha,
4480 value: None,
4481 });
4482 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4483 version.bump(BumpCommand::BumpPrerelease {
4484 kind: PrereleaseKind::Alpha,
4485 value: None,
4486 });
4487 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4488 }
4489
4490 #[test]
4493 fn bump_beta() {
4494 let mut version = "0".parse::<Version>().unwrap();
4496 version.bump(BumpCommand::BumpPrerelease {
4497 kind: PrereleaseKind::Beta,
4498 value: None,
4499 });
4500 assert_eq!(version.to_string().as_str(), "0b1");
4501
4502 let mut version = "1.5".parse::<Version>().unwrap();
4504 version.bump(BumpCommand::BumpPrerelease {
4505 kind: PrereleaseKind::Beta,
4506 value: None,
4507 });
4508 assert_eq!(version.to_string().as_str(), "1.5b1");
4509
4510 let mut version = "5.3.6".parse::<Version>().unwrap();
4512 version.bump(BumpCommand::BumpPrerelease {
4513 kind: PrereleaseKind::Beta,
4514 value: None,
4515 });
4516 assert_eq!(version.to_string().as_str(), "5.3.6b1");
4517
4518 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4520 version.bump(BumpCommand::BumpPrerelease {
4521 kind: PrereleaseKind::Beta,
4522 value: None,
4523 });
4524 assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4525
4526 let mut version = "5!1.7.3.5a2.post345.dev456+local"
4528 .parse::<Version>()
4529 .unwrap();
4530 version.bump(BumpCommand::BumpPrerelease {
4531 kind: PrereleaseKind::Beta,
4532 value: None,
4533 });
4534 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4535 version.bump(BumpCommand::BumpPrerelease {
4536 kind: PrereleaseKind::Beta,
4537 value: None,
4538 });
4539 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4540 }
4541
4542 #[test]
4545 fn bump_rc() {
4546 let mut version = "0".parse::<Version>().unwrap();
4548 version.bump(BumpCommand::BumpPrerelease {
4549 kind: PrereleaseKind::Rc,
4550 value: None,
4551 });
4552 assert_eq!(version.to_string().as_str(), "0rc1");
4553
4554 let mut version = "1.5".parse::<Version>().unwrap();
4556 version.bump(BumpCommand::BumpPrerelease {
4557 kind: PrereleaseKind::Rc,
4558 value: None,
4559 });
4560 assert_eq!(version.to_string().as_str(), "1.5rc1");
4561
4562 let mut version = "5.3.6".parse::<Version>().unwrap();
4564 version.bump(BumpCommand::BumpPrerelease {
4565 kind: PrereleaseKind::Rc,
4566 value: None,
4567 });
4568 assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4569
4570 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4572 version.bump(BumpCommand::BumpPrerelease {
4573 kind: PrereleaseKind::Rc,
4574 value: None,
4575 });
4576 assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4577
4578 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4580 .parse::<Version>()
4581 .unwrap();
4582 version.bump(BumpCommand::BumpPrerelease {
4583 kind: PrereleaseKind::Rc,
4584 value: None,
4585 });
4586 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4587 version.bump(BumpCommand::BumpPrerelease {
4588 kind: PrereleaseKind::Rc,
4589 value: None,
4590 });
4591 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4592 }
4593
4594 #[test]
4597 fn bump_post() {
4598 let mut version = "0".parse::<Version>().unwrap();
4600 version.bump(BumpCommand::BumpPost { value: None });
4601 assert_eq!(version.to_string().as_str(), "0.post1");
4602
4603 let mut version = "1.5".parse::<Version>().unwrap();
4605 version.bump(BumpCommand::BumpPost { value: None });
4606 assert_eq!(version.to_string().as_str(), "1.5.post1");
4607
4608 let mut version = "5.3.6".parse::<Version>().unwrap();
4610 version.bump(BumpCommand::BumpPost { value: None });
4611 assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4612
4613 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4615 version.bump(BumpCommand::BumpPost { value: None });
4616 assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4617
4618 let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4620 version.bump(BumpCommand::BumpPost { value: None });
4621 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4622 version.bump(BumpCommand::BumpPost { value: None });
4623 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4624 }
4625
4626 #[test]
4629 fn bump_dev() {
4630 let mut version = "0".parse::<Version>().unwrap();
4632 version.bump(BumpCommand::BumpDev { value: None });
4633 assert_eq!(version.to_string().as_str(), "0.dev1");
4634
4635 let mut version = "1.5".parse::<Version>().unwrap();
4637 version.bump(BumpCommand::BumpDev { value: None });
4638 assert_eq!(version.to_string().as_str(), "1.5.dev1");
4639
4640 let mut version = "5.3.6".parse::<Version>().unwrap();
4642 version.bump(BumpCommand::BumpDev { value: None });
4643 assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4644
4645 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4647 version.bump(BumpCommand::BumpDev { value: None });
4648 assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4649
4650 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4652 version.bump(BumpCommand::BumpDev { value: None });
4653 assert_eq!(
4654 version.to_string().as_str(),
4655 "5!1.7.3.5b2.post345.dev1+local"
4656 );
4657 version.bump(BumpCommand::BumpDev { value: None });
4658 assert_eq!(
4659 version.to_string().as_str(),
4660 "5!1.7.3.5b2.post345.dev2+local"
4661 );
4662 }
4663
4664 #[test]
4667 fn make_stable() {
4668 let mut version = "0".parse::<Version>().unwrap();
4670 version.bump(BumpCommand::MakeStable);
4671 assert_eq!(version.to_string().as_str(), "0");
4672
4673 let mut version = "1.5".parse::<Version>().unwrap();
4675 version.bump(BumpCommand::MakeStable);
4676 assert_eq!(version.to_string().as_str(), "1.5");
4677
4678 let mut version = "5.3.6".parse::<Version>().unwrap();
4680 version.bump(BumpCommand::MakeStable);
4681 assert_eq!(version.to_string().as_str(), "5.3.6");
4682
4683 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4685 version.bump(BumpCommand::MakeStable);
4686 assert_eq!(version.to_string().as_str(), "1.2.3.4");
4687
4688 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4690 version.bump(BumpCommand::MakeStable);
4691 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4692 version.bump(BumpCommand::MakeStable);
4693 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4694 }
4695}