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