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 #[allow(clippy::unused_self)]
1210 fn epoch(&self) -> u64 {
1211 0
1212 }
1213
1214 #[inline]
1215 #[allow(clippy::unused_self)]
1216 fn set_epoch(&mut self, value: u64) -> bool {
1217 if value != 0 {
1218 return false;
1219 }
1220 true
1221 }
1222
1223 #[inline]
1224 fn clear_release(&mut self) {
1225 self.repr &= !Self::SUFFIX_RELEASE_MASK;
1226 self.len = 0;
1227 }
1228
1229 #[inline]
1230 fn push_release(&mut self, n: u64) -> bool {
1231 if self.len == 0 {
1232 if n > u64::from(u16::MAX) {
1233 return false;
1234 }
1235 self.repr |= n << 48;
1236 self.len = 1;
1237 true
1238 } else {
1239 if n > u64::from(u8::MAX) {
1240 return false;
1241 }
1242 if self.len >= 4 {
1243 return false;
1244 }
1245 let shift = 48 - (usize::from(self.len) * 8);
1246 self.repr |= n << shift;
1247 self.len += 1;
1248 true
1249 }
1250 }
1251
1252 #[inline]
1253 fn post(&self) -> Option<u64> {
1254 if self.suffix_kind() == Self::SUFFIX_POST {
1255 Some(self.suffix_version())
1256 } else {
1257 None
1258 }
1259 }
1260
1261 #[inline]
1262 fn set_post(&mut self, value: Option<u64>) -> bool {
1263 let suffix_kind = self.suffix_kind();
1264 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1265 return value.is_none();
1266 }
1267 match value {
1268 None => {
1269 self.set_suffix_kind(Self::SUFFIX_NONE);
1270 }
1271 Some(number) => {
1272 if number > Self::SUFFIX_VERSION_MASK {
1273 return false;
1274 }
1275 self.set_suffix_kind(Self::SUFFIX_POST);
1276 self.set_suffix_version(number);
1277 }
1278 }
1279 true
1280 }
1281
1282 #[inline]
1283 fn pre(&self) -> Option<Prerelease> {
1284 let (kind, number) = (self.suffix_kind(), self.suffix_version());
1285 if kind == Self::SUFFIX_PRE_ALPHA {
1286 Some(Prerelease {
1287 kind: PrereleaseKind::Alpha,
1288 number,
1289 })
1290 } else if kind == Self::SUFFIX_PRE_BETA {
1291 Some(Prerelease {
1292 kind: PrereleaseKind::Beta,
1293 number,
1294 })
1295 } else if kind == Self::SUFFIX_PRE_RC {
1296 Some(Prerelease {
1297 kind: PrereleaseKind::Rc,
1298 number,
1299 })
1300 } else {
1301 None
1302 }
1303 }
1304
1305 #[inline]
1306 fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1307 let suffix_kind = self.suffix_kind();
1308 if !(suffix_kind == Self::SUFFIX_NONE
1309 || suffix_kind == Self::SUFFIX_PRE_ALPHA
1310 || suffix_kind == Self::SUFFIX_PRE_BETA
1311 || suffix_kind == Self::SUFFIX_PRE_RC)
1312 {
1313 return value.is_none();
1314 }
1315 match value {
1316 None => {
1317 self.set_suffix_kind(Self::SUFFIX_NONE);
1318 }
1319 Some(Prerelease { kind, number }) => {
1320 if number > Self::SUFFIX_VERSION_MASK {
1321 return false;
1322 }
1323 match kind {
1324 PrereleaseKind::Alpha => {
1325 self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1326 }
1327 PrereleaseKind::Beta => {
1328 self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1329 }
1330 PrereleaseKind::Rc => {
1331 self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1332 }
1333 }
1334 self.set_suffix_version(number);
1335 }
1336 }
1337 true
1338 }
1339
1340 #[inline]
1341 fn dev(&self) -> Option<u64> {
1342 if self.suffix_kind() == Self::SUFFIX_DEV {
1343 Some(self.suffix_version())
1344 } else {
1345 None
1346 }
1347 }
1348
1349 #[inline]
1350 fn set_dev(&mut self, value: Option<u64>) -> bool {
1351 let suffix_kind = self.suffix_kind();
1352 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1353 return value.is_none();
1354 }
1355 match value {
1356 None => {
1357 self.set_suffix_kind(Self::SUFFIX_NONE);
1358 }
1359 Some(number) => {
1360 if number > Self::SUFFIX_VERSION_MASK {
1361 return false;
1362 }
1363 self.set_suffix_kind(Self::SUFFIX_DEV);
1364 self.set_suffix_version(number);
1365 }
1366 }
1367 true
1368 }
1369
1370 #[inline]
1371 fn min(&self) -> Option<u64> {
1372 if self.suffix_kind() == Self::SUFFIX_MIN {
1373 Some(self.suffix_version())
1374 } else {
1375 None
1376 }
1377 }
1378
1379 #[inline]
1380 fn set_min(&mut self, value: Option<u64>) -> bool {
1381 let suffix_kind = self.suffix_kind();
1382 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1383 return value.is_none();
1384 }
1385 match value {
1386 None => {
1387 self.set_suffix_kind(Self::SUFFIX_NONE);
1388 }
1389 Some(number) => {
1390 if number > Self::SUFFIX_VERSION_MASK {
1391 return false;
1392 }
1393 self.set_suffix_kind(Self::SUFFIX_MIN);
1394 self.set_suffix_version(number);
1395 }
1396 }
1397 true
1398 }
1399
1400 #[inline]
1401 fn max(&self) -> Option<u64> {
1402 if self.suffix_kind() == Self::SUFFIX_MAX {
1403 Some(self.suffix_version())
1404 } else {
1405 None
1406 }
1407 }
1408
1409 #[inline]
1410 fn set_max(&mut self, value: Option<u64>) -> bool {
1411 let suffix_kind = self.suffix_kind();
1412 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1413 return value.is_none();
1414 }
1415 match value {
1416 None => {
1417 self.set_suffix_kind(Self::SUFFIX_NONE);
1418 }
1419 Some(number) => {
1420 if number > Self::SUFFIX_VERSION_MASK {
1421 return false;
1422 }
1423 self.set_suffix_kind(Self::SUFFIX_MAX);
1424 self.set_suffix_version(number);
1425 }
1426 }
1427 true
1428 }
1429
1430 #[inline]
1431 fn local(&self) -> LocalVersion {
1432 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1433 LocalVersion::Max
1434 } else {
1435 LocalVersion::empty()
1436 }
1437 }
1438
1439 #[inline]
1440 fn local_slice(&self) -> LocalVersionSlice<'_> {
1441 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1442 LocalVersionSlice::Max
1443 } else {
1444 LocalVersionSlice::empty()
1445 }
1446 }
1447
1448 #[inline]
1449 fn set_local(&mut self, value: LocalVersion) -> bool {
1450 let suffix_kind = self.suffix_kind();
1451 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1452 return value.is_empty();
1453 }
1454 match value {
1455 LocalVersion::Max => {
1456 self.set_suffix_kind(Self::SUFFIX_LOCAL);
1457 true
1458 }
1459 LocalVersion::Segments(segments) if segments.is_empty() => {
1460 self.set_suffix_kind(Self::SUFFIX_NONE);
1461 true
1462 }
1463 LocalVersion::Segments(_) => false,
1464 }
1465 }
1466
1467 #[inline]
1468 fn suffix_kind(&self) -> u64 {
1469 let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1470 debug_assert!(kind <= Self::SUFFIX_MAX);
1471 kind
1472 }
1473
1474 #[inline]
1475 fn set_suffix_kind(&mut self, kind: u64) {
1476 debug_assert!(kind <= Self::SUFFIX_MAX);
1477 self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1478 self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1479 if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1480 self.set_suffix_version(0);
1481 }
1482 }
1483
1484 #[inline]
1485 fn suffix_version(&self) -> u64 {
1486 self.repr & Self::SUFFIX_VERSION_MASK
1487 }
1488
1489 #[inline]
1490 fn set_suffix_version(&mut self, value: u64) {
1491 debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1492 self.repr &= !Self::SUFFIX_VERSION_MASK;
1493 self.repr |= value;
1494 }
1495}
1496
1497#[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 #[allow(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 Ok(Some(parse_u64(digits)?))
2270 }
2271
2272 fn into_pattern(self) -> VersionPattern {
2280 assert!(
2281 self.release.len() > 0,
2282 "version with no release numbers is invalid"
2283 );
2284 let version = Version::new(self.release.as_slice())
2285 .with_epoch(self.epoch)
2286 .with_pre(self.pre)
2287 .with_post(self.post)
2288 .with_dev(self.dev)
2289 .with_local(LocalVersion::Segments(self.local));
2290 VersionPattern {
2291 version,
2292 wildcard: self.wildcard,
2293 }
2294 }
2295
2296 fn bump_while(&mut self, mut predicate: impl FnMut(u8) -> bool) -> &'a [u8] {
2303 let start = self.i;
2304 while !self.is_done() && predicate(self.byte()) {
2305 self.i = self.i.saturating_add(1);
2306 }
2307 &self.v[start..self.i]
2308 }
2309
2310 fn bump_if(&mut self, string: &str) -> bool {
2315 if self.is_done() {
2316 return false;
2317 }
2318 if starts_with_ignore_ascii_case(string.as_bytes(), &self.v[self.i..]) {
2319 self.i = self
2320 .i
2321 .checked_add(string.len())
2322 .expect("valid offset because of prefix");
2323 true
2324 } else {
2325 false
2326 }
2327 }
2328
2329 fn bump_if_string_set(&mut self, set: &StringSet) -> Option<usize> {
2333 let index = set.starts_with(&self.v[self.i..])?;
2334 let found = &set.strings[index];
2335 self.i = self
2336 .i
2337 .checked_add(found.len())
2338 .expect("valid offset because of prefix");
2339 Some(index)
2340 }
2341
2342 fn bump_if_byte_set(&mut self, set: &ByteSet) -> Option<u8> {
2346 let found = set.starts_with(&self.v[self.i..])?;
2347 self.i = self
2348 .i
2349 .checked_add(1)
2350 .expect("valid offset because of prefix");
2351 Some(found)
2352 }
2353
2354 fn unbump(&mut self) {
2363 self.i = self.i.checked_sub(1).expect("not at beginning of input");
2364 }
2365
2366 fn reset(&mut self, offset: usize) {
2372 assert!(offset <= self.v.len());
2373 self.i = offset;
2374 }
2375
2376 fn byte(&self) -> u8 {
2382 self.v[self.i]
2383 }
2384
2385 fn is_done(&self) -> bool {
2387 self.i >= self.v.len()
2388 }
2389}
2390
2391#[derive(Debug)]
2395enum ReleaseNumbers {
2396 Inline { numbers: [u64; 4], len: usize },
2397 Vec(Vec<u64>),
2398}
2399
2400impl ReleaseNumbers {
2401 fn new() -> Self {
2403 Self::Inline {
2404 numbers: [0; 4],
2405 len: 0,
2406 }
2407 }
2408
2409 fn push(&mut self, n: u64) {
2412 match *self {
2413 Self::Inline {
2414 ref mut numbers,
2415 ref mut len,
2416 } => {
2417 assert!(*len <= 4);
2418 if *len == 4 {
2419 let mut numbers = numbers.to_vec();
2420 numbers.push(n);
2421 *self = Self::Vec(numbers.clone());
2422 } else {
2423 numbers[*len] = n;
2424 *len += 1;
2425 }
2426 }
2427 Self::Vec(ref mut numbers) => {
2428 numbers.push(n);
2429 }
2430 }
2431 }
2432
2433 fn len(&self) -> usize {
2435 self.as_slice().len()
2436 }
2437
2438 fn as_slice(&self) -> &[u64] {
2440 match self {
2441 Self::Inline { numbers, len } => &numbers[..*len],
2442 Self::Vec(vec) => vec,
2443 }
2444 }
2445}
2446
2447struct StringSet {
2452 first_byte: ByteSet,
2456 strings: &'static [&'static str],
2458}
2459
2460impl StringSet {
2461 const fn new(strings: &'static [&'static str]) -> Self {
2467 assert!(
2468 strings.len() <= 20,
2469 "only a small number of strings are supported"
2470 );
2471 let (mut firsts, mut firsts_len) = ([0u8; 20], 0);
2472 let mut i = 0;
2473 while i < strings.len() {
2474 assert!(
2475 !strings[i].is_empty(),
2476 "every string in set should be non-empty",
2477 );
2478 firsts[firsts_len] = strings[i].as_bytes()[0];
2479 firsts_len += 1;
2480 i += 1;
2481 }
2482 let first_byte = ByteSet::new(&firsts);
2483 Self {
2484 first_byte,
2485 strings,
2486 }
2487 }
2488
2489 fn starts_with(&self, haystack: &[u8]) -> Option<usize> {
2492 let first_byte = self.first_byte.starts_with(haystack)?;
2493 for (i, &string) in self.strings.iter().enumerate() {
2494 let bytes = string.as_bytes();
2495 if bytes[0].eq_ignore_ascii_case(&first_byte)
2496 && starts_with_ignore_ascii_case(bytes, haystack)
2497 {
2498 return Some(i);
2499 }
2500 }
2501 None
2502 }
2503}
2504
2505struct ByteSet {
2507 set: [bool; 256],
2508}
2509
2510impl ByteSet {
2511 const fn new(bytes: &[u8]) -> Self {
2513 let mut set = [false; 256];
2514 let mut i = 0;
2515 while i < bytes.len() {
2516 set[bytes[i].to_ascii_uppercase() as usize] = true;
2517 set[bytes[i].to_ascii_lowercase() as usize] = true;
2518 i += 1;
2519 }
2520 Self { set }
2521 }
2522
2523 fn starts_with(&self, haystack: &[u8]) -> Option<u8> {
2526 let byte = *haystack.first()?;
2527 if self.contains(byte) {
2528 Some(byte)
2529 } else {
2530 None
2531 }
2532 }
2533
2534 fn contains(&self, byte: u8) -> bool {
2536 self.set[usize::from(byte)]
2537 }
2538}
2539
2540impl std::fmt::Debug for ByteSet {
2541 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2542 let mut set = f.debug_set();
2543 for byte in 0..=255 {
2544 if self.contains(byte) {
2545 set.entry(&char::from(byte));
2546 }
2547 }
2548 set.finish()
2549 }
2550}
2551
2552#[derive(Clone, Debug, Eq, PartialEq)]
2554pub struct VersionParseError {
2555 kind: Box<ErrorKind>,
2556}
2557
2558impl std::error::Error for VersionParseError {}
2559
2560impl std::fmt::Display for VersionParseError {
2561 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2562 match *self.kind {
2563 ErrorKind::Wildcard => write!(f, "wildcards are not allowed in a version"),
2564 ErrorKind::InvalidDigit { got } if got.is_ascii() => {
2565 write!(f, "expected ASCII digit, but found {:?}", char::from(got))
2566 }
2567 ErrorKind::InvalidDigit { got } => {
2568 write!(
2569 f,
2570 "expected ASCII digit, but found non-ASCII byte \\x{got:02X}"
2571 )
2572 }
2573 ErrorKind::NumberTooBig { ref bytes } => {
2574 let string = match std::str::from_utf8(bytes) {
2575 Ok(v) => v,
2576 Err(err) => {
2577 std::str::from_utf8(&bytes[..err.valid_up_to()]).expect("valid UTF-8")
2578 }
2579 };
2580 write!(
2581 f,
2582 "expected number less than or equal to {}, \
2583 but number found in {string:?} exceeds it",
2584 u64::MAX,
2585 )
2586 }
2587 ErrorKind::NoLeadingNumber => {
2588 write!(
2589 f,
2590 "expected version to start with a number, \
2591 but no leading ASCII digits were found"
2592 )
2593 }
2594 ErrorKind::NoLeadingReleaseNumber => {
2595 write!(
2596 f,
2597 "expected version to have a non-empty release component after an epoch, \
2598 but no ASCII digits after the epoch were found"
2599 )
2600 }
2601 ErrorKind::LocalEmpty { precursor } => {
2602 write!(
2603 f,
2604 "found a `{precursor}` indicating the start of a local \
2605 component in a version, but did not find any alphanumeric \
2606 ASCII segment following the `{precursor}`",
2607 )
2608 }
2609 ErrorKind::UnexpectedEnd {
2610 ref version,
2611 ref remaining,
2612 } => {
2613 write!(
2614 f,
2615 "after parsing `{version}`, found `{remaining}`, \
2616 which is not part of a valid version",
2617 )
2618 }
2619 }
2620 }
2621}
2622
2623#[derive(Clone, Debug, Eq, PartialEq)]
2625pub(crate) enum ErrorKind {
2626 Wildcard,
2629 InvalidDigit {
2631 got: u8,
2633 },
2634 NumberTooBig {
2636 bytes: Vec<u8>,
2639 },
2640 NoLeadingNumber,
2642 NoLeadingReleaseNumber,
2644 LocalEmpty {
2648 precursor: char,
2651 },
2652 UnexpectedEnd {
2655 version: String,
2657 remaining: String,
2659 },
2660}
2661
2662impl From<ErrorKind> for VersionParseError {
2663 fn from(kind: ErrorKind) -> Self {
2664 Self {
2665 kind: Box::new(kind),
2666 }
2667 }
2668}
2669
2670#[derive(Clone, Debug, Eq, PartialEq)]
2672pub struct VersionPatternParseError {
2673 kind: Box<PatternErrorKind>,
2674}
2675
2676impl std::error::Error for VersionPatternParseError {}
2677
2678impl std::fmt::Display for VersionPatternParseError {
2679 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2680 match *self.kind {
2681 PatternErrorKind::Version(ref err) => err.fmt(f),
2682 PatternErrorKind::WildcardNotTrailing => {
2683 write!(f, "wildcards in versions must be at the end")
2684 }
2685 }
2686 }
2687}
2688
2689#[derive(Clone, Debug, Eq, PartialEq)]
2691pub(crate) enum PatternErrorKind {
2692 Version(VersionParseError),
2693 WildcardNotTrailing,
2694}
2695
2696impl From<PatternErrorKind> for VersionPatternParseError {
2697 fn from(kind: PatternErrorKind) -> Self {
2698 Self {
2699 kind: Box::new(kind),
2700 }
2701 }
2702}
2703
2704impl From<ErrorKind> for VersionPatternParseError {
2705 fn from(kind: ErrorKind) -> Self {
2706 Self::from(VersionParseError::from(kind))
2707 }
2708}
2709
2710impl From<VersionParseError> for VersionPatternParseError {
2711 fn from(err: VersionParseError) -> Self {
2712 Self {
2713 kind: Box::new(PatternErrorKind::Version(err)),
2714 }
2715 }
2716}
2717
2718pub(crate) fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2721 if this.len() == other.len() {
2722 return this.cmp(other);
2723 }
2724 for (this, other) in this.iter().chain(std::iter::repeat(&0)).zip(
2727 other
2728 .iter()
2729 .chain(std::iter::repeat(&0))
2730 .take(this.len().max(other.len())),
2731 ) {
2732 match this.cmp(other) {
2733 Ordering::Less => {
2734 return Ordering::Less;
2735 }
2736 Ordering::Equal => {}
2737 Ordering::Greater => {
2738 return Ordering::Greater;
2739 }
2740 }
2741 }
2742 Ordering::Equal
2743}
2744
2745fn sortable_tuple(version: &Version) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2761 let post = if version.max().is_some() {
2763 Some(u64::MAX)
2764 } else {
2765 version.post()
2766 };
2767 match (version.pre(), post, version.dev(), version.min()) {
2768 (_pre, post, _dev, Some(n)) => (0, 0, post, n, version.local()),
2770 (None, None, Some(n), None) => (1, 0, None, n, version.local()),
2772 (
2774 Some(Prerelease {
2775 kind: PrereleaseKind::Alpha,
2776 number: n,
2777 }),
2778 post,
2779 dev,
2780 None,
2781 ) => (2, n, post, dev.unwrap_or(u64::MAX), version.local()),
2782 (
2784 Some(Prerelease {
2785 kind: PrereleaseKind::Beta,
2786 number: n,
2787 }),
2788 post,
2789 dev,
2790 None,
2791 ) => (3, n, post, dev.unwrap_or(u64::MAX), version.local()),
2792 (
2794 Some(Prerelease {
2795 kind: PrereleaseKind::Rc,
2796 number: n,
2797 }),
2798 post,
2799 dev,
2800 None,
2801 ) => (4, n, post, dev.unwrap_or(u64::MAX), version.local()),
2802 (None, None, None, None) => (5, 0, None, 0, version.local()),
2804 (None, Some(post), dev, None) => {
2806 (6, 0, Some(post), dev.unwrap_or(u64::MAX), version.local())
2807 }
2808 }
2809}
2810
2811fn starts_with_ignore_ascii_case(needle: &[u8], haystack: &[u8]) -> bool {
2814 needle.len() <= haystack.len()
2815 && std::iter::zip(needle, haystack).all(|(b1, b2)| b1.eq_ignore_ascii_case(b2))
2816}
2817
2818fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
2833 let mut n: u64 = 0;
2834 for &byte in bytes {
2835 let digit = match byte.checked_sub(b'0') {
2836 None => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2837 Some(digit) if digit > 9 => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2838 Some(digit) => {
2839 debug_assert!((0..=9).contains(&digit));
2840 u64::from(digit)
2841 }
2842 };
2843 n = n
2844 .checked_mul(10)
2845 .and_then(|n| n.checked_add(digit))
2846 .ok_or_else(|| ErrorKind::NumberTooBig {
2847 bytes: bytes.to_vec(),
2848 })?;
2849 }
2850 Ok(n)
2851}
2852
2853pub static MIN_VERSION: LazyLock<Version> =
2855 LazyLock::new(|| Version::from_str("0a0.dev0").unwrap());
2856
2857#[cfg(test)]
2858mod tests {
2859 use std::str::FromStr;
2860
2861 use crate::VersionSpecifier;
2862
2863 use super::*;
2864
2865 #[test]
2867 fn test_packaging_versions() {
2868 let versions = [
2869 ("1.0.dev456", Version::new([1, 0]).with_dev(Some(456))),
2871 (
2872 "1.0a1",
2873 Version::new([1, 0]).with_pre(Some(Prerelease {
2874 kind: PrereleaseKind::Alpha,
2875 number: 1,
2876 })),
2877 ),
2878 (
2879 "1.0a2.dev456",
2880 Version::new([1, 0])
2881 .with_pre(Some(Prerelease {
2882 kind: PrereleaseKind::Alpha,
2883 number: 2,
2884 }))
2885 .with_dev(Some(456)),
2886 ),
2887 (
2888 "1.0a12.dev456",
2889 Version::new([1, 0])
2890 .with_pre(Some(Prerelease {
2891 kind: PrereleaseKind::Alpha,
2892 number: 12,
2893 }))
2894 .with_dev(Some(456)),
2895 ),
2896 (
2897 "1.0a12",
2898 Version::new([1, 0]).with_pre(Some(Prerelease {
2899 kind: PrereleaseKind::Alpha,
2900 number: 12,
2901 })),
2902 ),
2903 (
2904 "1.0b1.dev456",
2905 Version::new([1, 0])
2906 .with_pre(Some(Prerelease {
2907 kind: PrereleaseKind::Beta,
2908 number: 1,
2909 }))
2910 .with_dev(Some(456)),
2911 ),
2912 (
2913 "1.0b2",
2914 Version::new([1, 0]).with_pre(Some(Prerelease {
2915 kind: PrereleaseKind::Beta,
2916 number: 2,
2917 })),
2918 ),
2919 (
2920 "1.0b2.post345.dev456",
2921 Version::new([1, 0])
2922 .with_pre(Some(Prerelease {
2923 kind: PrereleaseKind::Beta,
2924 number: 2,
2925 }))
2926 .with_dev(Some(456))
2927 .with_post(Some(345)),
2928 ),
2929 (
2930 "1.0b2.post345",
2931 Version::new([1, 0])
2932 .with_pre(Some(Prerelease {
2933 kind: PrereleaseKind::Beta,
2934 number: 2,
2935 }))
2936 .with_post(Some(345)),
2937 ),
2938 (
2939 "1.0b2-346",
2940 Version::new([1, 0])
2941 .with_pre(Some(Prerelease {
2942 kind: PrereleaseKind::Beta,
2943 number: 2,
2944 }))
2945 .with_post(Some(346)),
2946 ),
2947 (
2948 "1.0c1.dev456",
2949 Version::new([1, 0])
2950 .with_pre(Some(Prerelease {
2951 kind: PrereleaseKind::Rc,
2952 number: 1,
2953 }))
2954 .with_dev(Some(456)),
2955 ),
2956 (
2957 "1.0c1",
2958 Version::new([1, 0]).with_pre(Some(Prerelease {
2959 kind: PrereleaseKind::Rc,
2960 number: 1,
2961 })),
2962 ),
2963 (
2964 "1.0rc2",
2965 Version::new([1, 0]).with_pre(Some(Prerelease {
2966 kind: PrereleaseKind::Rc,
2967 number: 2,
2968 })),
2969 ),
2970 (
2971 "1.0c3",
2972 Version::new([1, 0]).with_pre(Some(Prerelease {
2973 kind: PrereleaseKind::Rc,
2974 number: 3,
2975 })),
2976 ),
2977 ("1.0", Version::new([1, 0])),
2978 (
2979 "1.0.post456.dev34",
2980 Version::new([1, 0]).with_post(Some(456)).with_dev(Some(34)),
2981 ),
2982 ("1.0.post456", Version::new([1, 0]).with_post(Some(456))),
2983 ("1.1.dev1", Version::new([1, 1]).with_dev(Some(1))),
2984 (
2985 "1.2+123abc",
2986 Version::new([1, 2])
2987 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
2988 ),
2989 (
2990 "1.2+123abc456",
2991 Version::new([1, 2])
2992 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
2993 ),
2994 (
2995 "1.2+abc",
2996 Version::new([1, 2])
2997 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
2998 ),
2999 (
3000 "1.2+abc123",
3001 Version::new([1, 2])
3002 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3003 ),
3004 (
3005 "1.2+abc123def",
3006 Version::new([1, 2])
3007 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3008 ),
3009 (
3010 "1.2+1234.abc",
3011 Version::new([1, 2]).with_local_segments(vec![
3012 LocalSegment::Number(1234),
3013 LocalSegment::String("abc".to_string()),
3014 ]),
3015 ),
3016 (
3017 "1.2+123456",
3018 Version::new([1, 2]).with_local_segments(vec![LocalSegment::Number(123_456)]),
3019 ),
3020 (
3021 "1.2.r32+123456",
3022 Version::new([1, 2])
3023 .with_post(Some(32))
3024 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3025 ),
3026 (
3027 "1.2.rev33+123456",
3028 Version::new([1, 2])
3029 .with_post(Some(33))
3030 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3031 ),
3032 (
3034 "1!1.0.dev456",
3035 Version::new([1, 0]).with_epoch(1).with_dev(Some(456)),
3036 ),
3037 (
3038 "1!1.0a1",
3039 Version::new([1, 0])
3040 .with_epoch(1)
3041 .with_pre(Some(Prerelease {
3042 kind: PrereleaseKind::Alpha,
3043 number: 1,
3044 })),
3045 ),
3046 (
3047 "1!1.0a2.dev456",
3048 Version::new([1, 0])
3049 .with_epoch(1)
3050 .with_pre(Some(Prerelease {
3051 kind: PrereleaseKind::Alpha,
3052 number: 2,
3053 }))
3054 .with_dev(Some(456)),
3055 ),
3056 (
3057 "1!1.0a12.dev456",
3058 Version::new([1, 0])
3059 .with_epoch(1)
3060 .with_pre(Some(Prerelease {
3061 kind: PrereleaseKind::Alpha,
3062 number: 12,
3063 }))
3064 .with_dev(Some(456)),
3065 ),
3066 (
3067 "1!1.0a12",
3068 Version::new([1, 0])
3069 .with_epoch(1)
3070 .with_pre(Some(Prerelease {
3071 kind: PrereleaseKind::Alpha,
3072 number: 12,
3073 })),
3074 ),
3075 (
3076 "1!1.0b1.dev456",
3077 Version::new([1, 0])
3078 .with_epoch(1)
3079 .with_pre(Some(Prerelease {
3080 kind: PrereleaseKind::Beta,
3081 number: 1,
3082 }))
3083 .with_dev(Some(456)),
3084 ),
3085 (
3086 "1!1.0b2",
3087 Version::new([1, 0])
3088 .with_epoch(1)
3089 .with_pre(Some(Prerelease {
3090 kind: PrereleaseKind::Beta,
3091 number: 2,
3092 })),
3093 ),
3094 (
3095 "1!1.0b2.post345.dev456",
3096 Version::new([1, 0])
3097 .with_epoch(1)
3098 .with_pre(Some(Prerelease {
3099 kind: PrereleaseKind::Beta,
3100 number: 2,
3101 }))
3102 .with_post(Some(345))
3103 .with_dev(Some(456)),
3104 ),
3105 (
3106 "1!1.0b2.post345",
3107 Version::new([1, 0])
3108 .with_epoch(1)
3109 .with_pre(Some(Prerelease {
3110 kind: PrereleaseKind::Beta,
3111 number: 2,
3112 }))
3113 .with_post(Some(345)),
3114 ),
3115 (
3116 "1!1.0b2-346",
3117 Version::new([1, 0])
3118 .with_epoch(1)
3119 .with_pre(Some(Prerelease {
3120 kind: PrereleaseKind::Beta,
3121 number: 2,
3122 }))
3123 .with_post(Some(346)),
3124 ),
3125 (
3126 "1!1.0c1.dev456",
3127 Version::new([1, 0])
3128 .with_epoch(1)
3129 .with_pre(Some(Prerelease {
3130 kind: PrereleaseKind::Rc,
3131 number: 1,
3132 }))
3133 .with_dev(Some(456)),
3134 ),
3135 (
3136 "1!1.0c1",
3137 Version::new([1, 0])
3138 .with_epoch(1)
3139 .with_pre(Some(Prerelease {
3140 kind: PrereleaseKind::Rc,
3141 number: 1,
3142 })),
3143 ),
3144 (
3145 "1!1.0rc2",
3146 Version::new([1, 0])
3147 .with_epoch(1)
3148 .with_pre(Some(Prerelease {
3149 kind: PrereleaseKind::Rc,
3150 number: 2,
3151 })),
3152 ),
3153 (
3154 "1!1.0c3",
3155 Version::new([1, 0])
3156 .with_epoch(1)
3157 .with_pre(Some(Prerelease {
3158 kind: PrereleaseKind::Rc,
3159 number: 3,
3160 })),
3161 ),
3162 ("1!1.0", Version::new([1, 0]).with_epoch(1)),
3163 (
3164 "1!1.0.post456.dev34",
3165 Version::new([1, 0])
3166 .with_epoch(1)
3167 .with_post(Some(456))
3168 .with_dev(Some(34)),
3169 ),
3170 (
3171 "1!1.0.post456",
3172 Version::new([1, 0]).with_epoch(1).with_post(Some(456)),
3173 ),
3174 (
3175 "1!1.1.dev1",
3176 Version::new([1, 1]).with_epoch(1).with_dev(Some(1)),
3177 ),
3178 (
3179 "1!1.2+123abc",
3180 Version::new([1, 2])
3181 .with_epoch(1)
3182 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3183 ),
3184 (
3185 "1!1.2+123abc456",
3186 Version::new([1, 2])
3187 .with_epoch(1)
3188 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3189 ),
3190 (
3191 "1!1.2+abc",
3192 Version::new([1, 2])
3193 .with_epoch(1)
3194 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3195 ),
3196 (
3197 "1!1.2+abc123",
3198 Version::new([1, 2])
3199 .with_epoch(1)
3200 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3201 ),
3202 (
3203 "1!1.2+abc123def",
3204 Version::new([1, 2])
3205 .with_epoch(1)
3206 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3207 ),
3208 (
3209 "1!1.2+1234.abc",
3210 Version::new([1, 2]).with_epoch(1).with_local_segments(vec![
3211 LocalSegment::Number(1234),
3212 LocalSegment::String("abc".to_string()),
3213 ]),
3214 ),
3215 (
3216 "1!1.2+123456",
3217 Version::new([1, 2])
3218 .with_epoch(1)
3219 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3220 ),
3221 (
3222 "1!1.2.r32+123456",
3223 Version::new([1, 2])
3224 .with_epoch(1)
3225 .with_post(Some(32))
3226 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3227 ),
3228 (
3229 "1!1.2.rev33+123456",
3230 Version::new([1, 2])
3231 .with_epoch(1)
3232 .with_post(Some(33))
3233 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3234 ),
3235 (
3236 "98765!1.2.rev33+123456",
3237 Version::new([1, 2])
3238 .with_epoch(98765)
3239 .with_post(Some(33))
3240 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3241 ),
3242 ];
3243 for (string, structured) in versions {
3244 match Version::from_str(string) {
3245 Err(err) => {
3246 unreachable!(
3247 "expected {string:?} to parse as {structured:?}, but got {err:?}",
3248 structured = structured.as_bloated_debug(),
3249 )
3250 }
3251 Ok(v) => assert!(
3252 v == structured,
3253 "for {string:?}, expected {structured:?} but got {v:?}",
3254 structured = structured.as_bloated_debug(),
3255 v = v.as_bloated_debug(),
3256 ),
3257 }
3258 let spec = format!("=={string}");
3259 match VersionSpecifier::from_str(&spec) {
3260 Err(err) => {
3261 unreachable!(
3262 "expected version in {spec:?} to parse as {structured:?}, but got {err:?}",
3263 structured = structured.as_bloated_debug(),
3264 )
3265 }
3266 Ok(v) => assert!(
3267 v.version() == &structured,
3268 "for {string:?}, expected {structured:?} but got {v:?}",
3269 structured = structured.as_bloated_debug(),
3270 v = v.version.as_bloated_debug(),
3271 ),
3272 }
3273 }
3274 }
3275
3276 #[test]
3278 fn test_packaging_failures() {
3279 let versions = [
3280 "1.0+a+",
3282 "1.0++",
3283 "1.0+_foobar",
3284 "1.0+foo&asd",
3285 "1.0+1+1",
3286 "french toast",
3288 "==french toast",
3289 ];
3290 for version in versions {
3291 assert!(Version::from_str(version).is_err());
3292 assert!(VersionSpecifier::from_str(&format!("=={version}")).is_err());
3293 }
3294 }
3295
3296 #[test]
3297 fn test_equality_and_normalization() {
3298 let versions = [
3299 ("1.0dev", "1.0.dev0"),
3301 ("1.0.dev", "1.0.dev0"),
3302 ("1.0dev1", "1.0.dev1"),
3303 ("1.0dev", "1.0.dev0"),
3304 ("1.0-dev", "1.0.dev0"),
3305 ("1.0-dev1", "1.0.dev1"),
3306 ("1.0DEV", "1.0.dev0"),
3307 ("1.0.DEV", "1.0.dev0"),
3308 ("1.0DEV1", "1.0.dev1"),
3309 ("1.0DEV", "1.0.dev0"),
3310 ("1.0.DEV1", "1.0.dev1"),
3311 ("1.0-DEV", "1.0.dev0"),
3312 ("1.0-DEV1", "1.0.dev1"),
3313 ("1.0a", "1.0a0"),
3315 ("1.0.a", "1.0a0"),
3316 ("1.0.a1", "1.0a1"),
3317 ("1.0-a", "1.0a0"),
3318 ("1.0-a1", "1.0a1"),
3319 ("1.0alpha", "1.0a0"),
3320 ("1.0.alpha", "1.0a0"),
3321 ("1.0.alpha1", "1.0a1"),
3322 ("1.0-alpha", "1.0a0"),
3323 ("1.0-alpha1", "1.0a1"),
3324 ("1.0A", "1.0a0"),
3325 ("1.0.A", "1.0a0"),
3326 ("1.0.A1", "1.0a1"),
3327 ("1.0-A", "1.0a0"),
3328 ("1.0-A1", "1.0a1"),
3329 ("1.0ALPHA", "1.0a0"),
3330 ("1.0.ALPHA", "1.0a0"),
3331 ("1.0.ALPHA1", "1.0a1"),
3332 ("1.0-ALPHA", "1.0a0"),
3333 ("1.0-ALPHA1", "1.0a1"),
3334 ("1.0b", "1.0b0"),
3336 ("1.0.b", "1.0b0"),
3337 ("1.0.b1", "1.0b1"),
3338 ("1.0-b", "1.0b0"),
3339 ("1.0-b1", "1.0b1"),
3340 ("1.0beta", "1.0b0"),
3341 ("1.0.beta", "1.0b0"),
3342 ("1.0.beta1", "1.0b1"),
3343 ("1.0-beta", "1.0b0"),
3344 ("1.0-beta1", "1.0b1"),
3345 ("1.0B", "1.0b0"),
3346 ("1.0.B", "1.0b0"),
3347 ("1.0.B1", "1.0b1"),
3348 ("1.0-B", "1.0b0"),
3349 ("1.0-B1", "1.0b1"),
3350 ("1.0BETA", "1.0b0"),
3351 ("1.0.BETA", "1.0b0"),
3352 ("1.0.BETA1", "1.0b1"),
3353 ("1.0-BETA", "1.0b0"),
3354 ("1.0-BETA1", "1.0b1"),
3355 ("1.0c", "1.0rc0"),
3357 ("1.0.c", "1.0rc0"),
3358 ("1.0.c1", "1.0rc1"),
3359 ("1.0-c", "1.0rc0"),
3360 ("1.0-c1", "1.0rc1"),
3361 ("1.0rc", "1.0rc0"),
3362 ("1.0.rc", "1.0rc0"),
3363 ("1.0.rc1", "1.0rc1"),
3364 ("1.0-rc", "1.0rc0"),
3365 ("1.0-rc1", "1.0rc1"),
3366 ("1.0C", "1.0rc0"),
3367 ("1.0.C", "1.0rc0"),
3368 ("1.0.C1", "1.0rc1"),
3369 ("1.0-C", "1.0rc0"),
3370 ("1.0-C1", "1.0rc1"),
3371 ("1.0RC", "1.0rc0"),
3372 ("1.0.RC", "1.0rc0"),
3373 ("1.0.RC1", "1.0rc1"),
3374 ("1.0-RC", "1.0rc0"),
3375 ("1.0-RC1", "1.0rc1"),
3376 ("1.0post", "1.0.post0"),
3378 ("1.0.post", "1.0.post0"),
3379 ("1.0post1", "1.0.post1"),
3380 ("1.0post", "1.0.post0"),
3381 ("1.0-post", "1.0.post0"),
3382 ("1.0-post1", "1.0.post1"),
3383 ("1.0POST", "1.0.post0"),
3384 ("1.0.POST", "1.0.post0"),
3385 ("1.0POST1", "1.0.post1"),
3386 ("1.0POST", "1.0.post0"),
3387 ("1.0r", "1.0.post0"),
3388 ("1.0rev", "1.0.post0"),
3389 ("1.0.POST1", "1.0.post1"),
3390 ("1.0.r1", "1.0.post1"),
3391 ("1.0.rev1", "1.0.post1"),
3392 ("1.0-POST", "1.0.post0"),
3393 ("1.0-POST1", "1.0.post1"),
3394 ("1.0-5", "1.0.post5"),
3395 ("1.0-r5", "1.0.post5"),
3396 ("1.0-rev5", "1.0.post5"),
3397 ("1.0+AbC", "1.0+abc"),
3399 ("1.01", "1.1"),
3401 ("1.0a05", "1.0a5"),
3402 ("1.0b07", "1.0b7"),
3403 ("1.0c056", "1.0rc56"),
3404 ("1.0rc09", "1.0rc9"),
3405 ("1.0.post000", "1.0.post0"),
3406 ("1.1.dev09000", "1.1.dev9000"),
3407 ("00!1.2", "1.2"),
3408 ("0100!0.0", "100!0.0"),
3409 ("v1.0", "1.0"),
3411 (" v1.0\t\n", "1.0"),
3412 ];
3413 for (version_str, normalized_str) in versions {
3414 let version = Version::from_str(version_str).unwrap();
3415 let normalized = Version::from_str(normalized_str).unwrap();
3416 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3418 assert_eq!(
3420 version.to_string(),
3421 normalized.to_string(),
3422 "{version_str} {normalized_str}"
3423 );
3424 }
3425 }
3426
3427 #[test]
3429 fn test_equality_and_normalization2() {
3430 let versions = [
3431 ("1.0.dev456", "1.0.dev456"),
3432 ("1.0a1", "1.0a1"),
3433 ("1.0a2.dev456", "1.0a2.dev456"),
3434 ("1.0a12.dev456", "1.0a12.dev456"),
3435 ("1.0a12", "1.0a12"),
3436 ("1.0b1.dev456", "1.0b1.dev456"),
3437 ("1.0b2", "1.0b2"),
3438 ("1.0b2.post345.dev456", "1.0b2.post345.dev456"),
3439 ("1.0b2.post345", "1.0b2.post345"),
3440 ("1.0rc1.dev456", "1.0rc1.dev456"),
3441 ("1.0rc1", "1.0rc1"),
3442 ("1.0", "1.0"),
3443 ("1.0.post456.dev34", "1.0.post456.dev34"),
3444 ("1.0.post456", "1.0.post456"),
3445 ("1.0.1", "1.0.1"),
3446 ("0!1.0.2", "1.0.2"),
3447 ("1.0.3+7", "1.0.3+7"),
3448 ("0!1.0.4+8.0", "1.0.4+8.0"),
3449 ("1.0.5+9.5", "1.0.5+9.5"),
3450 ("1.2+1234.abc", "1.2+1234.abc"),
3451 ("1.2+123456", "1.2+123456"),
3452 ("1.2+123abc", "1.2+123abc"),
3453 ("1.2+123abc456", "1.2+123abc456"),
3454 ("1.2+abc", "1.2+abc"),
3455 ("1.2+abc123", "1.2+abc123"),
3456 ("1.2+abc123def", "1.2+abc123def"),
3457 ("1.1.dev1", "1.1.dev1"),
3458 ("7!1.0.dev456", "7!1.0.dev456"),
3459 ("7!1.0a1", "7!1.0a1"),
3460 ("7!1.0a2.dev456", "7!1.0a2.dev456"),
3461 ("7!1.0a12.dev456", "7!1.0a12.dev456"),
3462 ("7!1.0a12", "7!1.0a12"),
3463 ("7!1.0b1.dev456", "7!1.0b1.dev456"),
3464 ("7!1.0b2", "7!1.0b2"),
3465 ("7!1.0b2.post345.dev456", "7!1.0b2.post345.dev456"),
3466 ("7!1.0b2.post345", "7!1.0b2.post345"),
3467 ("7!1.0rc1.dev456", "7!1.0rc1.dev456"),
3468 ("7!1.0rc1", "7!1.0rc1"),
3469 ("7!1.0", "7!1.0"),
3470 ("7!1.0.post456.dev34", "7!1.0.post456.dev34"),
3471 ("7!1.0.post456", "7!1.0.post456"),
3472 ("7!1.0.1", "7!1.0.1"),
3473 ("7!1.0.2", "7!1.0.2"),
3474 ("7!1.0.3+7", "7!1.0.3+7"),
3475 ("7!1.0.4+8.0", "7!1.0.4+8.0"),
3476 ("7!1.0.5+9.5", "7!1.0.5+9.5"),
3477 ("7!1.1.dev1", "7!1.1.dev1"),
3478 ];
3479 for (version_str, normalized_str) in versions {
3480 let version = Version::from_str(version_str).unwrap();
3481 let normalized = Version::from_str(normalized_str).unwrap();
3482 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3483 assert_eq!(
3485 version.to_string(),
3486 normalized_str,
3487 "{version_str} {normalized_str}"
3488 );
3489 assert_eq!(
3491 version.to_string(),
3492 normalized.to_string(),
3493 "{version_str} {normalized_str}"
3494 );
3495 }
3496 }
3497
3498 #[test]
3499 fn test_star_fixed_version() {
3500 let result = Version::from_str("0.9.1.*");
3501 assert_eq!(result.unwrap_err(), ErrorKind::Wildcard.into());
3502 }
3503
3504 #[test]
3505 fn test_invalid_word() {
3506 let result = Version::from_str("blergh");
3507 assert_eq!(result.unwrap_err(), ErrorKind::NoLeadingNumber.into());
3508 }
3509
3510 #[test]
3511 fn test_from_version_star() {
3512 let p = |s: &str| -> Result<VersionPattern, _> { s.parse() };
3513 assert!(!p("1.2.3").unwrap().is_wildcard());
3514 assert!(p("1.2.3.*").unwrap().is_wildcard());
3515 assert_eq!(
3516 p("1.2.*.4.*").unwrap_err(),
3517 PatternErrorKind::WildcardNotTrailing.into(),
3518 );
3519 assert_eq!(
3520 p("1.0-dev1.*").unwrap_err(),
3521 ErrorKind::UnexpectedEnd {
3522 version: "1.0-dev1".to_string(),
3523 remaining: ".*".to_string()
3524 }
3525 .into(),
3526 );
3527 assert_eq!(
3528 p("1.0a1.*").unwrap_err(),
3529 ErrorKind::UnexpectedEnd {
3530 version: "1.0a1".to_string(),
3531 remaining: ".*".to_string()
3532 }
3533 .into(),
3534 );
3535 assert_eq!(
3536 p("1.0.post1.*").unwrap_err(),
3537 ErrorKind::UnexpectedEnd {
3538 version: "1.0.post1".to_string(),
3539 remaining: ".*".to_string()
3540 }
3541 .into(),
3542 );
3543 assert_eq!(
3544 p("1.0+lolwat.*").unwrap_err(),
3545 ErrorKind::LocalEmpty { precursor: '.' }.into(),
3546 );
3547 }
3548
3549 #[test]
3555 fn parse_version_valid() {
3556 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3557 Ok(v) => v,
3558 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3559 };
3560
3561 assert_eq!(p("5"), Version::new([5]));
3563 assert_eq!(p("5.6"), Version::new([5, 6]));
3564 assert_eq!(p("5.6.7"), Version::new([5, 6, 7]));
3565 assert_eq!(p("512.623.734"), Version::new([512, 623, 734]));
3566 assert_eq!(p("1.2.3.4"), Version::new([1, 2, 3, 4]));
3567 assert_eq!(p("1.2.3.4.5"), Version::new([1, 2, 3, 4, 5]));
3568
3569 assert_eq!(p("4!5"), Version::new([5]).with_epoch(4));
3571 assert_eq!(p("4!5.6"), Version::new([5, 6]).with_epoch(4));
3572
3573 assert_eq!(
3575 p("5a1"),
3576 Version::new([5]).with_pre(Some(Prerelease {
3577 kind: PrereleaseKind::Alpha,
3578 number: 1
3579 }))
3580 );
3581 assert_eq!(
3582 p("5alpha1"),
3583 Version::new([5]).with_pre(Some(Prerelease {
3584 kind: PrereleaseKind::Alpha,
3585 number: 1
3586 }))
3587 );
3588 assert_eq!(
3589 p("5b1"),
3590 Version::new([5]).with_pre(Some(Prerelease {
3591 kind: PrereleaseKind::Beta,
3592 number: 1
3593 }))
3594 );
3595 assert_eq!(
3596 p("5beta1"),
3597 Version::new([5]).with_pre(Some(Prerelease {
3598 kind: PrereleaseKind::Beta,
3599 number: 1
3600 }))
3601 );
3602 assert_eq!(
3603 p("5rc1"),
3604 Version::new([5]).with_pre(Some(Prerelease {
3605 kind: PrereleaseKind::Rc,
3606 number: 1
3607 }))
3608 );
3609 assert_eq!(
3610 p("5c1"),
3611 Version::new([5]).with_pre(Some(Prerelease {
3612 kind: PrereleaseKind::Rc,
3613 number: 1
3614 }))
3615 );
3616 assert_eq!(
3617 p("5preview1"),
3618 Version::new([5]).with_pre(Some(Prerelease {
3619 kind: PrereleaseKind::Rc,
3620 number: 1
3621 }))
3622 );
3623 assert_eq!(
3624 p("5pre1"),
3625 Version::new([5]).with_pre(Some(Prerelease {
3626 kind: PrereleaseKind::Rc,
3627 number: 1
3628 }))
3629 );
3630 assert_eq!(
3631 p("5.6.7pre1"),
3632 Version::new([5, 6, 7]).with_pre(Some(Prerelease {
3633 kind: PrereleaseKind::Rc,
3634 number: 1
3635 }))
3636 );
3637 assert_eq!(
3638 p("5alpha789"),
3639 Version::new([5]).with_pre(Some(Prerelease {
3640 kind: PrereleaseKind::Alpha,
3641 number: 789
3642 }))
3643 );
3644 assert_eq!(
3645 p("5.alpha789"),
3646 Version::new([5]).with_pre(Some(Prerelease {
3647 kind: PrereleaseKind::Alpha,
3648 number: 789
3649 }))
3650 );
3651 assert_eq!(
3652 p("5-alpha789"),
3653 Version::new([5]).with_pre(Some(Prerelease {
3654 kind: PrereleaseKind::Alpha,
3655 number: 789
3656 }))
3657 );
3658 assert_eq!(
3659 p("5_alpha789"),
3660 Version::new([5]).with_pre(Some(Prerelease {
3661 kind: PrereleaseKind::Alpha,
3662 number: 789
3663 }))
3664 );
3665 assert_eq!(
3666 p("5alpha.789"),
3667 Version::new([5]).with_pre(Some(Prerelease {
3668 kind: PrereleaseKind::Alpha,
3669 number: 789
3670 }))
3671 );
3672 assert_eq!(
3673 p("5alpha-789"),
3674 Version::new([5]).with_pre(Some(Prerelease {
3675 kind: PrereleaseKind::Alpha,
3676 number: 789
3677 }))
3678 );
3679 assert_eq!(
3680 p("5alpha_789"),
3681 Version::new([5]).with_pre(Some(Prerelease {
3682 kind: PrereleaseKind::Alpha,
3683 number: 789
3684 }))
3685 );
3686 assert_eq!(
3687 p("5ALPHA789"),
3688 Version::new([5]).with_pre(Some(Prerelease {
3689 kind: PrereleaseKind::Alpha,
3690 number: 789
3691 }))
3692 );
3693 assert_eq!(
3694 p("5aLpHa789"),
3695 Version::new([5]).with_pre(Some(Prerelease {
3696 kind: PrereleaseKind::Alpha,
3697 number: 789
3698 }))
3699 );
3700 assert_eq!(
3701 p("5alpha"),
3702 Version::new([5]).with_pre(Some(Prerelease {
3703 kind: PrereleaseKind::Alpha,
3704 number: 0
3705 }))
3706 );
3707
3708 assert_eq!(p("5post2"), Version::new([5]).with_post(Some(2)));
3710 assert_eq!(p("5rev2"), Version::new([5]).with_post(Some(2)));
3711 assert_eq!(p("5r2"), Version::new([5]).with_post(Some(2)));
3712 assert_eq!(p("5.post2"), Version::new([5]).with_post(Some(2)));
3713 assert_eq!(p("5-post2"), Version::new([5]).with_post(Some(2)));
3714 assert_eq!(p("5_post2"), Version::new([5]).with_post(Some(2)));
3715 assert_eq!(p("5.post.2"), Version::new([5]).with_post(Some(2)));
3716 assert_eq!(p("5.post-2"), Version::new([5]).with_post(Some(2)));
3717 assert_eq!(p("5.post_2"), Version::new([5]).with_post(Some(2)));
3718 assert_eq!(
3719 p("5.6.7.post_2"),
3720 Version::new([5, 6, 7]).with_post(Some(2))
3721 );
3722 assert_eq!(p("5-2"), Version::new([5]).with_post(Some(2)));
3723 assert_eq!(p("5.6.7-2"), Version::new([5, 6, 7]).with_post(Some(2)));
3724 assert_eq!(p("5POST2"), Version::new([5]).with_post(Some(2)));
3725 assert_eq!(p("5PoSt2"), Version::new([5]).with_post(Some(2)));
3726 assert_eq!(p("5post"), Version::new([5]).with_post(Some(0)));
3727
3728 assert_eq!(p("5dev2"), Version::new([5]).with_dev(Some(2)));
3730 assert_eq!(p("5.dev2"), Version::new([5]).with_dev(Some(2)));
3731 assert_eq!(p("5-dev2"), Version::new([5]).with_dev(Some(2)));
3732 assert_eq!(p("5_dev2"), Version::new([5]).with_dev(Some(2)));
3733 assert_eq!(p("5.dev.2"), Version::new([5]).with_dev(Some(2)));
3734 assert_eq!(p("5.dev-2"), Version::new([5]).with_dev(Some(2)));
3735 assert_eq!(p("5.dev_2"), Version::new([5]).with_dev(Some(2)));
3736 assert_eq!(p("5.6.7.dev_2"), Version::new([5, 6, 7]).with_dev(Some(2)));
3737 assert_eq!(p("5DEV2"), Version::new([5]).with_dev(Some(2)));
3738 assert_eq!(p("5dEv2"), Version::new([5]).with_dev(Some(2)));
3739 assert_eq!(p("5DeV2"), Version::new([5]).with_dev(Some(2)));
3740 assert_eq!(p("5dev"), Version::new([5]).with_dev(Some(0)));
3741
3742 assert_eq!(
3744 p("5+2"),
3745 Version::new([5]).with_local_segments(vec![LocalSegment::Number(2)])
3746 );
3747 assert_eq!(
3748 p("5+a"),
3749 Version::new([5]).with_local_segments(vec![LocalSegment::String("a".to_string())])
3750 );
3751 assert_eq!(
3752 p("5+abc.123"),
3753 Version::new([5]).with_local_segments(vec![
3754 LocalSegment::String("abc".to_string()),
3755 LocalSegment::Number(123),
3756 ])
3757 );
3758 assert_eq!(
3759 p("5+123.abc"),
3760 Version::new([5]).with_local_segments(vec![
3761 LocalSegment::Number(123),
3762 LocalSegment::String("abc".to_string()),
3763 ])
3764 );
3765 assert_eq!(
3766 p("5+18446744073709551615.abc"),
3767 Version::new([5]).with_local_segments(vec![
3768 LocalSegment::Number(18_446_744_073_709_551_615),
3769 LocalSegment::String("abc".to_string()),
3770 ])
3771 );
3772 assert_eq!(
3773 p("5+18446744073709551616.abc"),
3774 Version::new([5]).with_local_segments(vec![
3775 LocalSegment::String("18446744073709551616".to_string()),
3776 LocalSegment::String("abc".to_string()),
3777 ])
3778 );
3779 assert_eq!(
3780 p("5+ABC.123"),
3781 Version::new([5]).with_local_segments(vec![
3782 LocalSegment::String("abc".to_string()),
3783 LocalSegment::Number(123),
3784 ])
3785 );
3786 assert_eq!(
3787 p("5+ABC-123.4_5_xyz-MNO"),
3788 Version::new([5]).with_local_segments(vec![
3789 LocalSegment::String("abc".to_string()),
3790 LocalSegment::Number(123),
3791 LocalSegment::Number(4),
3792 LocalSegment::Number(5),
3793 LocalSegment::String("xyz".to_string()),
3794 LocalSegment::String("mno".to_string()),
3795 ])
3796 );
3797 assert_eq!(
3798 p("5.6.7+abc-00123"),
3799 Version::new([5, 6, 7]).with_local_segments(vec![
3800 LocalSegment::String("abc".to_string()),
3801 LocalSegment::Number(123),
3802 ])
3803 );
3804 assert_eq!(
3805 p("5.6.7+abc-foo00123"),
3806 Version::new([5, 6, 7]).with_local_segments(vec![
3807 LocalSegment::String("abc".to_string()),
3808 LocalSegment::String("foo00123".to_string()),
3809 ])
3810 );
3811 assert_eq!(
3812 p("5.6.7+abc-00123a"),
3813 Version::new([5, 6, 7]).with_local_segments(vec![
3814 LocalSegment::String("abc".to_string()),
3815 LocalSegment::String("00123a".to_string()),
3816 ])
3817 );
3818
3819 assert_eq!(
3821 p("5a2post3"),
3822 Version::new([5])
3823 .with_pre(Some(Prerelease {
3824 kind: PrereleaseKind::Alpha,
3825 number: 2
3826 }))
3827 .with_post(Some(3))
3828 );
3829 assert_eq!(
3830 p("5.a-2_post-3"),
3831 Version::new([5])
3832 .with_pre(Some(Prerelease {
3833 kind: PrereleaseKind::Alpha,
3834 number: 2
3835 }))
3836 .with_post(Some(3))
3837 );
3838 assert_eq!(
3839 p("5a2-3"),
3840 Version::new([5])
3841 .with_pre(Some(Prerelease {
3842 kind: PrereleaseKind::Alpha,
3843 number: 2
3844 }))
3845 .with_post(Some(3))
3846 );
3847
3848 assert_eq!(p("v5"), Version::new([5]));
3850 assert_eq!(p("V5"), Version::new([5]));
3851 assert_eq!(p("v5.6.7"), Version::new([5, 6, 7]));
3852
3853 assert_eq!(p(" v5 "), Version::new([5]));
3855 assert_eq!(p(" 5 "), Version::new([5]));
3856 assert_eq!(
3857 p(" 5.6.7+abc.123.xyz "),
3858 Version::new([5, 6, 7]).with_local_segments(vec![
3859 LocalSegment::String("abc".to_string()),
3860 LocalSegment::Number(123),
3861 LocalSegment::String("xyz".to_string())
3862 ])
3863 );
3864 assert_eq!(p(" \n5\n \t"), Version::new([5]));
3865
3866 assert!(Parser::new("1.min0".as_bytes()).parse().is_err());
3868 }
3869
3870 #[test]
3878 fn parse_version_invalid() {
3879 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3880 Err(err) => err,
3881 Ok(v) => unreachable!(
3882 "expected version parser error, but got: {v:?}",
3883 v = v.as_bloated_debug()
3884 ),
3885 };
3886
3887 assert_eq!(p(""), ErrorKind::NoLeadingNumber.into());
3888 assert_eq!(p("a"), ErrorKind::NoLeadingNumber.into());
3889 assert_eq!(p("v 5"), ErrorKind::NoLeadingNumber.into());
3890 assert_eq!(p("V 5"), ErrorKind::NoLeadingNumber.into());
3891 assert_eq!(p("x 5"), ErrorKind::NoLeadingNumber.into());
3892 assert_eq!(
3893 p("18446744073709551616"),
3894 ErrorKind::NumberTooBig {
3895 bytes: b"18446744073709551616".to_vec()
3896 }
3897 .into()
3898 );
3899 assert_eq!(p("5!"), ErrorKind::NoLeadingReleaseNumber.into());
3900 assert_eq!(
3901 p("5.6./"),
3902 ErrorKind::UnexpectedEnd {
3903 version: "5.6".to_string(),
3904 remaining: "./".to_string()
3905 }
3906 .into()
3907 );
3908 assert_eq!(
3909 p("5.6.-alpha2"),
3910 ErrorKind::UnexpectedEnd {
3911 version: "5.6".to_string(),
3912 remaining: ".-alpha2".to_string()
3913 }
3914 .into()
3915 );
3916 assert_eq!(
3917 p("1.2.3a18446744073709551616"),
3918 ErrorKind::NumberTooBig {
3919 bytes: b"18446744073709551616".to_vec()
3920 }
3921 .into()
3922 );
3923 assert_eq!(p("5+"), ErrorKind::LocalEmpty { precursor: '+' }.into());
3924 assert_eq!(p("5+ "), ErrorKind::LocalEmpty { precursor: '+' }.into());
3925 assert_eq!(p("5+abc."), ErrorKind::LocalEmpty { precursor: '.' }.into());
3926 assert_eq!(p("5+abc-"), ErrorKind::LocalEmpty { precursor: '-' }.into());
3927 assert_eq!(p("5+abc_"), ErrorKind::LocalEmpty { precursor: '_' }.into());
3928 assert_eq!(
3929 p("5+abc. "),
3930 ErrorKind::LocalEmpty { precursor: '.' }.into()
3931 );
3932 assert_eq!(
3933 p("5.6-"),
3934 ErrorKind::UnexpectedEnd {
3935 version: "5.6".to_string(),
3936 remaining: "-".to_string()
3937 }
3938 .into()
3939 );
3940 }
3941
3942 #[test]
3943 fn parse_version_pattern_valid() {
3944 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3945 Ok(v) => v,
3946 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3947 };
3948
3949 assert_eq!(p("5.*"), VersionPattern::wildcard(Version::new([5])));
3950 assert_eq!(p("5.6.*"), VersionPattern::wildcard(Version::new([5, 6])));
3951 assert_eq!(
3952 p("2!5.6.*"),
3953 VersionPattern::wildcard(Version::new([5, 6]).with_epoch(2))
3954 );
3955 }
3956
3957 #[test]
3958 fn parse_version_pattern_invalid() {
3959 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
3960 Err(err) => err,
3961 Ok(vpat) => unreachable!("expected version pattern parser error, but got: {vpat:?}"),
3962 };
3963
3964 assert_eq!(p("*"), ErrorKind::NoLeadingNumber.into());
3965 assert_eq!(p("2!*"), ErrorKind::NoLeadingReleaseNumber.into());
3966 }
3967
3968 #[test]
3973 fn ordering() {
3974 let versions = &[
3975 "1.dev0",
3976 "1.0.dev456",
3977 "1.0a1",
3978 "1.0a2.dev456",
3979 "1.0a12.dev456",
3980 "1.0a12",
3981 "1.0b1.dev456",
3982 "1.0b2",
3983 "1.0b2.post345.dev456",
3984 "1.0b2.post345",
3985 "1.0rc1.dev456",
3986 "1.0rc1",
3987 "1.0",
3988 "1.0+abc.5",
3989 "1.0+abc.7",
3990 "1.0+5",
3991 "1.0.post456.dev34",
3992 "1.0.post456",
3993 "1.0.15",
3994 "1.1.dev1",
3995 ];
3996 for (i, v1) in versions.iter().enumerate() {
3997 for v2 in &versions[i + 1..] {
3998 let less = v1.parse::<Version>().unwrap();
3999 let greater = v2.parse::<Version>().unwrap();
4000 assert_eq!(
4001 less.cmp(&greater),
4002 Ordering::Less,
4003 "less: {:?}\ngreater: {:?}",
4004 less.as_bloated_debug(),
4005 greater.as_bloated_debug()
4006 );
4007 }
4008 }
4009 }
4010
4011 #[test]
4012 fn local_sentinel_version() {
4013 let sentinel = Version::new([1, 0]).with_local(LocalVersion::Max);
4014
4015 let versions = &["1.0.post0", "1.1"];
4017
4018 for greater in versions {
4019 let greater = greater.parse::<Version>().unwrap();
4020 assert_eq!(
4021 sentinel.cmp(&greater),
4022 Ordering::Less,
4023 "less: {:?}\ngreater: {:?}",
4024 greater.as_bloated_debug(),
4025 sentinel.as_bloated_debug(),
4026 );
4027 }
4028
4029 let versions = &["1.0", "1.0.a0", "1.0+local"];
4031
4032 for less in versions {
4033 let less = less.parse::<Version>().unwrap();
4034 assert_eq!(
4035 sentinel.cmp(&less),
4036 Ordering::Greater,
4037 "less: {:?}\ngreater: {:?}",
4038 sentinel.as_bloated_debug(),
4039 less.as_bloated_debug()
4040 );
4041 }
4042 }
4043
4044 #[test]
4045 fn min_version() {
4046 let less = Version::new([1, 0]).with_min(Some(0));
4048
4049 let versions = &[
4050 "1.dev0",
4051 "1.0.dev456",
4052 "1.0a1",
4053 "1.0a2.dev456",
4054 "1.0a12.dev456",
4055 "1.0a12",
4056 "1.0b1.dev456",
4057 "1.0b2",
4058 "1.0b2.post345.dev456",
4059 "1.0b2.post345",
4060 "1.0rc1.dev456",
4061 "1.0rc1",
4062 "1.0",
4063 "1.0+abc.5",
4064 "1.0+abc.7",
4065 "1.0+5",
4066 "1.0.post456.dev34",
4067 "1.0.post456",
4068 "1.0.15",
4069 "1.1.dev1",
4070 ];
4071
4072 for greater in versions {
4073 let greater = greater.parse::<Version>().unwrap();
4074 assert_eq!(
4075 less.cmp(&greater),
4076 Ordering::Less,
4077 "less: {:?}\ngreater: {:?}",
4078 less.as_bloated_debug(),
4079 greater.as_bloated_debug()
4080 );
4081 }
4082 }
4083
4084 #[test]
4085 fn max_version() {
4086 let greater = Version::new([1, 0]).with_max(Some(0));
4088
4089 let versions = &[
4090 "1.dev0",
4091 "1.0.dev456",
4092 "1.0a1",
4093 "1.0a2.dev456",
4094 "1.0a12.dev456",
4095 "1.0a12",
4096 "1.0b1.dev456",
4097 "1.0b2",
4098 "1.0b2.post345.dev456",
4099 "1.0b2.post345",
4100 "1.0rc1.dev456",
4101 "1.0rc1",
4102 "1.0",
4103 "1.0+abc.5",
4104 "1.0+abc.7",
4105 "1.0+5",
4106 "1.0.post456.dev34",
4107 "1.0.post456",
4108 "1.0",
4109 ];
4110
4111 for less in versions {
4112 let less = less.parse::<Version>().unwrap();
4113 assert_eq!(
4114 less.cmp(&greater),
4115 Ordering::Less,
4116 "less: {:?}\ngreater: {:?}",
4117 less.as_bloated_debug(),
4118 greater.as_bloated_debug()
4119 );
4120 }
4121
4122 let greater = Version::new([1, 0])
4124 .with_pre(Some(Prerelease {
4125 kind: PrereleaseKind::Alpha,
4126 number: 1,
4127 }))
4128 .with_max(Some(0));
4129
4130 let versions = &["1.0a1", "1.0a1+local", "1.0a1.post1"];
4131
4132 for less in versions {
4133 let less = less.parse::<Version>().unwrap();
4134 assert_eq!(
4135 less.cmp(&greater),
4136 Ordering::Less,
4137 "less: {:?}\ngreater: {:?}",
4138 less.as_bloated_debug(),
4139 greater.as_bloated_debug()
4140 );
4141 }
4142
4143 let less = Version::new([1, 0])
4145 .with_pre(Some(Prerelease {
4146 kind: PrereleaseKind::Alpha,
4147 number: 1,
4148 }))
4149 .with_max(Some(0));
4150
4151 let versions = &["1.0b1", "1.0b1+local", "1.0b1.post1", "1.0"];
4152
4153 for greater in versions {
4154 let greater = greater.parse::<Version>().unwrap();
4155 assert_eq!(
4156 less.cmp(&greater),
4157 Ordering::Less,
4158 "less: {:?}\ngreater: {:?}",
4159 less.as_bloated_debug(),
4160 greater.as_bloated_debug()
4161 );
4162 }
4163 }
4164
4165 #[test]
4167 fn parse_number_u64() {
4168 let p = |s: &str| parse_u64(s.as_bytes());
4169 assert_eq!(p("0"), Ok(0));
4170 assert_eq!(p("00"), Ok(0));
4171 assert_eq!(p("1"), Ok(1));
4172 assert_eq!(p("01"), Ok(1));
4173 assert_eq!(p("9"), Ok(9));
4174 assert_eq!(p("10"), Ok(10));
4175 assert_eq!(p("18446744073709551615"), Ok(18_446_744_073_709_551_615));
4176 assert_eq!(p("018446744073709551615"), Ok(18_446_744_073_709_551_615));
4177 assert_eq!(
4178 p("000000018446744073709551615"),
4179 Ok(18_446_744_073_709_551_615)
4180 );
4181
4182 assert_eq!(p("10a"), Err(ErrorKind::InvalidDigit { got: b'a' }.into()));
4183 assert_eq!(p("10["), Err(ErrorKind::InvalidDigit { got: b'[' }.into()));
4184 assert_eq!(p("10/"), Err(ErrorKind::InvalidDigit { got: b'/' }.into()));
4185 assert_eq!(
4186 p("18446744073709551616"),
4187 Err(ErrorKind::NumberTooBig {
4188 bytes: b"18446744073709551616".to_vec()
4189 }
4190 .into())
4191 );
4192 assert_eq!(
4193 p("18446744073799551615abc"),
4194 Err(ErrorKind::NumberTooBig {
4195 bytes: b"18446744073799551615abc".to_vec()
4196 }
4197 .into())
4198 );
4199 assert_eq!(
4200 parse_u64(b"18446744073799551615\xFF"),
4201 Err(ErrorKind::NumberTooBig {
4202 bytes: b"18446744073799551615\xFF".to_vec()
4203 }
4204 .into())
4205 );
4206 }
4207
4208 struct VersionBloatedDebug<'a>(&'a Version);
4219
4220 impl std::fmt::Debug for VersionBloatedDebug<'_> {
4221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4222 f.debug_struct("Version")
4223 .field("epoch", &self.0.epoch())
4224 .field("release", &&*self.0.release())
4225 .field("pre", &self.0.pre())
4226 .field("post", &self.0.post())
4227 .field("dev", &self.0.dev())
4228 .field("local", &self.0.local())
4229 .field("min", &self.0.min())
4230 .field("max", &self.0.max())
4231 .finish()
4232 }
4233 }
4234
4235 impl Version {
4236 pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4237 VersionBloatedDebug(self)
4238 }
4239 }
4240
4241 #[test]
4245 fn preserve_trailing_zeros() {
4246 let v1: Version = "1.2.0".parse().unwrap();
4247 assert_eq!(&*v1.release(), &[1, 2, 0]);
4248 assert_eq!(v1.to_string(), "1.2.0");
4249
4250 let v2: Version = "1.2".parse().unwrap();
4251 assert_eq!(&*v2.release(), &[1, 2]);
4252 assert_eq!(v2.to_string(), "1.2");
4253 }
4254
4255 #[test]
4256 fn type_size() {
4257 assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4258 assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4259 }
4260
4261 #[test]
4264 fn bump_major() {
4265 let mut version = "0".parse::<Version>().unwrap();
4267 version.bump(BumpCommand::BumpRelease {
4268 index: 0,
4269 value: None,
4270 });
4271 assert_eq!(version.to_string().as_str(), "1");
4272
4273 let mut version = "1.5".parse::<Version>().unwrap();
4275 version.bump(BumpCommand::BumpRelease {
4276 index: 0,
4277 value: None,
4278 });
4279 assert_eq!(version.to_string().as_str(), "2.0");
4280
4281 let mut version = "0.1.2".parse::<Version>().unwrap();
4283 version.bump(BumpCommand::BumpRelease {
4284 index: 0,
4285 value: None,
4286 });
4287 assert_eq!(version.to_string().as_str(), "1.0.0");
4288
4289 let mut version = "1.2.3".parse::<Version>().unwrap();
4291 version.bump(BumpCommand::BumpRelease {
4292 index: 0,
4293 value: None,
4294 });
4295 assert_eq!(version.to_string().as_str(), "2.0.0");
4296
4297 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4299 version.bump(BumpCommand::BumpRelease {
4300 index: 0,
4301 value: None,
4302 });
4303 assert_eq!(version.to_string().as_str(), "2.0.0.0");
4304
4305 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4307 .parse::<Version>()
4308 .unwrap();
4309 version.bump(BumpCommand::BumpRelease {
4310 index: 0,
4311 value: None,
4312 });
4313 assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4314 version.bump(BumpCommand::BumpRelease {
4315 index: 0,
4316 value: None,
4317 });
4318 assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4319 }
4320
4321 #[test]
4324 fn bump_minor() {
4325 let mut version = "0".parse::<Version>().unwrap();
4327 version.bump(BumpCommand::BumpRelease {
4328 index: 1,
4329 value: None,
4330 });
4331 assert_eq!(version.to_string().as_str(), "0.1");
4332
4333 let mut version = "1.5".parse::<Version>().unwrap();
4335 version.bump(BumpCommand::BumpRelease {
4336 index: 1,
4337 value: None,
4338 });
4339 assert_eq!(version.to_string().as_str(), "1.6");
4340
4341 let mut version = "5.3.6".parse::<Version>().unwrap();
4343 version.bump(BumpCommand::BumpRelease {
4344 index: 1,
4345 value: None,
4346 });
4347 assert_eq!(version.to_string().as_str(), "5.4.0");
4348
4349 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4351 version.bump(BumpCommand::BumpRelease {
4352 index: 1,
4353 value: None,
4354 });
4355 assert_eq!(version.to_string().as_str(), "1.3.0.0");
4356
4357 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4359 .parse::<Version>()
4360 .unwrap();
4361 version.bump(BumpCommand::BumpRelease {
4362 index: 1,
4363 value: None,
4364 });
4365 assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4366 version.bump(BumpCommand::BumpRelease {
4367 index: 1,
4368 value: None,
4369 });
4370 assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4371 }
4372
4373 #[test]
4376 fn bump_patch() {
4377 let mut version = "0".parse::<Version>().unwrap();
4379 version.bump(BumpCommand::BumpRelease {
4380 index: 2,
4381 value: None,
4382 });
4383 assert_eq!(version.to_string().as_str(), "0.0.1");
4384
4385 let mut version = "1.5".parse::<Version>().unwrap();
4387 version.bump(BumpCommand::BumpRelease {
4388 index: 2,
4389 value: None,
4390 });
4391 assert_eq!(version.to_string().as_str(), "1.5.1");
4392
4393 let mut version = "5.3.6".parse::<Version>().unwrap();
4395 version.bump(BumpCommand::BumpRelease {
4396 index: 2,
4397 value: None,
4398 });
4399 assert_eq!(version.to_string().as_str(), "5.3.7");
4400
4401 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4403 version.bump(BumpCommand::BumpRelease {
4404 index: 2,
4405 value: None,
4406 });
4407 assert_eq!(version.to_string().as_str(), "1.2.4.0");
4408
4409 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4411 .parse::<Version>()
4412 .unwrap();
4413 version.bump(BumpCommand::BumpRelease {
4414 index: 2,
4415 value: None,
4416 });
4417 assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4418 version.bump(BumpCommand::BumpRelease {
4419 index: 2,
4420 value: None,
4421 });
4422 assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4423 }
4424
4425 #[test]
4428 fn bump_alpha() {
4429 let mut version = "0".parse::<Version>().unwrap();
4431 version.bump(BumpCommand::BumpPrerelease {
4432 kind: PrereleaseKind::Alpha,
4433 value: None,
4434 });
4435 assert_eq!(version.to_string().as_str(), "0a1");
4436
4437 let mut version = "1.5".parse::<Version>().unwrap();
4439 version.bump(BumpCommand::BumpPrerelease {
4440 kind: PrereleaseKind::Alpha,
4441 value: None,
4442 });
4443 assert_eq!(version.to_string().as_str(), "1.5a1");
4444
4445 let mut version = "5.3.6".parse::<Version>().unwrap();
4447 version.bump(BumpCommand::BumpPrerelease {
4448 kind: PrereleaseKind::Alpha,
4449 value: None,
4450 });
4451 assert_eq!(version.to_string().as_str(), "5.3.6a1");
4452
4453 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4455 version.bump(BumpCommand::BumpPrerelease {
4456 kind: PrereleaseKind::Alpha,
4457 value: None,
4458 });
4459 assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4460
4461 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4463 .parse::<Version>()
4464 .unwrap();
4465 version.bump(BumpCommand::BumpPrerelease {
4466 kind: PrereleaseKind::Alpha,
4467 value: None,
4468 });
4469 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4470 version.bump(BumpCommand::BumpPrerelease {
4471 kind: PrereleaseKind::Alpha,
4472 value: None,
4473 });
4474 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4475 }
4476
4477 #[test]
4480 fn bump_beta() {
4481 let mut version = "0".parse::<Version>().unwrap();
4483 version.bump(BumpCommand::BumpPrerelease {
4484 kind: PrereleaseKind::Beta,
4485 value: None,
4486 });
4487 assert_eq!(version.to_string().as_str(), "0b1");
4488
4489 let mut version = "1.5".parse::<Version>().unwrap();
4491 version.bump(BumpCommand::BumpPrerelease {
4492 kind: PrereleaseKind::Beta,
4493 value: None,
4494 });
4495 assert_eq!(version.to_string().as_str(), "1.5b1");
4496
4497 let mut version = "5.3.6".parse::<Version>().unwrap();
4499 version.bump(BumpCommand::BumpPrerelease {
4500 kind: PrereleaseKind::Beta,
4501 value: None,
4502 });
4503 assert_eq!(version.to_string().as_str(), "5.3.6b1");
4504
4505 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4507 version.bump(BumpCommand::BumpPrerelease {
4508 kind: PrereleaseKind::Beta,
4509 value: None,
4510 });
4511 assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4512
4513 let mut version = "5!1.7.3.5a2.post345.dev456+local"
4515 .parse::<Version>()
4516 .unwrap();
4517 version.bump(BumpCommand::BumpPrerelease {
4518 kind: PrereleaseKind::Beta,
4519 value: None,
4520 });
4521 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4522 version.bump(BumpCommand::BumpPrerelease {
4523 kind: PrereleaseKind::Beta,
4524 value: None,
4525 });
4526 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4527 }
4528
4529 #[test]
4532 fn bump_rc() {
4533 let mut version = "0".parse::<Version>().unwrap();
4535 version.bump(BumpCommand::BumpPrerelease {
4536 kind: PrereleaseKind::Rc,
4537 value: None,
4538 });
4539 assert_eq!(version.to_string().as_str(), "0rc1");
4540
4541 let mut version = "1.5".parse::<Version>().unwrap();
4543 version.bump(BumpCommand::BumpPrerelease {
4544 kind: PrereleaseKind::Rc,
4545 value: None,
4546 });
4547 assert_eq!(version.to_string().as_str(), "1.5rc1");
4548
4549 let mut version = "5.3.6".parse::<Version>().unwrap();
4551 version.bump(BumpCommand::BumpPrerelease {
4552 kind: PrereleaseKind::Rc,
4553 value: None,
4554 });
4555 assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4556
4557 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4559 version.bump(BumpCommand::BumpPrerelease {
4560 kind: PrereleaseKind::Rc,
4561 value: None,
4562 });
4563 assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4564
4565 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4567 .parse::<Version>()
4568 .unwrap();
4569 version.bump(BumpCommand::BumpPrerelease {
4570 kind: PrereleaseKind::Rc,
4571 value: None,
4572 });
4573 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4574 version.bump(BumpCommand::BumpPrerelease {
4575 kind: PrereleaseKind::Rc,
4576 value: None,
4577 });
4578 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4579 }
4580
4581 #[test]
4584 fn bump_post() {
4585 let mut version = "0".parse::<Version>().unwrap();
4587 version.bump(BumpCommand::BumpPost { value: None });
4588 assert_eq!(version.to_string().as_str(), "0.post1");
4589
4590 let mut version = "1.5".parse::<Version>().unwrap();
4592 version.bump(BumpCommand::BumpPost { value: None });
4593 assert_eq!(version.to_string().as_str(), "1.5.post1");
4594
4595 let mut version = "5.3.6".parse::<Version>().unwrap();
4597 version.bump(BumpCommand::BumpPost { value: None });
4598 assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4599
4600 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4602 version.bump(BumpCommand::BumpPost { value: None });
4603 assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4604
4605 let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4607 version.bump(BumpCommand::BumpPost { value: None });
4608 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4609 version.bump(BumpCommand::BumpPost { value: None });
4610 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4611 }
4612
4613 #[test]
4616 fn bump_dev() {
4617 let mut version = "0".parse::<Version>().unwrap();
4619 version.bump(BumpCommand::BumpDev { value: None });
4620 assert_eq!(version.to_string().as_str(), "0.dev1");
4621
4622 let mut version = "1.5".parse::<Version>().unwrap();
4624 version.bump(BumpCommand::BumpDev { value: None });
4625 assert_eq!(version.to_string().as_str(), "1.5.dev1");
4626
4627 let mut version = "5.3.6".parse::<Version>().unwrap();
4629 version.bump(BumpCommand::BumpDev { value: None });
4630 assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4631
4632 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4634 version.bump(BumpCommand::BumpDev { value: None });
4635 assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4636
4637 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4639 version.bump(BumpCommand::BumpDev { value: None });
4640 assert_eq!(
4641 version.to_string().as_str(),
4642 "5!1.7.3.5b2.post345.dev1+local"
4643 );
4644 version.bump(BumpCommand::BumpDev { value: None });
4645 assert_eq!(
4646 version.to_string().as_str(),
4647 "5!1.7.3.5b2.post345.dev2+local"
4648 );
4649 }
4650
4651 #[test]
4654 fn make_stable() {
4655 let mut version = "0".parse::<Version>().unwrap();
4657 version.bump(BumpCommand::MakeStable);
4658 assert_eq!(version.to_string().as_str(), "0");
4659
4660 let mut version = "1.5".parse::<Version>().unwrap();
4662 version.bump(BumpCommand::MakeStable);
4663 assert_eq!(version.to_string().as_str(), "1.5");
4664
4665 let mut version = "5.3.6".parse::<Version>().unwrap();
4667 version.bump(BumpCommand::MakeStable);
4668 assert_eq!(version.to_string().as_str(), "5.3.6");
4669
4670 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4672 version.bump(BumpCommand::MakeStable);
4673 assert_eq!(version.to_string().as_str(), "1.2.3.4");
4674
4675 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4677 version.bump(BumpCommand::MakeStable);
4678 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4679 version.bump(BumpCommand::MakeStable);
4680 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4681 }
4682}