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 impl Version {
4222 pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4232 std::fmt::from_fn(|f| {
4233 f.debug_struct("Version")
4234 .field("epoch", &self.epoch())
4235 .field("release", &&*self.release())
4236 .field("pre", &self.pre())
4237 .field("post", &self.post())
4238 .field("dev", &self.dev())
4239 .field("local", &self.local())
4240 .field("min", &self.min())
4241 .field("max", &self.max())
4242 .finish()
4243 })
4244 }
4245 }
4246
4247 #[test]
4251 fn preserve_trailing_zeros() {
4252 let v1: Version = "1.2.0".parse().unwrap();
4253 assert_eq!(&*v1.release(), &[1, 2, 0]);
4254 assert_eq!(v1.to_string(), "1.2.0");
4255
4256 let v2: Version = "1.2".parse().unwrap();
4257 assert_eq!(&*v2.release(), &[1, 2]);
4258 assert_eq!(v2.to_string(), "1.2");
4259 }
4260
4261 #[test]
4262 fn type_size() {
4263 assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4264 assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4265 }
4266
4267 #[test]
4270 fn bump_major() {
4271 let mut version = "0".parse::<Version>().unwrap();
4273 version.bump(BumpCommand::BumpRelease {
4274 index: 0,
4275 value: None,
4276 });
4277 assert_eq!(version.to_string().as_str(), "1");
4278
4279 let mut version = "1.5".parse::<Version>().unwrap();
4281 version.bump(BumpCommand::BumpRelease {
4282 index: 0,
4283 value: None,
4284 });
4285 assert_eq!(version.to_string().as_str(), "2.0");
4286
4287 let mut version = "0.1.2".parse::<Version>().unwrap();
4289 version.bump(BumpCommand::BumpRelease {
4290 index: 0,
4291 value: None,
4292 });
4293 assert_eq!(version.to_string().as_str(), "1.0.0");
4294
4295 let mut version = "1.2.3".parse::<Version>().unwrap();
4297 version.bump(BumpCommand::BumpRelease {
4298 index: 0,
4299 value: None,
4300 });
4301 assert_eq!(version.to_string().as_str(), "2.0.0");
4302
4303 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4305 version.bump(BumpCommand::BumpRelease {
4306 index: 0,
4307 value: None,
4308 });
4309 assert_eq!(version.to_string().as_str(), "2.0.0.0");
4310
4311 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4313 .parse::<Version>()
4314 .unwrap();
4315 version.bump(BumpCommand::BumpRelease {
4316 index: 0,
4317 value: None,
4318 });
4319 assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4320 version.bump(BumpCommand::BumpRelease {
4321 index: 0,
4322 value: None,
4323 });
4324 assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4325 }
4326
4327 #[test]
4330 fn bump_minor() {
4331 let mut version = "0".parse::<Version>().unwrap();
4333 version.bump(BumpCommand::BumpRelease {
4334 index: 1,
4335 value: None,
4336 });
4337 assert_eq!(version.to_string().as_str(), "0.1");
4338
4339 let mut version = "1.5".parse::<Version>().unwrap();
4341 version.bump(BumpCommand::BumpRelease {
4342 index: 1,
4343 value: None,
4344 });
4345 assert_eq!(version.to_string().as_str(), "1.6");
4346
4347 let mut version = "5.3.6".parse::<Version>().unwrap();
4349 version.bump(BumpCommand::BumpRelease {
4350 index: 1,
4351 value: None,
4352 });
4353 assert_eq!(version.to_string().as_str(), "5.4.0");
4354
4355 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4357 version.bump(BumpCommand::BumpRelease {
4358 index: 1,
4359 value: None,
4360 });
4361 assert_eq!(version.to_string().as_str(), "1.3.0.0");
4362
4363 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4365 .parse::<Version>()
4366 .unwrap();
4367 version.bump(BumpCommand::BumpRelease {
4368 index: 1,
4369 value: None,
4370 });
4371 assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4372 version.bump(BumpCommand::BumpRelease {
4373 index: 1,
4374 value: None,
4375 });
4376 assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4377 }
4378
4379 #[test]
4382 fn bump_patch() {
4383 let mut version = "0".parse::<Version>().unwrap();
4385 version.bump(BumpCommand::BumpRelease {
4386 index: 2,
4387 value: None,
4388 });
4389 assert_eq!(version.to_string().as_str(), "0.0.1");
4390
4391 let mut version = "1.5".parse::<Version>().unwrap();
4393 version.bump(BumpCommand::BumpRelease {
4394 index: 2,
4395 value: None,
4396 });
4397 assert_eq!(version.to_string().as_str(), "1.5.1");
4398
4399 let mut version = "5.3.6".parse::<Version>().unwrap();
4401 version.bump(BumpCommand::BumpRelease {
4402 index: 2,
4403 value: None,
4404 });
4405 assert_eq!(version.to_string().as_str(), "5.3.7");
4406
4407 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4409 version.bump(BumpCommand::BumpRelease {
4410 index: 2,
4411 value: None,
4412 });
4413 assert_eq!(version.to_string().as_str(), "1.2.4.0");
4414
4415 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4417 .parse::<Version>()
4418 .unwrap();
4419 version.bump(BumpCommand::BumpRelease {
4420 index: 2,
4421 value: None,
4422 });
4423 assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4424 version.bump(BumpCommand::BumpRelease {
4425 index: 2,
4426 value: None,
4427 });
4428 assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4429 }
4430
4431 #[test]
4434 fn bump_alpha() {
4435 let mut version = "0".parse::<Version>().unwrap();
4437 version.bump(BumpCommand::BumpPrerelease {
4438 kind: PrereleaseKind::Alpha,
4439 value: None,
4440 });
4441 assert_eq!(version.to_string().as_str(), "0a1");
4442
4443 let mut version = "1.5".parse::<Version>().unwrap();
4445 version.bump(BumpCommand::BumpPrerelease {
4446 kind: PrereleaseKind::Alpha,
4447 value: None,
4448 });
4449 assert_eq!(version.to_string().as_str(), "1.5a1");
4450
4451 let mut version = "5.3.6".parse::<Version>().unwrap();
4453 version.bump(BumpCommand::BumpPrerelease {
4454 kind: PrereleaseKind::Alpha,
4455 value: None,
4456 });
4457 assert_eq!(version.to_string().as_str(), "5.3.6a1");
4458
4459 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4461 version.bump(BumpCommand::BumpPrerelease {
4462 kind: PrereleaseKind::Alpha,
4463 value: None,
4464 });
4465 assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4466
4467 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4469 .parse::<Version>()
4470 .unwrap();
4471 version.bump(BumpCommand::BumpPrerelease {
4472 kind: PrereleaseKind::Alpha,
4473 value: None,
4474 });
4475 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4476 version.bump(BumpCommand::BumpPrerelease {
4477 kind: PrereleaseKind::Alpha,
4478 value: None,
4479 });
4480 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4481 }
4482
4483 #[test]
4486 fn bump_beta() {
4487 let mut version = "0".parse::<Version>().unwrap();
4489 version.bump(BumpCommand::BumpPrerelease {
4490 kind: PrereleaseKind::Beta,
4491 value: None,
4492 });
4493 assert_eq!(version.to_string().as_str(), "0b1");
4494
4495 let mut version = "1.5".parse::<Version>().unwrap();
4497 version.bump(BumpCommand::BumpPrerelease {
4498 kind: PrereleaseKind::Beta,
4499 value: None,
4500 });
4501 assert_eq!(version.to_string().as_str(), "1.5b1");
4502
4503 let mut version = "5.3.6".parse::<Version>().unwrap();
4505 version.bump(BumpCommand::BumpPrerelease {
4506 kind: PrereleaseKind::Beta,
4507 value: None,
4508 });
4509 assert_eq!(version.to_string().as_str(), "5.3.6b1");
4510
4511 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4513 version.bump(BumpCommand::BumpPrerelease {
4514 kind: PrereleaseKind::Beta,
4515 value: None,
4516 });
4517 assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4518
4519 let mut version = "5!1.7.3.5a2.post345.dev456+local"
4521 .parse::<Version>()
4522 .unwrap();
4523 version.bump(BumpCommand::BumpPrerelease {
4524 kind: PrereleaseKind::Beta,
4525 value: None,
4526 });
4527 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4528 version.bump(BumpCommand::BumpPrerelease {
4529 kind: PrereleaseKind::Beta,
4530 value: None,
4531 });
4532 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4533 }
4534
4535 #[test]
4538 fn bump_rc() {
4539 let mut version = "0".parse::<Version>().unwrap();
4541 version.bump(BumpCommand::BumpPrerelease {
4542 kind: PrereleaseKind::Rc,
4543 value: None,
4544 });
4545 assert_eq!(version.to_string().as_str(), "0rc1");
4546
4547 let mut version = "1.5".parse::<Version>().unwrap();
4549 version.bump(BumpCommand::BumpPrerelease {
4550 kind: PrereleaseKind::Rc,
4551 value: None,
4552 });
4553 assert_eq!(version.to_string().as_str(), "1.5rc1");
4554
4555 let mut version = "5.3.6".parse::<Version>().unwrap();
4557 version.bump(BumpCommand::BumpPrerelease {
4558 kind: PrereleaseKind::Rc,
4559 value: None,
4560 });
4561 assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4562
4563 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4565 version.bump(BumpCommand::BumpPrerelease {
4566 kind: PrereleaseKind::Rc,
4567 value: None,
4568 });
4569 assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4570
4571 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4573 .parse::<Version>()
4574 .unwrap();
4575 version.bump(BumpCommand::BumpPrerelease {
4576 kind: PrereleaseKind::Rc,
4577 value: None,
4578 });
4579 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4580 version.bump(BumpCommand::BumpPrerelease {
4581 kind: PrereleaseKind::Rc,
4582 value: None,
4583 });
4584 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4585 }
4586
4587 #[test]
4590 fn bump_post() {
4591 let mut version = "0".parse::<Version>().unwrap();
4593 version.bump(BumpCommand::BumpPost { value: None });
4594 assert_eq!(version.to_string().as_str(), "0.post1");
4595
4596 let mut version = "1.5".parse::<Version>().unwrap();
4598 version.bump(BumpCommand::BumpPost { value: None });
4599 assert_eq!(version.to_string().as_str(), "1.5.post1");
4600
4601 let mut version = "5.3.6".parse::<Version>().unwrap();
4603 version.bump(BumpCommand::BumpPost { value: None });
4604 assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4605
4606 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4608 version.bump(BumpCommand::BumpPost { value: None });
4609 assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4610
4611 let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4613 version.bump(BumpCommand::BumpPost { value: None });
4614 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4615 version.bump(BumpCommand::BumpPost { value: None });
4616 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4617 }
4618
4619 #[test]
4622 fn bump_dev() {
4623 let mut version = "0".parse::<Version>().unwrap();
4625 version.bump(BumpCommand::BumpDev { value: None });
4626 assert_eq!(version.to_string().as_str(), "0.dev1");
4627
4628 let mut version = "1.5".parse::<Version>().unwrap();
4630 version.bump(BumpCommand::BumpDev { value: None });
4631 assert_eq!(version.to_string().as_str(), "1.5.dev1");
4632
4633 let mut version = "5.3.6".parse::<Version>().unwrap();
4635 version.bump(BumpCommand::BumpDev { value: None });
4636 assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4637
4638 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4640 version.bump(BumpCommand::BumpDev { value: None });
4641 assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4642
4643 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4645 version.bump(BumpCommand::BumpDev { value: None });
4646 assert_eq!(
4647 version.to_string().as_str(),
4648 "5!1.7.3.5b2.post345.dev1+local"
4649 );
4650 version.bump(BumpCommand::BumpDev { value: None });
4651 assert_eq!(
4652 version.to_string().as_str(),
4653 "5!1.7.3.5b2.post345.dev2+local"
4654 );
4655 }
4656
4657 #[test]
4660 fn make_stable() {
4661 let mut version = "0".parse::<Version>().unwrap();
4663 version.bump(BumpCommand::MakeStable);
4664 assert_eq!(version.to_string().as_str(), "0");
4665
4666 let mut version = "1.5".parse::<Version>().unwrap();
4668 version.bump(BumpCommand::MakeStable);
4669 assert_eq!(version.to_string().as_str(), "1.5");
4670
4671 let mut version = "5.3.6".parse::<Version>().unwrap();
4673 version.bump(BumpCommand::MakeStable);
4674 assert_eq!(version.to_string().as_str(), "5.3.6");
4675
4676 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4678 version.bump(BumpCommand::MakeStable);
4679 assert_eq!(version.to_string().as_str(), "1.2.3.4");
4680
4681 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4683 version.bump(BumpCommand::MakeStable);
4684 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4685 version.bump(BumpCommand::MakeStable);
4686 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4687 }
4688}