1use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
2use std::fmt::Formatter;
3use std::num::NonZero;
4use std::ops::Deref;
5use std::sync::LazyLock;
6use std::{
7 borrow::Borrow,
8 cmp::Ordering,
9 hash::{Hash, Hasher},
10 str::FromStr,
11 sync::Arc,
12};
13use uv_cache_key::{CacheKey, CacheKeyHasher};
14
15#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Hash, Clone, Copy)]
17#[cfg_attr(
18 feature = "rkyv",
19 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
20)]
21#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
22pub enum Operator {
23 Equal,
25 EqualStar,
27 ExactEqual,
34 NotEqual,
36 NotEqualStar,
38 TildeEqual,
42 LessThan,
44 LessThanEqual,
46 GreaterThan,
48 GreaterThanEqual,
50}
51
52impl Operator {
53 pub fn negate(self) -> Option<Self> {
67 Some(match self {
68 Self::Equal => Self::NotEqual,
69 Self::EqualStar => Self::NotEqualStar,
70 Self::ExactEqual => Self::NotEqual,
71 Self::NotEqual => Self::Equal,
72 Self::NotEqualStar => Self::EqualStar,
73 Self::TildeEqual => return None,
74 Self::LessThan => Self::GreaterThanEqual,
75 Self::LessThanEqual => Self::GreaterThan,
76 Self::GreaterThan => Self::LessThanEqual,
77 Self::GreaterThanEqual => Self::LessThan,
78 })
79 }
80
81 pub(crate) fn is_local_compatible(self) -> bool {
90 !matches!(
91 self,
92 Self::GreaterThan
93 | Self::GreaterThanEqual
94 | Self::LessThan
95 | Self::LessThanEqual
96 | Self::TildeEqual
97 | Self::EqualStar
98 | Self::NotEqualStar
99 )
100 }
101
102 pub(crate) fn to_star(self) -> Option<Self> {
107 match self {
108 Self::Equal => Some(Self::EqualStar),
109 Self::NotEqual => Some(Self::NotEqualStar),
110 _ => None,
111 }
112 }
113
114 pub fn is_star(self) -> bool {
116 matches!(self, Self::EqualStar | Self::NotEqualStar)
117 }
118
119 pub fn as_str(self) -> &'static str {
121 match self {
122 Self::Equal => "==",
123 Self::EqualStar => "==",
125 #[allow(deprecated)]
126 Self::ExactEqual => "===",
127 Self::NotEqual => "!=",
128 Self::NotEqualStar => "!=",
129 Self::TildeEqual => "~=",
130 Self::LessThan => "<",
131 Self::LessThanEqual => "<=",
132 Self::GreaterThan => ">",
133 Self::GreaterThanEqual => ">=",
134 }
135 }
136}
137
138impl FromStr for Operator {
139 type Err = OperatorParseError;
140
141 fn from_str(s: &str) -> Result<Self, Self::Err> {
143 let operator = match s {
144 "==" => Self::Equal,
145 "===" => {
146 #[cfg(feature = "tracing")]
147 {
148 tracing::warn!("Using arbitrary equality (`===`) is discouraged");
149 }
150 #[allow(deprecated)]
151 Self::ExactEqual
152 }
153 "!=" => Self::NotEqual,
154 "~=" => Self::TildeEqual,
155 "<" => Self::LessThan,
156 "<=" => Self::LessThanEqual,
157 ">" => Self::GreaterThan,
158 ">=" => Self::GreaterThanEqual,
159 other => {
160 return Err(OperatorParseError {
161 got: other.to_string(),
162 });
163 }
164 };
165 Ok(operator)
166 }
167}
168
169impl std::fmt::Display for Operator {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 let operator = self.as_str();
173 write!(f, "{operator}")
174 }
175}
176
177#[derive(Clone, Debug, Eq, PartialEq)]
179pub struct OperatorParseError {
180 pub(crate) got: String,
181}
182
183impl std::error::Error for OperatorParseError {}
184
185impl std::fmt::Display for OperatorParseError {
186 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
187 write!(
188 f,
189 "no such comparison operator {:?}, must be one of ~= == != <= >= < > ===",
190 self.got
191 )
192 }
193}
194
195#[derive(Clone)]
272#[cfg_attr(
273 feature = "rkyv",
274 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
275)]
276#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
277pub struct Version {
278 inner: VersionInner,
279}
280
281#[derive(Clone, Debug)]
282#[cfg_attr(
283 feature = "rkyv",
284 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
285)]
286#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
287enum VersionInner {
288 Small { small: VersionSmall },
289 Full { full: Arc<VersionFull> },
290}
291
292impl Version {
293 #[inline]
300 pub fn new<I, R>(release_numbers: I) -> Self
301 where
302 I: IntoIterator<Item = R>,
303 R: Borrow<u64>,
304 {
305 Self {
306 inner: VersionInner::Small {
307 small: VersionSmall::new(),
308 },
309 }
310 .with_release(release_numbers)
311 }
312
313 #[inline]
315 pub fn any_prerelease(&self) -> bool {
316 self.is_pre() || self.is_dev()
317 }
318
319 #[inline]
321 pub fn is_stable(&self) -> bool {
322 !self.is_pre() && !self.is_dev()
323 }
324
325 #[inline]
327 pub fn is_pre(&self) -> bool {
328 self.pre().is_some()
329 }
330
331 #[inline]
333 pub fn is_dev(&self) -> bool {
334 self.dev().is_some()
335 }
336
337 #[inline]
339 pub fn is_post(&self) -> bool {
340 self.post().is_some()
341 }
342
343 #[inline]
348 pub fn is_local(&self) -> bool {
349 !self.local().is_empty()
350 }
351
352 #[inline]
354 pub fn epoch(&self) -> u64 {
355 match self.inner {
356 VersionInner::Small { ref small } => small.epoch(),
357 VersionInner::Full { ref full } => full.epoch,
358 }
359 }
360
361 #[inline]
363 pub fn release(&self) -> Release<'_> {
364 let inner = match &self.inner {
365 VersionInner::Small { small } => {
366 match small.len {
371 0 => ReleaseInner::Small0([]),
372 1 => ReleaseInner::Small1([(small.repr >> 0o60) & 0xFFFF]),
373 2 => ReleaseInner::Small2([
374 (small.repr >> 0o60) & 0xFFFF,
375 (small.repr >> 0o50) & 0xFF,
376 ]),
377 3 => ReleaseInner::Small3([
378 (small.repr >> 0o60) & 0xFFFF,
379 (small.repr >> 0o50) & 0xFF,
380 (small.repr >> 0o40) & 0xFF,
381 ]),
382 4 => ReleaseInner::Small4([
383 (small.repr >> 0o60) & 0xFFFF,
384 (small.repr >> 0o50) & 0xFF,
385 (small.repr >> 0o40) & 0xFF,
386 (small.repr >> 0o30) & 0xFF,
387 ]),
388 _ => unreachable!("{}", small.len),
389 }
390 }
391 VersionInner::Full { full } => ReleaseInner::Full(&full.release),
392 };
393
394 Release { inner }
395 }
396
397 #[inline]
399 pub fn pre(&self) -> Option<Prerelease> {
400 match self.inner {
401 VersionInner::Small { ref small } => small.pre(),
402 VersionInner::Full { ref full } => full.pre,
403 }
404 }
405
406 #[inline]
408 pub fn post(&self) -> Option<u64> {
409 match self.inner {
410 VersionInner::Small { ref small } => small.post(),
411 VersionInner::Full { ref full } => full.post,
412 }
413 }
414
415 #[inline]
417 pub fn dev(&self) -> Option<u64> {
418 match self.inner {
419 VersionInner::Small { ref small } => small.dev(),
420 VersionInner::Full { ref full } => full.dev,
421 }
422 }
423
424 #[inline]
426 pub fn local(&self) -> LocalVersionSlice<'_> {
427 match self.inner {
428 VersionInner::Small { ref small } => small.local_slice(),
429 VersionInner::Full { ref full } => full.local.as_slice(),
430 }
431 }
432
433 #[inline]
439 pub(crate) fn min(&self) -> Option<u64> {
440 match self.inner {
441 VersionInner::Small { ref small } => small.min(),
442 VersionInner::Full { ref full } => full.min,
443 }
444 }
445
446 #[inline]
452 pub(crate) 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 #[inline]
851 pub(crate) fn without_post_and_dev_eq(&self, other: &Self) -> bool {
852 match (&self.inner, &other.inner) {
853 (VersionInner::Small { small }, VersionInner::Small { small: other }) => {
854 let mut base = small.clone();
856 let _ = base.set_post(None);
857 let _ = base.set_dev(None);
858 base.repr == other.repr
859 }
860 (VersionInner::Small { .. }, VersionInner::Full { .. })
861 | (VersionInner::Full { .. }, VersionInner::Small { .. } | VersionInner::Full { .. }) => {
862 self.without_post_and_dev_eq_slow(other)
863 }
864 }
865 }
866
867 #[cold]
868 #[inline(never)]
869 fn without_post_and_dev_eq_slow(&self, other: &Self) -> bool {
870 self.epoch() == other.epoch()
871 && compare_release(&self.release(), &other.release()) == Ordering::Equal
872 && sortable_tuple_with(self, None, None) == sortable_tuple(other)
873 }
874
875 #[cold]
882 #[inline(never)]
883 fn cmp_slow(&self, other: &Self) -> Ordering {
884 match self.epoch().cmp(&other.epoch()) {
885 Ordering::Less => {
886 return Ordering::Less;
887 }
888 Ordering::Equal => {}
889 Ordering::Greater => {
890 return Ordering::Greater;
891 }
892 }
893
894 match compare_release(&self.release(), &other.release()) {
895 Ordering::Less => {
896 return Ordering::Less;
897 }
898 Ordering::Equal => {}
899 Ordering::Greater => {
900 return Ordering::Greater;
901 }
902 }
903
904 sortable_tuple(self).cmp(&sortable_tuple(other))
906 }
907}
908
909impl<'de> Deserialize<'de> for Version {
910 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
911 where
912 D: Deserializer<'de>,
913 {
914 struct Visitor;
915
916 impl de::Visitor<'_> for Visitor {
917 type Value = Version;
918
919 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
920 f.write_str("a string")
921 }
922
923 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
924 Version::from_str(v).map_err(de::Error::custom)
925 }
926 }
927
928 deserializer.deserialize_str(Visitor)
929 }
930}
931
932impl Serialize for Version {
934 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
935 where
936 S: Serializer,
937 {
938 serializer.collect_str(self)
939 }
940}
941
942impl std::fmt::Display for Version {
944 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
945 if self.epoch() != 0 {
946 write!(f, "{}!", self.epoch())?;
947 }
948 let release = self.release();
949 let mut release_iter = release.iter();
950 if let Some(first) = release_iter.next() {
951 write!(f, "{first}")?;
952 for n in release_iter {
953 write!(f, ".{n}")?;
954 }
955 }
956
957 if let Some(Prerelease { kind, number }) = self.pre() {
958 write!(f, "{kind}{number}")?;
959 }
960 if let Some(post) = self.post() {
961 write!(f, ".post{post}")?;
962 }
963 if let Some(dev) = self.dev() {
964 write!(f, ".dev{dev}")?;
965 }
966 if !self.local().is_empty() {
967 match self.local() {
968 LocalVersionSlice::Segments(_) => {
969 write!(f, "+{}", self.local())?;
970 }
971 LocalVersionSlice::Max => {
972 write!(f, "+")?;
973 }
974 }
975 }
976 Ok(())
977 }
978}
979
980impl std::fmt::Debug for Version {
981 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
982 write!(f, "\"{self}\"")
983 }
984}
985
986impl PartialEq<Self> for Version {
987 #[inline]
988 fn eq(&self, other: &Self) -> bool {
989 self.cmp(other) == Ordering::Equal
990 }
991}
992
993impl Eq for Version {}
994
995impl Hash for Version {
996 #[inline]
998 fn hash<H: Hasher>(&self, state: &mut H) {
999 self.epoch().hash(state);
1000 for i in self.release().iter().rev().skip_while(|x| **x == 0) {
1002 i.hash(state);
1003 }
1004 self.pre().hash(state);
1005 self.dev().hash(state);
1006 self.post().hash(state);
1007 self.local().hash(state);
1008 }
1009}
1010
1011impl CacheKey for Version {
1012 fn cache_key(&self, state: &mut CacheKeyHasher) {
1013 self.epoch().cache_key(state);
1014
1015 let release = self.release();
1016 release.len().cache_key(state);
1017 for segment in release.iter() {
1018 segment.cache_key(state);
1019 }
1020
1021 if let Some(pre) = self.pre() {
1022 1u8.cache_key(state);
1023 match pre.kind {
1024 PrereleaseKind::Alpha => 0u8.cache_key(state),
1025 PrereleaseKind::Beta => 1u8.cache_key(state),
1026 PrereleaseKind::Rc => 2u8.cache_key(state),
1027 }
1028 pre.number.cache_key(state);
1029 } else {
1030 0u8.cache_key(state);
1031 }
1032
1033 if let Some(post) = self.post() {
1034 1u8.cache_key(state);
1035 post.cache_key(state);
1036 } else {
1037 0u8.cache_key(state);
1038 }
1039
1040 if let Some(dev) = self.dev() {
1041 1u8.cache_key(state);
1042 dev.cache_key(state);
1043 } else {
1044 0u8.cache_key(state);
1045 }
1046
1047 self.local().cache_key(state);
1048 }
1049}
1050
1051impl PartialOrd<Self> for Version {
1052 #[inline]
1053 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1054 Some(self.cmp(other))
1055 }
1056}
1057
1058impl Ord for Version {
1059 #[inline]
1063 fn cmp(&self, other: &Self) -> Ordering {
1064 match (&self.inner, &other.inner) {
1065 (VersionInner::Small { small: small1 }, VersionInner::Small { small: small2 }) => {
1066 small1.repr.cmp(&small2.repr)
1067 }
1068 _ => self.cmp_slow(other),
1069 }
1070 }
1071}
1072
1073impl FromStr for Version {
1074 type Err = VersionParseError;
1075
1076 fn from_str(version: &str) -> Result<Self, Self::Err> {
1080 Parser::new(version.as_bytes()).parse()
1081 }
1082}
1083
1084#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
1086pub enum BumpCommand {
1087 BumpRelease {
1089 index: usize,
1091 value: Option<u64>,
1093 },
1094 BumpPrerelease {
1096 kind: PrereleaseKind,
1098 value: Option<u64>,
1100 },
1101 MakeStable,
1103 BumpPost {
1105 value: Option<u64>,
1107 },
1108 BumpDev {
1110 value: Option<u64>,
1112 },
1113}
1114
1115#[derive(Clone, Debug)]
1190#[cfg_attr(
1191 feature = "rkyv",
1192 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1193)]
1194#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1195struct VersionSmall {
1196 repr: u64,
1198 len: u8,
1203 _force_niche: NonZero<u8>,
1205}
1206
1207impl VersionSmall {
1208 const SUFFIX_MIN: u64 = 0;
1223 const SUFFIX_DEV: u64 = 1;
1224 const SUFFIX_PRE_ALPHA: u64 = 2;
1225 const SUFFIX_PRE_BETA: u64 = 3;
1226 const SUFFIX_PRE_RC: u64 = 4;
1227 const SUFFIX_NONE: u64 = 5;
1228 const SUFFIX_LOCAL: u64 = 6;
1229 const SUFFIX_POST: u64 = 7;
1230 const SUFFIX_MAX: u64 = 8;
1231
1232 const SUFFIX_RELEASE_MASK: u64 = 0xFFFF_FFFF_FF00_0000;
1238 const SUFFIX_VERSION_MASK: u64 = 0x000F_FFFF;
1240 const SUFFIX_VERSION_BIT_LEN: u64 = 20;
1244 const SUFFIX_KIND_MASK: u64 = 0b1111;
1249
1250 #[inline]
1251 fn new() -> Self {
1252 Self {
1253 _force_niche: NonZero::<u8>::MIN,
1254 repr: Self::SUFFIX_NONE << Self::SUFFIX_VERSION_BIT_LEN,
1255 len: 0,
1256 }
1257 }
1258
1259 #[inline]
1260 #[expect(clippy::unused_self)]
1261 fn epoch(&self) -> u64 {
1262 0
1263 }
1264
1265 #[inline]
1266 #[expect(clippy::unused_self)]
1267 fn set_epoch(&mut self, value: u64) -> bool {
1268 if value != 0 {
1269 return false;
1270 }
1271 true
1272 }
1273
1274 #[inline]
1275 fn clear_release(&mut self) {
1276 self.repr &= !Self::SUFFIX_RELEASE_MASK;
1277 self.len = 0;
1278 }
1279
1280 #[inline]
1281 fn push_release(&mut self, n: u64) -> bool {
1282 if self.len == 0 {
1283 if n > u64::from(u16::MAX) {
1284 return false;
1285 }
1286 self.repr |= n << 48;
1287 self.len = 1;
1288 true
1289 } else {
1290 if n > u64::from(u8::MAX) {
1291 return false;
1292 }
1293 if self.len >= 4 {
1294 return false;
1295 }
1296 let shift = 48 - (usize::from(self.len) * 8);
1297 self.repr |= n << shift;
1298 self.len += 1;
1299 true
1300 }
1301 }
1302
1303 #[inline]
1304 fn post(&self) -> Option<u64> {
1305 if self.suffix_kind() == Self::SUFFIX_POST {
1306 Some(self.suffix_version())
1307 } else {
1308 None
1309 }
1310 }
1311
1312 #[inline]
1313 fn set_post(&mut self, value: Option<u64>) -> bool {
1314 let suffix_kind = self.suffix_kind();
1315 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_POST) {
1316 return value.is_none();
1317 }
1318 match value {
1319 None => {
1320 self.set_suffix_kind(Self::SUFFIX_NONE);
1321 }
1322 Some(number) => {
1323 if number > Self::SUFFIX_VERSION_MASK {
1324 return false;
1325 }
1326 self.set_suffix_kind(Self::SUFFIX_POST);
1327 self.set_suffix_version(number);
1328 }
1329 }
1330 true
1331 }
1332
1333 #[inline]
1334 fn pre(&self) -> Option<Prerelease> {
1335 let (kind, number) = (self.suffix_kind(), self.suffix_version());
1336 if kind == Self::SUFFIX_PRE_ALPHA {
1337 Some(Prerelease {
1338 kind: PrereleaseKind::Alpha,
1339 number,
1340 })
1341 } else if kind == Self::SUFFIX_PRE_BETA {
1342 Some(Prerelease {
1343 kind: PrereleaseKind::Beta,
1344 number,
1345 })
1346 } else if kind == Self::SUFFIX_PRE_RC {
1347 Some(Prerelease {
1348 kind: PrereleaseKind::Rc,
1349 number,
1350 })
1351 } else {
1352 None
1353 }
1354 }
1355
1356 #[inline]
1357 fn set_pre(&mut self, value: Option<Prerelease>) -> bool {
1358 let suffix_kind = self.suffix_kind();
1359 if !(suffix_kind == Self::SUFFIX_NONE
1360 || suffix_kind == Self::SUFFIX_PRE_ALPHA
1361 || suffix_kind == Self::SUFFIX_PRE_BETA
1362 || suffix_kind == Self::SUFFIX_PRE_RC)
1363 {
1364 return value.is_none();
1365 }
1366 match value {
1367 None => {
1368 self.set_suffix_kind(Self::SUFFIX_NONE);
1369 }
1370 Some(Prerelease { kind, number }) => {
1371 if number > Self::SUFFIX_VERSION_MASK {
1372 return false;
1373 }
1374 match kind {
1375 PrereleaseKind::Alpha => {
1376 self.set_suffix_kind(Self::SUFFIX_PRE_ALPHA);
1377 }
1378 PrereleaseKind::Beta => {
1379 self.set_suffix_kind(Self::SUFFIX_PRE_BETA);
1380 }
1381 PrereleaseKind::Rc => {
1382 self.set_suffix_kind(Self::SUFFIX_PRE_RC);
1383 }
1384 }
1385 self.set_suffix_version(number);
1386 }
1387 }
1388 true
1389 }
1390
1391 #[inline]
1392 fn dev(&self) -> Option<u64> {
1393 if self.suffix_kind() == Self::SUFFIX_DEV {
1394 Some(self.suffix_version())
1395 } else {
1396 None
1397 }
1398 }
1399
1400 #[inline]
1401 fn set_dev(&mut self, value: Option<u64>) -> bool {
1402 let suffix_kind = self.suffix_kind();
1403 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_DEV) {
1404 return value.is_none();
1405 }
1406 match value {
1407 None => {
1408 self.set_suffix_kind(Self::SUFFIX_NONE);
1409 }
1410 Some(number) => {
1411 if number > Self::SUFFIX_VERSION_MASK {
1412 return false;
1413 }
1414 self.set_suffix_kind(Self::SUFFIX_DEV);
1415 self.set_suffix_version(number);
1416 }
1417 }
1418 true
1419 }
1420
1421 #[inline]
1422 fn min(&self) -> Option<u64> {
1423 if self.suffix_kind() == Self::SUFFIX_MIN {
1424 Some(self.suffix_version())
1425 } else {
1426 None
1427 }
1428 }
1429
1430 #[inline]
1431 fn set_min(&mut self, value: Option<u64>) -> bool {
1432 let suffix_kind = self.suffix_kind();
1433 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MIN) {
1434 return value.is_none();
1435 }
1436 match value {
1437 None => {
1438 self.set_suffix_kind(Self::SUFFIX_NONE);
1439 }
1440 Some(number) => {
1441 if number > Self::SUFFIX_VERSION_MASK {
1442 return false;
1443 }
1444 self.set_suffix_kind(Self::SUFFIX_MIN);
1445 self.set_suffix_version(number);
1446 }
1447 }
1448 true
1449 }
1450
1451 #[inline]
1452 fn max(&self) -> Option<u64> {
1453 if self.suffix_kind() == Self::SUFFIX_MAX {
1454 Some(self.suffix_version())
1455 } else {
1456 None
1457 }
1458 }
1459
1460 #[inline]
1461 fn set_max(&mut self, value: Option<u64>) -> bool {
1462 let suffix_kind = self.suffix_kind();
1463 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_MAX) {
1464 return value.is_none();
1465 }
1466 match value {
1467 None => {
1468 self.set_suffix_kind(Self::SUFFIX_NONE);
1469 }
1470 Some(number) => {
1471 if number > Self::SUFFIX_VERSION_MASK {
1472 return false;
1473 }
1474 self.set_suffix_kind(Self::SUFFIX_MAX);
1475 self.set_suffix_version(number);
1476 }
1477 }
1478 true
1479 }
1480
1481 #[inline]
1482 fn local(&self) -> LocalVersion {
1483 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1484 LocalVersion::Max
1485 } else {
1486 LocalVersion::empty()
1487 }
1488 }
1489
1490 #[inline]
1491 fn local_slice(&self) -> LocalVersionSlice<'_> {
1492 if self.suffix_kind() == Self::SUFFIX_LOCAL {
1493 LocalVersionSlice::Max
1494 } else {
1495 LocalVersionSlice::empty()
1496 }
1497 }
1498
1499 #[inline]
1500 fn set_local(&mut self, value: LocalVersion) -> bool {
1501 let suffix_kind = self.suffix_kind();
1502 if !(suffix_kind == Self::SUFFIX_NONE || suffix_kind == Self::SUFFIX_LOCAL) {
1503 return value.is_empty();
1504 }
1505 match value {
1506 LocalVersion::Max => {
1507 self.set_suffix_kind(Self::SUFFIX_LOCAL);
1508 true
1509 }
1510 LocalVersion::Segments(segments) if segments.is_empty() => {
1511 self.set_suffix_kind(Self::SUFFIX_NONE);
1512 true
1513 }
1514 LocalVersion::Segments(_) => false,
1515 }
1516 }
1517
1518 #[inline]
1519 fn suffix_kind(&self) -> u64 {
1520 let kind = (self.repr >> Self::SUFFIX_VERSION_BIT_LEN) & Self::SUFFIX_KIND_MASK;
1521 debug_assert!(kind <= Self::SUFFIX_MAX);
1522 kind
1523 }
1524
1525 #[inline]
1526 fn set_suffix_kind(&mut self, kind: u64) {
1527 debug_assert!(kind <= Self::SUFFIX_MAX);
1528 self.repr &= !(Self::SUFFIX_KIND_MASK << Self::SUFFIX_VERSION_BIT_LEN);
1529 self.repr |= kind << Self::SUFFIX_VERSION_BIT_LEN;
1530 if kind == Self::SUFFIX_NONE || kind == Self::SUFFIX_LOCAL {
1531 self.set_suffix_version(0);
1532 }
1533 }
1534
1535 #[inline]
1536 fn suffix_version(&self) -> u64 {
1537 self.repr & Self::SUFFIX_VERSION_MASK
1538 }
1539
1540 #[inline]
1541 fn set_suffix_version(&mut self, value: u64) {
1542 debug_assert!(value <= Self::SUFFIX_VERSION_MASK);
1543 self.repr &= !Self::SUFFIX_VERSION_MASK;
1544 self.repr |= value;
1545 }
1546}
1547
1548#[derive(Clone, Debug)]
1557#[cfg_attr(
1558 feature = "rkyv",
1559 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1560)]
1561#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1562struct VersionFull {
1563 epoch: u64,
1568 release: Vec<u64>,
1574 pre: Option<Prerelease>,
1580 post: Option<u64>,
1584 dev: Option<u64>,
1588 local: LocalVersion,
1601 min: Option<u64>,
1605 max: Option<u64>,
1609}
1610
1611#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1630pub struct VersionPattern {
1631 version: Version,
1632 wildcard: bool,
1633}
1634
1635impl VersionPattern {
1636 #[inline]
1639 pub fn verbatim(version: Version) -> Self {
1640 Self {
1641 version,
1642 wildcard: false,
1643 }
1644 }
1645
1646 #[inline]
1649 pub fn wildcard(version: Version) -> Self {
1650 Self {
1651 version,
1652 wildcard: true,
1653 }
1654 }
1655
1656 #[inline]
1658 pub fn version(&self) -> &Version {
1659 &self.version
1660 }
1661
1662 #[inline]
1664 pub(crate) fn into_version(self) -> Version {
1665 self.version
1666 }
1667
1668 #[inline]
1670 pub(crate) fn is_wildcard(&self) -> bool {
1671 self.wildcard
1672 }
1673}
1674
1675impl FromStr for VersionPattern {
1676 type Err = VersionPatternParseError;
1677
1678 fn from_str(version: &str) -> Result<Self, VersionPatternParseError> {
1679 Parser::new(version.as_bytes()).parse_pattern()
1680 }
1681}
1682
1683pub struct Release<'a> {
1688 inner: ReleaseInner<'a>,
1689}
1690
1691enum ReleaseInner<'a> {
1692 Small0([u64; 0]),
1696 Small1([u64; 1]),
1697 Small2([u64; 2]),
1698 Small3([u64; 3]),
1699 Small4([u64; 4]),
1700 Full(&'a [u64]),
1701}
1702
1703impl Deref for Release<'_> {
1704 type Target = [u64];
1705
1706 fn deref(&self) -> &Self::Target {
1707 match &self.inner {
1708 ReleaseInner::Small0(v) => v,
1709 ReleaseInner::Small1(v) => v,
1710 ReleaseInner::Small2(v) => v,
1711 ReleaseInner::Small3(v) => v,
1712 ReleaseInner::Small4(v) => v,
1713 ReleaseInner::Full(v) => v,
1714 }
1715 }
1716}
1717
1718#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1720#[cfg_attr(
1721 feature = "rkyv",
1722 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1723)]
1724#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1725pub struct Prerelease {
1726 pub kind: PrereleaseKind,
1728 pub number: u64,
1730}
1731
1732#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Ord, PartialOrd)]
1736#[cfg_attr(
1737 feature = "rkyv",
1738 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1739)]
1740#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1741pub enum PrereleaseKind {
1742 Alpha,
1744 Beta,
1746 Rc,
1748}
1749
1750impl std::fmt::Display for PrereleaseKind {
1751 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1752 match self {
1753 Self::Alpha => write!(f, "a"),
1754 Self::Beta => write!(f, "b"),
1755 Self::Rc => write!(f, "rc"),
1756 }
1757 }
1758}
1759
1760impl std::fmt::Display for Prerelease {
1761 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1762 write!(f, "{}{}", self.kind, self.number)
1763 }
1764}
1765
1766#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1769#[cfg_attr(
1770 feature = "rkyv",
1771 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1772)]
1773#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1774pub enum LocalVersion {
1775 Segments(Vec<LocalSegment>),
1777 Max,
1779}
1780
1781#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1783pub enum LocalVersionSlice<'a> {
1784 Segments(&'a [LocalSegment]),
1786 Max,
1788}
1789
1790impl LocalVersion {
1791 fn empty() -> Self {
1793 Self::Segments(Vec::new())
1794 }
1795
1796 fn is_empty(&self) -> bool {
1798 match self {
1799 Self::Segments(segments) => segments.is_empty(),
1800 Self::Max => false,
1801 }
1802 }
1803
1804 fn as_slice(&self) -> LocalVersionSlice<'_> {
1806 match self {
1807 Self::Segments(segments) => LocalVersionSlice::Segments(segments),
1808 Self::Max => LocalVersionSlice::Max,
1809 }
1810 }
1811}
1812
1813impl std::fmt::Display for LocalVersionSlice<'_> {
1818 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1819 match self {
1820 Self::Segments(segments) => {
1821 for (i, segment) in segments.iter().enumerate() {
1822 if i > 0 {
1823 write!(f, ".")?;
1824 }
1825 write!(f, "{segment}")?;
1826 }
1827 Ok(())
1828 }
1829 Self::Max => write!(f, "[max]"),
1830 }
1831 }
1832}
1833
1834impl CacheKey for LocalVersionSlice<'_> {
1835 fn cache_key(&self, state: &mut CacheKeyHasher) {
1836 match self {
1837 Self::Segments(segments) => {
1838 0u8.cache_key(state);
1839 segments.len().cache_key(state);
1840 for segment in *segments {
1841 segment.cache_key(state);
1842 }
1843 }
1844 Self::Max => {
1845 1u8.cache_key(state);
1846 }
1847 }
1848 }
1849}
1850
1851impl PartialOrd for LocalVersionSlice<'_> {
1852 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1853 Some(self.cmp(other))
1854 }
1855}
1856
1857impl Ord for LocalVersionSlice<'_> {
1858 fn cmp(&self, other: &Self) -> Ordering {
1859 match (self, other) {
1860 (LocalVersionSlice::Segments(lv1), LocalVersionSlice::Segments(lv2)) => lv1.cmp(lv2),
1861 (LocalVersionSlice::Segments(_), LocalVersionSlice::Max) => Ordering::Less,
1862 (LocalVersionSlice::Max, LocalVersionSlice::Segments(_)) => Ordering::Greater,
1863 (LocalVersionSlice::Max, LocalVersionSlice::Max) => Ordering::Equal,
1864 }
1865 }
1866}
1867
1868impl LocalVersionSlice<'_> {
1869 const fn empty() -> Self {
1871 Self::Segments(&[])
1872 }
1873
1874 pub fn is_empty(&self) -> bool {
1876 matches!(self, &Self::Segments(&[]))
1877 }
1878}
1879
1880#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1896#[cfg_attr(
1897 feature = "rkyv",
1898 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
1899)]
1900#[cfg_attr(feature = "rkyv", rkyv(derive(Debug, Eq, PartialEq, PartialOrd, Ord)))]
1901pub enum LocalSegment {
1902 String(String),
1904 Number(u64),
1906}
1907
1908impl std::fmt::Display for LocalSegment {
1909 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1910 match self {
1911 Self::String(string) => write!(f, "{string}"),
1912 Self::Number(number) => write!(f, "{number}"),
1913 }
1914 }
1915}
1916
1917impl CacheKey for LocalSegment {
1918 fn cache_key(&self, state: &mut CacheKeyHasher) {
1919 match self {
1920 Self::String(string) => {
1921 0u8.cache_key(state);
1922 string.cache_key(state);
1923 }
1924 Self::Number(number) => {
1925 1u8.cache_key(state);
1926 number.cache_key(state);
1927 }
1928 }
1929 }
1930}
1931
1932impl PartialOrd for LocalSegment {
1933 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1934 Some(self.cmp(other))
1935 }
1936}
1937
1938impl Ord for LocalSegment {
1939 fn cmp(&self, other: &Self) -> Ordering {
1940 match (self, other) {
1942 (Self::Number(n1), Self::Number(n2)) => n1.cmp(n2),
1943 (Self::String(s1), Self::String(s2)) => s1.cmp(s2),
1944 (Self::Number(_), Self::String(_)) => Ordering::Greater,
1945 (Self::String(_), Self::Number(_)) => Ordering::Less,
1946 }
1947 }
1948}
1949
1950#[derive(Debug)]
1960struct Parser<'a> {
1961 v: &'a [u8],
1963 i: usize,
1965 epoch: u64,
1967 release: ReleaseNumbers,
1969 pre: Option<Prerelease>,
1971 post: Option<u64>,
1973 dev: Option<u64>,
1975 local: Vec<LocalSegment>,
1977 wildcard: bool,
1981}
1982
1983impl<'a> Parser<'a> {
1984 #[expect(clippy::byte_char_slices)]
1987 const SEPARATOR: ByteSet = ByteSet::new(&[b'.', b'_', b'-']);
1988
1989 fn new(version: &'a [u8]) -> Self {
1991 Parser {
1992 v: version,
1993 i: 0,
1994 epoch: 0,
1995 release: ReleaseNumbers::new(),
1996 pre: None,
1997 post: None,
1998 dev: None,
1999 local: vec![],
2000 wildcard: false,
2001 }
2002 }
2003
2004 fn parse(self) -> Result<Version, VersionParseError> {
2008 match self.parse_pattern() {
2009 Ok(vpat) => {
2010 if vpat.is_wildcard() {
2011 Err(ErrorKind::Wildcard.into())
2012 } else {
2013 Ok(vpat.into_version())
2014 }
2015 }
2016 Err(err) => match *err.kind {
2023 PatternErrorKind::Version(err) => Err(err),
2024 PatternErrorKind::WildcardNotTrailing => Err(ErrorKind::Wildcard.into()),
2025 },
2026 }
2027 }
2028
2029 fn parse_pattern(mut self) -> Result<VersionPattern, VersionPatternParseError> {
2031 if let Some(vpat) = self.parse_fast() {
2032 return Ok(vpat);
2033 }
2034 self.bump_while(|byte| byte.is_ascii_whitespace());
2035 self.bump_if("v");
2036 self.parse_epoch_and_initial_release()?;
2037 self.parse_rest_of_release()?;
2038 if self.parse_wildcard()? {
2039 return Ok(self.into_pattern());
2040 }
2041 self.parse_pre()?;
2042 self.parse_post()?;
2043 self.parse_dev()?;
2044 self.parse_local()?;
2045 self.bump_while(|byte| byte.is_ascii_whitespace());
2046 if !self.is_done() {
2047 let version = String::from_utf8_lossy(&self.v[..self.i]).into_owned();
2048 let remaining = String::from_utf8_lossy(&self.v[self.i..]).into_owned();
2049 return Err(ErrorKind::UnexpectedEnd { version, remaining }.into());
2050 }
2051 Ok(self.into_pattern())
2052 }
2053
2054 fn parse_fast(&self) -> Option<VersionPattern> {
2064 if let [major, b'.', minor, b'.', patch] = self.v {
2065 let major = major.wrapping_sub(b'0');
2066 let minor = minor.wrapping_sub(b'0');
2067 let patch = patch.wrapping_sub(b'0');
2068 if major <= 9 && minor <= 9 && patch <= 9 {
2069 return Some(Self::from_fast_release([major, minor, patch, 0], 3));
2070 }
2071 }
2072
2073 let (mut prev_digit, mut cur, mut release, mut len) = (false, 0u8, [0u8; 4], 0u8);
2074 for &byte in self.v {
2075 if byte == b'.' {
2076 if !prev_digit {
2077 return None;
2078 }
2079 prev_digit = false;
2080 *release.get_mut(usize::from(len))? = cur;
2081 len += 1;
2082 cur = 0;
2083 } else {
2084 let digit = byte.checked_sub(b'0')?;
2085 if digit > 9 {
2086 return None;
2087 }
2088 prev_digit = true;
2089 cur = cur.checked_mul(10)?.checked_add(digit)?;
2090 }
2091 }
2092 if !prev_digit {
2093 return None;
2094 }
2095 *release.get_mut(usize::from(len))? = cur;
2096 len += 1;
2097 Some(Self::from_fast_release(release, len))
2098 }
2099
2100 fn from_fast_release(release: [u8; 4], len: u8) -> VersionPattern {
2102 let small = VersionSmall {
2103 _force_niche: NonZero::<u8>::MIN,
2104 repr: (u64::from(release[0]) << 48)
2105 | (u64::from(release[1]) << 40)
2106 | (u64::from(release[2]) << 32)
2107 | (u64::from(release[3]) << 24)
2108 | (VersionSmall::SUFFIX_NONE << VersionSmall::SUFFIX_VERSION_BIT_LEN),
2109
2110 len,
2111 };
2112 let inner = VersionInner::Small { small };
2113 let version = Version { inner };
2114 VersionPattern {
2115 version,
2116 wildcard: false,
2117 }
2118 }
2119
2120 fn parse_epoch_and_initial_release(&mut self) -> Result<(), VersionPatternParseError> {
2131 let first_number = self.parse_number()?.ok_or(ErrorKind::NoLeadingNumber)?;
2132 let first_release_number = if self.bump_if("!") {
2133 self.epoch = first_number;
2134 self.parse_number()?
2135 .ok_or(ErrorKind::NoLeadingReleaseNumber)?
2136 } else {
2137 first_number
2138 };
2139 self.release.push(first_release_number);
2140 Ok(())
2141 }
2142
2143 fn parse_rest_of_release(&mut self) -> Result<(), VersionPatternParseError> {
2154 while self.bump_if(".") {
2155 let Some(n) = self.parse_number()? else {
2156 self.unbump();
2157 break;
2158 };
2159 self.release.push(n);
2160 }
2161 Ok(())
2162 }
2163
2164 fn parse_wildcard(&mut self) -> Result<bool, VersionPatternParseError> {
2173 if !self.bump_if(".*") {
2174 return Ok(false);
2175 }
2176 if !self.is_done() {
2177 return Err(PatternErrorKind::WildcardNotTrailing.into());
2178 }
2179 self.wildcard = true;
2180 Ok(true)
2181 }
2182
2183 fn parse_pre(&mut self) -> Result<(), VersionPatternParseError> {
2189 const SPELLINGS: StringSet =
2198 StringSet::new(&["alpha", "beta", "preview", "pre", "rc", "a", "b", "c"]);
2199 const MAP: &[PrereleaseKind] = &[
2200 PrereleaseKind::Alpha,
2201 PrereleaseKind::Beta,
2202 PrereleaseKind::Rc,
2203 PrereleaseKind::Rc,
2204 PrereleaseKind::Rc,
2205 PrereleaseKind::Alpha,
2206 PrereleaseKind::Beta,
2207 PrereleaseKind::Rc,
2208 ];
2209
2210 let oldpos = self.i;
2211 self.bump_if_byte_set(&Parser::SEPARATOR);
2212 let Some(spelling) = self.bump_if_string_set(&SPELLINGS) else {
2213 self.reset(oldpos);
2218 return Ok(());
2219 };
2220 let kind = MAP[spelling];
2221 self.bump_if_byte_set(&Parser::SEPARATOR);
2222 let number = self.parse_number()?.unwrap_or(0);
2225 self.pre = Some(Prerelease { kind, number });
2226 Ok(())
2227 }
2228
2229 fn parse_post(&mut self) -> Result<(), VersionPatternParseError> {
2235 const SPELLINGS: StringSet = StringSet::new(&["post", "rev", "r"]);
2236
2237 let oldpos = self.i;
2238 if self.bump_if("-") {
2239 if let Some(n) = self.parse_number()? {
2240 self.post = Some(n);
2241 return Ok(());
2242 }
2243 self.reset(oldpos);
2244 }
2245 self.bump_if_byte_set(&Parser::SEPARATOR);
2246 if self.bump_if_string_set(&SPELLINGS).is_none() {
2247 self.reset(oldpos);
2251 return Ok(());
2252 }
2253 self.bump_if_byte_set(&Parser::SEPARATOR);
2254 self.post = Some(self.parse_number()?.unwrap_or(0));
2257 Ok(())
2258 }
2259
2260 fn parse_dev(&mut self) -> Result<(), VersionPatternParseError> {
2266 let oldpos = self.i;
2267 self.bump_if_byte_set(&Parser::SEPARATOR);
2268 if !self.bump_if("dev") {
2269 self.reset(oldpos);
2273 return Ok(());
2274 }
2275 self.bump_if_byte_set(&Parser::SEPARATOR);
2276 self.dev = Some(self.parse_number()?.unwrap_or(0));
2279 Ok(())
2280 }
2281
2282 fn parse_local(&mut self) -> Result<(), VersionPatternParseError> {
2290 if !self.bump_if("+") {
2291 return Ok(());
2292 }
2293 let mut precursor = '+';
2294 loop {
2295 let first = self.bump_while(|byte| byte.is_ascii_alphanumeric());
2296 if first.is_empty() {
2297 return Err(ErrorKind::LocalEmpty { precursor }.into());
2298 }
2299 self.local.push(if let Ok(number) = parse_u64(first) {
2300 LocalSegment::Number(number)
2301 } else {
2302 let string = String::from_utf8(first.to_ascii_lowercase())
2303 .expect("ASCII alphanumerics are always valid UTF-8");
2304 LocalSegment::String(string)
2305 });
2306 let Some(byte) = self.bump_if_byte_set(&Parser::SEPARATOR) else {
2307 break;
2308 };
2309 precursor = char::from(byte);
2310 }
2311 Ok(())
2312 }
2313
2314 fn parse_number(&mut self) -> Result<Option<u64>, VersionPatternParseError> {
2322 let digits = self.bump_while(|ch| ch.is_ascii_digit());
2323 if digits.is_empty() {
2324 return Ok(None);
2325 }
2326 let n = parse_u64(digits)?;
2327 if n == u64::MAX {
2333 return Err(ErrorKind::NumberTooBig {
2334 bytes: digits.to_vec(),
2335 }
2336 .into());
2337 }
2338 Ok(Some(n))
2339 }
2340
2341 fn into_pattern(self) -> VersionPattern {
2349 assert!(
2350 self.release.len() > 0,
2351 "version with no release numbers is invalid"
2352 );
2353 let version = Version::new(self.release.as_slice())
2354 .with_epoch(self.epoch)
2355 .with_pre(self.pre)
2356 .with_post(self.post)
2357 .with_dev(self.dev)
2358 .with_local(LocalVersion::Segments(self.local));
2359 VersionPattern {
2360 version,
2361 wildcard: self.wildcard,
2362 }
2363 }
2364
2365 fn bump_while(&mut self, mut predicate: impl FnMut(u8) -> bool) -> &'a [u8] {
2372 let start = self.i;
2373 while !self.is_done() && predicate(self.byte()) {
2374 self.i = self.i.saturating_add(1);
2375 }
2376 &self.v[start..self.i]
2377 }
2378
2379 fn bump_if(&mut self, string: &str) -> bool {
2384 if self.is_done() {
2385 return false;
2386 }
2387 if starts_with_ignore_ascii_case(string.as_bytes(), &self.v[self.i..]) {
2388 self.i = self
2389 .i
2390 .checked_add(string.len())
2391 .expect("valid offset because of prefix");
2392 true
2393 } else {
2394 false
2395 }
2396 }
2397
2398 fn bump_if_string_set(&mut self, set: &StringSet) -> Option<usize> {
2402 let index = set.starts_with(&self.v[self.i..])?;
2403 let found = &set.strings[index];
2404 self.i = self
2405 .i
2406 .checked_add(found.len())
2407 .expect("valid offset because of prefix");
2408 Some(index)
2409 }
2410
2411 fn bump_if_byte_set(&mut self, set: &ByteSet) -> Option<u8> {
2415 let found = set.starts_with(&self.v[self.i..])?;
2416 self.i = self
2417 .i
2418 .checked_add(1)
2419 .expect("valid offset because of prefix");
2420 Some(found)
2421 }
2422
2423 fn unbump(&mut self) {
2432 self.i = self.i.checked_sub(1).expect("not at beginning of input");
2433 }
2434
2435 fn reset(&mut self, offset: usize) {
2441 assert!(offset <= self.v.len());
2442 self.i = offset;
2443 }
2444
2445 fn byte(&self) -> u8 {
2451 self.v[self.i]
2452 }
2453
2454 fn is_done(&self) -> bool {
2456 self.i >= self.v.len()
2457 }
2458}
2459
2460#[derive(Debug)]
2464enum ReleaseNumbers {
2465 Inline { numbers: [u64; 4], len: usize },
2466 Vec(Vec<u64>),
2467}
2468
2469impl ReleaseNumbers {
2470 fn new() -> Self {
2472 Self::Inline {
2473 numbers: [0; 4],
2474 len: 0,
2475 }
2476 }
2477
2478 fn push(&mut self, n: u64) {
2481 match *self {
2482 Self::Inline {
2483 ref mut numbers,
2484 ref mut len,
2485 } => {
2486 assert!(*len <= 4);
2487 if *len == 4 {
2488 let mut numbers = numbers.to_vec();
2489 numbers.push(n);
2490 *self = Self::Vec(numbers);
2491 } else {
2492 numbers[*len] = n;
2493 *len += 1;
2494 }
2495 }
2496 Self::Vec(ref mut numbers) => {
2497 numbers.push(n);
2498 }
2499 }
2500 }
2501
2502 fn len(&self) -> usize {
2504 self.as_slice().len()
2505 }
2506
2507 fn as_slice(&self) -> &[u64] {
2509 match self {
2510 Self::Inline { numbers, len } => &numbers[..*len],
2511 Self::Vec(vec) => vec,
2512 }
2513 }
2514}
2515
2516struct StringSet {
2521 first_byte: ByteSet,
2525 strings: &'static [&'static str],
2527}
2528
2529impl StringSet {
2530 const fn new(strings: &'static [&'static str]) -> Self {
2536 assert!(
2537 strings.len() <= 20,
2538 "only a small number of strings are supported"
2539 );
2540 let (mut firsts, mut firsts_len) = ([0u8; 20], 0);
2541 let mut i = 0;
2542 while i < strings.len() {
2543 assert!(
2544 !strings[i].is_empty(),
2545 "every string in set should be non-empty",
2546 );
2547 firsts[firsts_len] = strings[i].as_bytes()[0];
2548 firsts_len += 1;
2549 i += 1;
2550 }
2551 let first_byte = ByteSet::new(&firsts);
2552 Self {
2553 first_byte,
2554 strings,
2555 }
2556 }
2557
2558 fn starts_with(&self, haystack: &[u8]) -> Option<usize> {
2561 let first_byte = self.first_byte.starts_with(haystack)?;
2562 for (i, &string) in self.strings.iter().enumerate() {
2563 let bytes = string.as_bytes();
2564 if bytes[0].eq_ignore_ascii_case(&first_byte)
2565 && starts_with_ignore_ascii_case(bytes, haystack)
2566 {
2567 return Some(i);
2568 }
2569 }
2570 None
2571 }
2572}
2573
2574struct ByteSet {
2576 set: [bool; 256],
2577}
2578
2579impl ByteSet {
2580 const fn new(bytes: &[u8]) -> Self {
2582 let mut set = [false; 256];
2583 let mut i = 0;
2584 while i < bytes.len() {
2585 set[bytes[i].to_ascii_uppercase() as usize] = true;
2586 set[bytes[i].to_ascii_lowercase() as usize] = true;
2587 i += 1;
2588 }
2589 Self { set }
2590 }
2591
2592 fn starts_with(&self, haystack: &[u8]) -> Option<u8> {
2595 let byte = *haystack.first()?;
2596 if self.contains(byte) {
2597 Some(byte)
2598 } else {
2599 None
2600 }
2601 }
2602
2603 fn contains(&self, byte: u8) -> bool {
2605 self.set[usize::from(byte)]
2606 }
2607}
2608
2609impl std::fmt::Debug for ByteSet {
2610 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2611 let mut set = f.debug_set();
2612 for byte in 0..=255 {
2613 if self.contains(byte) {
2614 set.entry(&char::from(byte));
2615 }
2616 }
2617 set.finish()
2618 }
2619}
2620
2621#[derive(Clone, Debug, Eq, PartialEq)]
2623pub struct VersionParseError {
2624 kind: Box<ErrorKind>,
2625}
2626
2627impl std::error::Error for VersionParseError {}
2628
2629impl std::fmt::Display for VersionParseError {
2630 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2631 match *self.kind {
2632 ErrorKind::Wildcard => write!(f, "wildcards are not allowed in a version"),
2633 ErrorKind::InvalidDigit { got } if got.is_ascii() => {
2634 write!(f, "expected ASCII digit, but found {:?}", char::from(got))
2635 }
2636 ErrorKind::InvalidDigit { got } => {
2637 write!(
2638 f,
2639 "expected ASCII digit, but found non-ASCII byte \\x{got:02X}"
2640 )
2641 }
2642 ErrorKind::NumberTooBig { ref bytes } => {
2643 let string = match std::str::from_utf8(bytes) {
2644 Ok(v) => v,
2645 Err(err) => {
2646 std::str::from_utf8(&bytes[..err.valid_up_to()]).expect("valid UTF-8")
2647 }
2648 };
2649 write!(
2650 f,
2651 "expected number less than or equal to {}, \
2652 but number found in {string:?} exceeds it",
2653 u64::MAX - 1,
2654 )
2655 }
2656 ErrorKind::NoLeadingNumber => {
2657 write!(
2658 f,
2659 "expected version to start with a number, \
2660 but no leading ASCII digits were found"
2661 )
2662 }
2663 ErrorKind::NoLeadingReleaseNumber => {
2664 write!(
2665 f,
2666 "expected version to have a non-empty release component after an epoch, \
2667 but no ASCII digits after the epoch were found"
2668 )
2669 }
2670 ErrorKind::LocalEmpty { precursor } => {
2671 write!(
2672 f,
2673 "found a `{precursor}` indicating the start of a local \
2674 component in a version, but did not find any alphanumeric \
2675 ASCII segment following the `{precursor}`",
2676 )
2677 }
2678 ErrorKind::UnexpectedEnd {
2679 ref version,
2680 ref remaining,
2681 } => {
2682 write!(
2683 f,
2684 "after parsing `{version}`, found `{remaining}`, \
2685 which is not part of a valid version",
2686 )
2687 }
2688 }
2689 }
2690}
2691
2692#[derive(Clone, Debug, Eq, PartialEq)]
2694pub(crate) enum ErrorKind {
2695 Wildcard,
2698 InvalidDigit {
2700 got: u8,
2702 },
2703 NumberTooBig {
2705 bytes: Vec<u8>,
2708 },
2709 NoLeadingNumber,
2711 NoLeadingReleaseNumber,
2713 LocalEmpty {
2717 precursor: char,
2720 },
2721 UnexpectedEnd {
2724 version: String,
2726 remaining: String,
2728 },
2729}
2730
2731impl From<ErrorKind> for VersionParseError {
2732 fn from(kind: ErrorKind) -> Self {
2733 Self {
2734 kind: Box::new(kind),
2735 }
2736 }
2737}
2738
2739#[derive(Clone, Debug, Eq, PartialEq)]
2741pub struct VersionPatternParseError {
2742 kind: Box<PatternErrorKind>,
2743}
2744
2745impl std::error::Error for VersionPatternParseError {}
2746
2747impl std::fmt::Display for VersionPatternParseError {
2748 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2749 match *self.kind {
2750 PatternErrorKind::Version(ref err) => err.fmt(f),
2751 PatternErrorKind::WildcardNotTrailing => {
2752 write!(f, "wildcards in versions must be at the end")
2753 }
2754 }
2755 }
2756}
2757
2758#[derive(Clone, Debug, Eq, PartialEq)]
2760pub(crate) enum PatternErrorKind {
2761 Version(VersionParseError),
2762 WildcardNotTrailing,
2763}
2764
2765impl From<PatternErrorKind> for VersionPatternParseError {
2766 fn from(kind: PatternErrorKind) -> Self {
2767 Self {
2768 kind: Box::new(kind),
2769 }
2770 }
2771}
2772
2773impl From<ErrorKind> for VersionPatternParseError {
2774 fn from(kind: ErrorKind) -> Self {
2775 Self::from(VersionParseError::from(kind))
2776 }
2777}
2778
2779impl From<VersionParseError> for VersionPatternParseError {
2780 fn from(err: VersionParseError) -> Self {
2781 Self {
2782 kind: Box::new(PatternErrorKind::Version(err)),
2783 }
2784 }
2785}
2786
2787fn compare_release(this: &[u64], other: &[u64]) -> Ordering {
2790 if this.len() == other.len() {
2791 return this.cmp(other);
2792 }
2793 for (this, other) in this.iter().chain(std::iter::repeat(&0)).zip(
2796 other
2797 .iter()
2798 .chain(std::iter::repeat(&0))
2799 .take(this.len().max(other.len())),
2800 ) {
2801 match this.cmp(other) {
2802 Ordering::Less => {
2803 return Ordering::Less;
2804 }
2805 Ordering::Equal => {}
2806 Ordering::Greater => {
2807 return Ordering::Greater;
2808 }
2809 }
2810 }
2811 Ordering::Equal
2812}
2813
2814fn sortable_tuple(version: &Version) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2830 sortable_tuple_with(version, version.post(), version.dev())
2831}
2832
2833fn sortable_tuple_with(
2834 version: &Version,
2835 post: Option<u64>,
2836 dev: Option<u64>,
2837) -> (u64, u64, Option<u64>, u64, LocalVersionSlice<'_>) {
2838 let post = if version.max().is_some() {
2840 Some(u64::MAX)
2841 } else {
2842 post
2843 };
2844 match (version.pre(), post, dev, version.min()) {
2845 (_pre, post, _dev, Some(n)) => (0, 0, post, n, version.local()),
2847 (None, None, Some(n), None) => (1, 0, None, n, version.local()),
2849 (
2851 Some(Prerelease {
2852 kind: PrereleaseKind::Alpha,
2853 number: n,
2854 }),
2855 post,
2856 dev,
2857 None,
2858 ) => (2, n, post, dev.unwrap_or(u64::MAX), version.local()),
2859 (
2861 Some(Prerelease {
2862 kind: PrereleaseKind::Beta,
2863 number: n,
2864 }),
2865 post,
2866 dev,
2867 None,
2868 ) => (3, n, post, dev.unwrap_or(u64::MAX), version.local()),
2869 (
2871 Some(Prerelease {
2872 kind: PrereleaseKind::Rc,
2873 number: n,
2874 }),
2875 post,
2876 dev,
2877 None,
2878 ) => (4, n, post, dev.unwrap_or(u64::MAX), version.local()),
2879 (None, None, None, None) => (5, 0, None, 0, version.local()),
2881 (None, Some(post), dev, None) => {
2883 (6, 0, Some(post), dev.unwrap_or(u64::MAX), version.local())
2884 }
2885 }
2886}
2887
2888fn starts_with_ignore_ascii_case(needle: &[u8], haystack: &[u8]) -> bool {
2891 needle.len() <= haystack.len()
2892 && std::iter::zip(needle, haystack).all(|(b1, b2)| b1.eq_ignore_ascii_case(b2))
2893}
2894
2895fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
2910 let mut n: u64 = 0;
2911 for &byte in bytes {
2912 let digit = match byte.checked_sub(b'0') {
2913 None => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2914 Some(digit) if digit > 9 => return Err(ErrorKind::InvalidDigit { got: byte }.into()),
2915 Some(digit) => {
2916 debug_assert!((0..=9).contains(&digit));
2917 u64::from(digit)
2918 }
2919 };
2920 n = n
2921 .checked_mul(10)
2922 .and_then(|n| n.checked_add(digit))
2923 .ok_or_else(|| ErrorKind::NumberTooBig {
2924 bytes: bytes.to_vec(),
2925 })?;
2926 }
2927 Ok(n)
2928}
2929
2930pub static MIN_VERSION: LazyLock<Version> =
2932 LazyLock::new(|| Version::from_str("0a0.dev0").unwrap());
2933
2934#[cfg(test)]
2935mod tests {
2936 use std::str::FromStr;
2937
2938 use crate::VersionSpecifier;
2939
2940 use super::*;
2941
2942 #[test]
2944 fn test_packaging_versions() {
2945 let versions = [
2946 ("1.0.dev456", Version::new([1, 0]).with_dev(Some(456))),
2948 (
2949 "1.0a1",
2950 Version::new([1, 0]).with_pre(Some(Prerelease {
2951 kind: PrereleaseKind::Alpha,
2952 number: 1,
2953 })),
2954 ),
2955 (
2956 "1.0a2.dev456",
2957 Version::new([1, 0])
2958 .with_pre(Some(Prerelease {
2959 kind: PrereleaseKind::Alpha,
2960 number: 2,
2961 }))
2962 .with_dev(Some(456)),
2963 ),
2964 (
2965 "1.0a12.dev456",
2966 Version::new([1, 0])
2967 .with_pre(Some(Prerelease {
2968 kind: PrereleaseKind::Alpha,
2969 number: 12,
2970 }))
2971 .with_dev(Some(456)),
2972 ),
2973 (
2974 "1.0a12",
2975 Version::new([1, 0]).with_pre(Some(Prerelease {
2976 kind: PrereleaseKind::Alpha,
2977 number: 12,
2978 })),
2979 ),
2980 (
2981 "1.0b1.dev456",
2982 Version::new([1, 0])
2983 .with_pre(Some(Prerelease {
2984 kind: PrereleaseKind::Beta,
2985 number: 1,
2986 }))
2987 .with_dev(Some(456)),
2988 ),
2989 (
2990 "1.0b2",
2991 Version::new([1, 0]).with_pre(Some(Prerelease {
2992 kind: PrereleaseKind::Beta,
2993 number: 2,
2994 })),
2995 ),
2996 (
2997 "1.0b2.post345.dev456",
2998 Version::new([1, 0])
2999 .with_pre(Some(Prerelease {
3000 kind: PrereleaseKind::Beta,
3001 number: 2,
3002 }))
3003 .with_dev(Some(456))
3004 .with_post(Some(345)),
3005 ),
3006 (
3007 "1.0b2.post345",
3008 Version::new([1, 0])
3009 .with_pre(Some(Prerelease {
3010 kind: PrereleaseKind::Beta,
3011 number: 2,
3012 }))
3013 .with_post(Some(345)),
3014 ),
3015 (
3016 "1.0b2-346",
3017 Version::new([1, 0])
3018 .with_pre(Some(Prerelease {
3019 kind: PrereleaseKind::Beta,
3020 number: 2,
3021 }))
3022 .with_post(Some(346)),
3023 ),
3024 (
3025 "1.0c1.dev456",
3026 Version::new([1, 0])
3027 .with_pre(Some(Prerelease {
3028 kind: PrereleaseKind::Rc,
3029 number: 1,
3030 }))
3031 .with_dev(Some(456)),
3032 ),
3033 (
3034 "1.0c1",
3035 Version::new([1, 0]).with_pre(Some(Prerelease {
3036 kind: PrereleaseKind::Rc,
3037 number: 1,
3038 })),
3039 ),
3040 (
3041 "1.0rc2",
3042 Version::new([1, 0]).with_pre(Some(Prerelease {
3043 kind: PrereleaseKind::Rc,
3044 number: 2,
3045 })),
3046 ),
3047 (
3048 "1.0c3",
3049 Version::new([1, 0]).with_pre(Some(Prerelease {
3050 kind: PrereleaseKind::Rc,
3051 number: 3,
3052 })),
3053 ),
3054 ("1.0", Version::new([1, 0])),
3055 (
3056 "1.0.post456.dev34",
3057 Version::new([1, 0]).with_post(Some(456)).with_dev(Some(34)),
3058 ),
3059 ("1.0.post456", Version::new([1, 0]).with_post(Some(456))),
3060 ("1.1.dev1", Version::new([1, 1]).with_dev(Some(1))),
3061 (
3062 "1.2+123abc",
3063 Version::new([1, 2])
3064 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3065 ),
3066 (
3067 "1.2+123abc456",
3068 Version::new([1, 2])
3069 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3070 ),
3071 (
3072 "1.2+abc",
3073 Version::new([1, 2])
3074 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3075 ),
3076 (
3077 "1.2+abc123",
3078 Version::new([1, 2])
3079 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3080 ),
3081 (
3082 "1.2+abc123def",
3083 Version::new([1, 2])
3084 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3085 ),
3086 (
3087 "1.2+1234.abc",
3088 Version::new([1, 2]).with_local_segments(vec![
3089 LocalSegment::Number(1234),
3090 LocalSegment::String("abc".to_string()),
3091 ]),
3092 ),
3093 (
3094 "1.2+123456",
3095 Version::new([1, 2]).with_local_segments(vec![LocalSegment::Number(123_456)]),
3096 ),
3097 (
3098 "1.2.r32+123456",
3099 Version::new([1, 2])
3100 .with_post(Some(32))
3101 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3102 ),
3103 (
3104 "1.2.rev33+123456",
3105 Version::new([1, 2])
3106 .with_post(Some(33))
3107 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3108 ),
3109 (
3111 "1!1.0.dev456",
3112 Version::new([1, 0]).with_epoch(1).with_dev(Some(456)),
3113 ),
3114 (
3115 "1!1.0a1",
3116 Version::new([1, 0])
3117 .with_epoch(1)
3118 .with_pre(Some(Prerelease {
3119 kind: PrereleaseKind::Alpha,
3120 number: 1,
3121 })),
3122 ),
3123 (
3124 "1!1.0a2.dev456",
3125 Version::new([1, 0])
3126 .with_epoch(1)
3127 .with_pre(Some(Prerelease {
3128 kind: PrereleaseKind::Alpha,
3129 number: 2,
3130 }))
3131 .with_dev(Some(456)),
3132 ),
3133 (
3134 "1!1.0a12.dev456",
3135 Version::new([1, 0])
3136 .with_epoch(1)
3137 .with_pre(Some(Prerelease {
3138 kind: PrereleaseKind::Alpha,
3139 number: 12,
3140 }))
3141 .with_dev(Some(456)),
3142 ),
3143 (
3144 "1!1.0a12",
3145 Version::new([1, 0])
3146 .with_epoch(1)
3147 .with_pre(Some(Prerelease {
3148 kind: PrereleaseKind::Alpha,
3149 number: 12,
3150 })),
3151 ),
3152 (
3153 "1!1.0b1.dev456",
3154 Version::new([1, 0])
3155 .with_epoch(1)
3156 .with_pre(Some(Prerelease {
3157 kind: PrereleaseKind::Beta,
3158 number: 1,
3159 }))
3160 .with_dev(Some(456)),
3161 ),
3162 (
3163 "1!1.0b2",
3164 Version::new([1, 0])
3165 .with_epoch(1)
3166 .with_pre(Some(Prerelease {
3167 kind: PrereleaseKind::Beta,
3168 number: 2,
3169 })),
3170 ),
3171 (
3172 "1!1.0b2.post345.dev456",
3173 Version::new([1, 0])
3174 .with_epoch(1)
3175 .with_pre(Some(Prerelease {
3176 kind: PrereleaseKind::Beta,
3177 number: 2,
3178 }))
3179 .with_post(Some(345))
3180 .with_dev(Some(456)),
3181 ),
3182 (
3183 "1!1.0b2.post345",
3184 Version::new([1, 0])
3185 .with_epoch(1)
3186 .with_pre(Some(Prerelease {
3187 kind: PrereleaseKind::Beta,
3188 number: 2,
3189 }))
3190 .with_post(Some(345)),
3191 ),
3192 (
3193 "1!1.0b2-346",
3194 Version::new([1, 0])
3195 .with_epoch(1)
3196 .with_pre(Some(Prerelease {
3197 kind: PrereleaseKind::Beta,
3198 number: 2,
3199 }))
3200 .with_post(Some(346)),
3201 ),
3202 (
3203 "1!1.0c1.dev456",
3204 Version::new([1, 0])
3205 .with_epoch(1)
3206 .with_pre(Some(Prerelease {
3207 kind: PrereleaseKind::Rc,
3208 number: 1,
3209 }))
3210 .with_dev(Some(456)),
3211 ),
3212 (
3213 "1!1.0c1",
3214 Version::new([1, 0])
3215 .with_epoch(1)
3216 .with_pre(Some(Prerelease {
3217 kind: PrereleaseKind::Rc,
3218 number: 1,
3219 })),
3220 ),
3221 (
3222 "1!1.0rc2",
3223 Version::new([1, 0])
3224 .with_epoch(1)
3225 .with_pre(Some(Prerelease {
3226 kind: PrereleaseKind::Rc,
3227 number: 2,
3228 })),
3229 ),
3230 (
3231 "1!1.0c3",
3232 Version::new([1, 0])
3233 .with_epoch(1)
3234 .with_pre(Some(Prerelease {
3235 kind: PrereleaseKind::Rc,
3236 number: 3,
3237 })),
3238 ),
3239 ("1!1.0", Version::new([1, 0]).with_epoch(1)),
3240 (
3241 "1!1.0.post456.dev34",
3242 Version::new([1, 0])
3243 .with_epoch(1)
3244 .with_post(Some(456))
3245 .with_dev(Some(34)),
3246 ),
3247 (
3248 "1!1.0.post456",
3249 Version::new([1, 0]).with_epoch(1).with_post(Some(456)),
3250 ),
3251 (
3252 "1!1.1.dev1",
3253 Version::new([1, 1]).with_epoch(1).with_dev(Some(1)),
3254 ),
3255 (
3256 "1!1.2+123abc",
3257 Version::new([1, 2])
3258 .with_epoch(1)
3259 .with_local_segments(vec![LocalSegment::String("123abc".to_string())]),
3260 ),
3261 (
3262 "1!1.2+123abc456",
3263 Version::new([1, 2])
3264 .with_epoch(1)
3265 .with_local_segments(vec![LocalSegment::String("123abc456".to_string())]),
3266 ),
3267 (
3268 "1!1.2+abc",
3269 Version::new([1, 2])
3270 .with_epoch(1)
3271 .with_local_segments(vec![LocalSegment::String("abc".to_string())]),
3272 ),
3273 (
3274 "1!1.2+abc123",
3275 Version::new([1, 2])
3276 .with_epoch(1)
3277 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
3278 ),
3279 (
3280 "1!1.2+abc123def",
3281 Version::new([1, 2])
3282 .with_epoch(1)
3283 .with_local_segments(vec![LocalSegment::String("abc123def".to_string())]),
3284 ),
3285 (
3286 "1!1.2+1234.abc",
3287 Version::new([1, 2]).with_epoch(1).with_local_segments(vec![
3288 LocalSegment::Number(1234),
3289 LocalSegment::String("abc".to_string()),
3290 ]),
3291 ),
3292 (
3293 "1!1.2+123456",
3294 Version::new([1, 2])
3295 .with_epoch(1)
3296 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3297 ),
3298 (
3299 "1!1.2.r32+123456",
3300 Version::new([1, 2])
3301 .with_epoch(1)
3302 .with_post(Some(32))
3303 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3304 ),
3305 (
3306 "1!1.2.rev33+123456",
3307 Version::new([1, 2])
3308 .with_epoch(1)
3309 .with_post(Some(33))
3310 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3311 ),
3312 (
3313 "98765!1.2.rev33+123456",
3314 Version::new([1, 2])
3315 .with_epoch(98765)
3316 .with_post(Some(33))
3317 .with_local_segments(vec![LocalSegment::Number(123_456)]),
3318 ),
3319 ];
3320 for (string, structured) in versions {
3321 match Version::from_str(string) {
3322 Err(err) => {
3323 unreachable!(
3324 "expected {string:?} to parse as {structured:?}, but got {err:?}",
3325 structured = structured.as_bloated_debug(),
3326 )
3327 }
3328 Ok(v) => assert!(
3329 v == structured,
3330 "for {string:?}, expected {structured:?} but got {v:?}",
3331 structured = structured.as_bloated_debug(),
3332 v = v.as_bloated_debug(),
3333 ),
3334 }
3335 let spec = format!("=={string}");
3336 match VersionSpecifier::from_str(&spec) {
3337 Err(err) => {
3338 unreachable!(
3339 "expected version in {spec:?} to parse as {structured:?}, but got {err:?}",
3340 structured = structured.as_bloated_debug(),
3341 )
3342 }
3343 Ok(v) => assert!(
3344 v.version() == &structured,
3345 "for {string:?}, expected {structured:?} but got {v:?}",
3346 structured = structured.as_bloated_debug(),
3347 v = v.version.as_bloated_debug(),
3348 ),
3349 }
3350 }
3351 }
3352
3353 #[test]
3355 fn test_packaging_failures() {
3356 let versions = [
3357 "1.0+a+",
3359 "1.0++",
3360 "1.0+_foobar",
3361 "1.0+foo&asd",
3362 "1.0+1+1",
3363 "french toast",
3365 "==french toast",
3366 ];
3367 for version in versions {
3368 assert!(Version::from_str(version).is_err());
3369 assert!(VersionSpecifier::from_str(&format!("=={version}")).is_err());
3370 }
3371 }
3372
3373 #[test]
3374 fn test_equality_and_normalization() {
3375 let versions = [
3376 ("1.0dev", "1.0.dev0"),
3378 ("1.0.dev", "1.0.dev0"),
3379 ("1.0dev1", "1.0.dev1"),
3380 ("1.0dev", "1.0.dev0"),
3381 ("1.0-dev", "1.0.dev0"),
3382 ("1.0-dev1", "1.0.dev1"),
3383 ("1.0DEV", "1.0.dev0"),
3384 ("1.0.DEV", "1.0.dev0"),
3385 ("1.0DEV1", "1.0.dev1"),
3386 ("1.0DEV", "1.0.dev0"),
3387 ("1.0.DEV1", "1.0.dev1"),
3388 ("1.0-DEV", "1.0.dev0"),
3389 ("1.0-DEV1", "1.0.dev1"),
3390 ("1.0a", "1.0a0"),
3392 ("1.0.a", "1.0a0"),
3393 ("1.0.a1", "1.0a1"),
3394 ("1.0-a", "1.0a0"),
3395 ("1.0-a1", "1.0a1"),
3396 ("1.0alpha", "1.0a0"),
3397 ("1.0.alpha", "1.0a0"),
3398 ("1.0.alpha1", "1.0a1"),
3399 ("1.0-alpha", "1.0a0"),
3400 ("1.0-alpha1", "1.0a1"),
3401 ("1.0A", "1.0a0"),
3402 ("1.0.A", "1.0a0"),
3403 ("1.0.A1", "1.0a1"),
3404 ("1.0-A", "1.0a0"),
3405 ("1.0-A1", "1.0a1"),
3406 ("1.0ALPHA", "1.0a0"),
3407 ("1.0.ALPHA", "1.0a0"),
3408 ("1.0.ALPHA1", "1.0a1"),
3409 ("1.0-ALPHA", "1.0a0"),
3410 ("1.0-ALPHA1", "1.0a1"),
3411 ("1.0b", "1.0b0"),
3413 ("1.0.b", "1.0b0"),
3414 ("1.0.b1", "1.0b1"),
3415 ("1.0-b", "1.0b0"),
3416 ("1.0-b1", "1.0b1"),
3417 ("1.0beta", "1.0b0"),
3418 ("1.0.beta", "1.0b0"),
3419 ("1.0.beta1", "1.0b1"),
3420 ("1.0-beta", "1.0b0"),
3421 ("1.0-beta1", "1.0b1"),
3422 ("1.0B", "1.0b0"),
3423 ("1.0.B", "1.0b0"),
3424 ("1.0.B1", "1.0b1"),
3425 ("1.0-B", "1.0b0"),
3426 ("1.0-B1", "1.0b1"),
3427 ("1.0BETA", "1.0b0"),
3428 ("1.0.BETA", "1.0b0"),
3429 ("1.0.BETA1", "1.0b1"),
3430 ("1.0-BETA", "1.0b0"),
3431 ("1.0-BETA1", "1.0b1"),
3432 ("1.0c", "1.0rc0"),
3434 ("1.0.c", "1.0rc0"),
3435 ("1.0.c1", "1.0rc1"),
3436 ("1.0-c", "1.0rc0"),
3437 ("1.0-c1", "1.0rc1"),
3438 ("1.0rc", "1.0rc0"),
3439 ("1.0.rc", "1.0rc0"),
3440 ("1.0.rc1", "1.0rc1"),
3441 ("1.0-rc", "1.0rc0"),
3442 ("1.0-rc1", "1.0rc1"),
3443 ("1.0C", "1.0rc0"),
3444 ("1.0.C", "1.0rc0"),
3445 ("1.0.C1", "1.0rc1"),
3446 ("1.0-C", "1.0rc0"),
3447 ("1.0-C1", "1.0rc1"),
3448 ("1.0RC", "1.0rc0"),
3449 ("1.0.RC", "1.0rc0"),
3450 ("1.0.RC1", "1.0rc1"),
3451 ("1.0-RC", "1.0rc0"),
3452 ("1.0-RC1", "1.0rc1"),
3453 ("1.0post", "1.0.post0"),
3455 ("1.0.post", "1.0.post0"),
3456 ("1.0post1", "1.0.post1"),
3457 ("1.0post", "1.0.post0"),
3458 ("1.0-post", "1.0.post0"),
3459 ("1.0-post1", "1.0.post1"),
3460 ("1.0POST", "1.0.post0"),
3461 ("1.0.POST", "1.0.post0"),
3462 ("1.0POST1", "1.0.post1"),
3463 ("1.0POST", "1.0.post0"),
3464 ("1.0r", "1.0.post0"),
3465 ("1.0rev", "1.0.post0"),
3466 ("1.0.POST1", "1.0.post1"),
3467 ("1.0.r1", "1.0.post1"),
3468 ("1.0.rev1", "1.0.post1"),
3469 ("1.0-POST", "1.0.post0"),
3470 ("1.0-POST1", "1.0.post1"),
3471 ("1.0-5", "1.0.post5"),
3472 ("1.0-r5", "1.0.post5"),
3473 ("1.0-rev5", "1.0.post5"),
3474 ("1.0+AbC", "1.0+abc"),
3476 ("1.01", "1.1"),
3478 ("1.0a05", "1.0a5"),
3479 ("1.0b07", "1.0b7"),
3480 ("1.0c056", "1.0rc56"),
3481 ("1.0rc09", "1.0rc9"),
3482 ("1.0.post000", "1.0.post0"),
3483 ("1.1.dev09000", "1.1.dev9000"),
3484 ("00!1.2", "1.2"),
3485 ("0100!0.0", "100!0.0"),
3486 ("v1.0", "1.0"),
3488 (" v1.0\t\n", "1.0"),
3489 ];
3490 for (version_str, normalized_str) in versions {
3491 let version = Version::from_str(version_str).unwrap();
3492 let normalized = Version::from_str(normalized_str).unwrap();
3493 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3495 assert_eq!(
3497 version.to_string(),
3498 normalized.to_string(),
3499 "{version_str} {normalized_str}"
3500 );
3501 }
3502 }
3503
3504 #[test]
3506 fn test_equality_and_normalization2() {
3507 let versions = [
3508 ("1.0.dev456", "1.0.dev456"),
3509 ("1.0a1", "1.0a1"),
3510 ("1.0a2.dev456", "1.0a2.dev456"),
3511 ("1.0a12.dev456", "1.0a12.dev456"),
3512 ("1.0a12", "1.0a12"),
3513 ("1.0b1.dev456", "1.0b1.dev456"),
3514 ("1.0b2", "1.0b2"),
3515 ("1.0b2.post345.dev456", "1.0b2.post345.dev456"),
3516 ("1.0b2.post345", "1.0b2.post345"),
3517 ("1.0rc1.dev456", "1.0rc1.dev456"),
3518 ("1.0rc1", "1.0rc1"),
3519 ("1.0", "1.0"),
3520 ("1.0.post456.dev34", "1.0.post456.dev34"),
3521 ("1.0.post456", "1.0.post456"),
3522 ("1.0.1", "1.0.1"),
3523 ("0!1.0.2", "1.0.2"),
3524 ("1.0.3+7", "1.0.3+7"),
3525 ("0!1.0.4+8.0", "1.0.4+8.0"),
3526 ("1.0.5+9.5", "1.0.5+9.5"),
3527 ("1.2+1234.abc", "1.2+1234.abc"),
3528 ("1.2+123456", "1.2+123456"),
3529 ("1.2+123abc", "1.2+123abc"),
3530 ("1.2+123abc456", "1.2+123abc456"),
3531 ("1.2+abc", "1.2+abc"),
3532 ("1.2+abc123", "1.2+abc123"),
3533 ("1.2+abc123def", "1.2+abc123def"),
3534 ("1.1.dev1", "1.1.dev1"),
3535 ("7!1.0.dev456", "7!1.0.dev456"),
3536 ("7!1.0a1", "7!1.0a1"),
3537 ("7!1.0a2.dev456", "7!1.0a2.dev456"),
3538 ("7!1.0a12.dev456", "7!1.0a12.dev456"),
3539 ("7!1.0a12", "7!1.0a12"),
3540 ("7!1.0b1.dev456", "7!1.0b1.dev456"),
3541 ("7!1.0b2", "7!1.0b2"),
3542 ("7!1.0b2.post345.dev456", "7!1.0b2.post345.dev456"),
3543 ("7!1.0b2.post345", "7!1.0b2.post345"),
3544 ("7!1.0rc1.dev456", "7!1.0rc1.dev456"),
3545 ("7!1.0rc1", "7!1.0rc1"),
3546 ("7!1.0", "7!1.0"),
3547 ("7!1.0.post456.dev34", "7!1.0.post456.dev34"),
3548 ("7!1.0.post456", "7!1.0.post456"),
3549 ("7!1.0.1", "7!1.0.1"),
3550 ("7!1.0.2", "7!1.0.2"),
3551 ("7!1.0.3+7", "7!1.0.3+7"),
3552 ("7!1.0.4+8.0", "7!1.0.4+8.0"),
3553 ("7!1.0.5+9.5", "7!1.0.5+9.5"),
3554 ("7!1.1.dev1", "7!1.1.dev1"),
3555 ];
3556 for (version_str, normalized_str) in versions {
3557 let version = Version::from_str(version_str).unwrap();
3558 let normalized = Version::from_str(normalized_str).unwrap();
3559 assert_eq!(version, normalized, "{version_str} {normalized_str}");
3560 assert_eq!(
3562 version.to_string(),
3563 normalized_str,
3564 "{version_str} {normalized_str}"
3565 );
3566 assert_eq!(
3568 version.to_string(),
3569 normalized.to_string(),
3570 "{version_str} {normalized_str}"
3571 );
3572 }
3573 }
3574
3575 #[test]
3576 fn test_star_fixed_version() {
3577 let result = Version::from_str("0.9.1.*");
3578 assert_eq!(result.unwrap_err(), ErrorKind::Wildcard.into());
3579 }
3580
3581 #[test]
3582 fn test_invalid_word() {
3583 let result = Version::from_str("blergh");
3584 assert_eq!(result.unwrap_err(), ErrorKind::NoLeadingNumber.into());
3585 }
3586
3587 #[test]
3588 fn test_from_version_star() {
3589 let p = |s: &str| -> Result<VersionPattern, _> { s.parse() };
3590 assert!(!p("1.2.3").unwrap().is_wildcard());
3591 assert!(p("1.2.3.*").unwrap().is_wildcard());
3592 assert_eq!(
3593 p("1.2.*.4.*").unwrap_err(),
3594 PatternErrorKind::WildcardNotTrailing.into(),
3595 );
3596 assert_eq!(
3597 p("1.0-dev1.*").unwrap_err(),
3598 ErrorKind::UnexpectedEnd {
3599 version: "1.0-dev1".to_string(),
3600 remaining: ".*".to_string()
3601 }
3602 .into(),
3603 );
3604 assert_eq!(
3605 p("1.0a1.*").unwrap_err(),
3606 ErrorKind::UnexpectedEnd {
3607 version: "1.0a1".to_string(),
3608 remaining: ".*".to_string()
3609 }
3610 .into(),
3611 );
3612 assert_eq!(
3613 p("1.0.post1.*").unwrap_err(),
3614 ErrorKind::UnexpectedEnd {
3615 version: "1.0.post1".to_string(),
3616 remaining: ".*".to_string()
3617 }
3618 .into(),
3619 );
3620 assert_eq!(
3621 p("1.0+lolwat.*").unwrap_err(),
3622 ErrorKind::LocalEmpty { precursor: '.' }.into(),
3623 );
3624 }
3625
3626 #[test]
3632 fn parse_version_valid() {
3633 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3634 Ok(v) => v,
3635 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
3636 };
3637
3638 assert_eq!(p("5"), Version::new([5]));
3640 assert_eq!(p("5.6"), Version::new([5, 6]));
3641 assert_eq!(p("5.6.7"), Version::new([5, 6, 7]));
3642 assert_eq!(p("512.623.734"), Version::new([512, 623, 734]));
3643 assert_eq!(p("1.2.3.4"), Version::new([1, 2, 3, 4]));
3644 assert_eq!(p("1.2.3.4.5"), Version::new([1, 2, 3, 4, 5]));
3645
3646 assert_eq!(p("4!5"), Version::new([5]).with_epoch(4));
3648 assert_eq!(p("4!5.6"), Version::new([5, 6]).with_epoch(4));
3649
3650 assert_eq!(
3652 p("5a1"),
3653 Version::new([5]).with_pre(Some(Prerelease {
3654 kind: PrereleaseKind::Alpha,
3655 number: 1
3656 }))
3657 );
3658 assert_eq!(
3659 p("5alpha1"),
3660 Version::new([5]).with_pre(Some(Prerelease {
3661 kind: PrereleaseKind::Alpha,
3662 number: 1
3663 }))
3664 );
3665 assert_eq!(
3666 p("5b1"),
3667 Version::new([5]).with_pre(Some(Prerelease {
3668 kind: PrereleaseKind::Beta,
3669 number: 1
3670 }))
3671 );
3672 assert_eq!(
3673 p("5beta1"),
3674 Version::new([5]).with_pre(Some(Prerelease {
3675 kind: PrereleaseKind::Beta,
3676 number: 1
3677 }))
3678 );
3679 assert_eq!(
3680 p("5rc1"),
3681 Version::new([5]).with_pre(Some(Prerelease {
3682 kind: PrereleaseKind::Rc,
3683 number: 1
3684 }))
3685 );
3686 assert_eq!(
3687 p("5c1"),
3688 Version::new([5]).with_pre(Some(Prerelease {
3689 kind: PrereleaseKind::Rc,
3690 number: 1
3691 }))
3692 );
3693 assert_eq!(
3694 p("5preview1"),
3695 Version::new([5]).with_pre(Some(Prerelease {
3696 kind: PrereleaseKind::Rc,
3697 number: 1
3698 }))
3699 );
3700 assert_eq!(
3701 p("5pre1"),
3702 Version::new([5]).with_pre(Some(Prerelease {
3703 kind: PrereleaseKind::Rc,
3704 number: 1
3705 }))
3706 );
3707 assert_eq!(
3708 p("5.6.7pre1"),
3709 Version::new([5, 6, 7]).with_pre(Some(Prerelease {
3710 kind: PrereleaseKind::Rc,
3711 number: 1
3712 }))
3713 );
3714 assert_eq!(
3715 p("5alpha789"),
3716 Version::new([5]).with_pre(Some(Prerelease {
3717 kind: PrereleaseKind::Alpha,
3718 number: 789
3719 }))
3720 );
3721 assert_eq!(
3722 p("5.alpha789"),
3723 Version::new([5]).with_pre(Some(Prerelease {
3724 kind: PrereleaseKind::Alpha,
3725 number: 789
3726 }))
3727 );
3728 assert_eq!(
3729 p("5-alpha789"),
3730 Version::new([5]).with_pre(Some(Prerelease {
3731 kind: PrereleaseKind::Alpha,
3732 number: 789
3733 }))
3734 );
3735 assert_eq!(
3736 p("5_alpha789"),
3737 Version::new([5]).with_pre(Some(Prerelease {
3738 kind: PrereleaseKind::Alpha,
3739 number: 789
3740 }))
3741 );
3742 assert_eq!(
3743 p("5alpha.789"),
3744 Version::new([5]).with_pre(Some(Prerelease {
3745 kind: PrereleaseKind::Alpha,
3746 number: 789
3747 }))
3748 );
3749 assert_eq!(
3750 p("5alpha-789"),
3751 Version::new([5]).with_pre(Some(Prerelease {
3752 kind: PrereleaseKind::Alpha,
3753 number: 789
3754 }))
3755 );
3756 assert_eq!(
3757 p("5alpha_789"),
3758 Version::new([5]).with_pre(Some(Prerelease {
3759 kind: PrereleaseKind::Alpha,
3760 number: 789
3761 }))
3762 );
3763 assert_eq!(
3764 p("5ALPHA789"),
3765 Version::new([5]).with_pre(Some(Prerelease {
3766 kind: PrereleaseKind::Alpha,
3767 number: 789
3768 }))
3769 );
3770 assert_eq!(
3771 p("5aLpHa789"),
3772 Version::new([5]).with_pre(Some(Prerelease {
3773 kind: PrereleaseKind::Alpha,
3774 number: 789
3775 }))
3776 );
3777 assert_eq!(
3778 p("5alpha"),
3779 Version::new([5]).with_pre(Some(Prerelease {
3780 kind: PrereleaseKind::Alpha,
3781 number: 0
3782 }))
3783 );
3784
3785 assert_eq!(p("5post2"), Version::new([5]).with_post(Some(2)));
3787 assert_eq!(p("5rev2"), Version::new([5]).with_post(Some(2)));
3788 assert_eq!(p("5r2"), Version::new([5]).with_post(Some(2)));
3789 assert_eq!(p("5.post2"), Version::new([5]).with_post(Some(2)));
3790 assert_eq!(p("5-post2"), Version::new([5]).with_post(Some(2)));
3791 assert_eq!(p("5_post2"), Version::new([5]).with_post(Some(2)));
3792 assert_eq!(p("5.post.2"), Version::new([5]).with_post(Some(2)));
3793 assert_eq!(p("5.post-2"), Version::new([5]).with_post(Some(2)));
3794 assert_eq!(p("5.post_2"), Version::new([5]).with_post(Some(2)));
3795 assert_eq!(
3796 p("5.6.7.post_2"),
3797 Version::new([5, 6, 7]).with_post(Some(2))
3798 );
3799 assert_eq!(p("5-2"), Version::new([5]).with_post(Some(2)));
3800 assert_eq!(p("5.6.7-2"), Version::new([5, 6, 7]).with_post(Some(2)));
3801 assert_eq!(p("5POST2"), Version::new([5]).with_post(Some(2)));
3802 assert_eq!(p("5PoSt2"), Version::new([5]).with_post(Some(2)));
3803 assert_eq!(p("5post"), Version::new([5]).with_post(Some(0)));
3804
3805 assert_eq!(p("5dev2"), Version::new([5]).with_dev(Some(2)));
3807 assert_eq!(p("5.dev2"), Version::new([5]).with_dev(Some(2)));
3808 assert_eq!(p("5-dev2"), Version::new([5]).with_dev(Some(2)));
3809 assert_eq!(p("5_dev2"), Version::new([5]).with_dev(Some(2)));
3810 assert_eq!(p("5.dev.2"), Version::new([5]).with_dev(Some(2)));
3811 assert_eq!(p("5.dev-2"), Version::new([5]).with_dev(Some(2)));
3812 assert_eq!(p("5.dev_2"), Version::new([5]).with_dev(Some(2)));
3813 assert_eq!(p("5.6.7.dev_2"), Version::new([5, 6, 7]).with_dev(Some(2)));
3814 assert_eq!(p("5DEV2"), Version::new([5]).with_dev(Some(2)));
3815 assert_eq!(p("5dEv2"), Version::new([5]).with_dev(Some(2)));
3816 assert_eq!(p("5DeV2"), Version::new([5]).with_dev(Some(2)));
3817 assert_eq!(p("5dev"), Version::new([5]).with_dev(Some(0)));
3818
3819 assert_eq!(
3821 p("5+2"),
3822 Version::new([5]).with_local_segments(vec![LocalSegment::Number(2)])
3823 );
3824 assert_eq!(
3825 p("5+a"),
3826 Version::new([5]).with_local_segments(vec![LocalSegment::String("a".to_string())])
3827 );
3828 assert_eq!(
3829 p("5+abc.123"),
3830 Version::new([5]).with_local_segments(vec![
3831 LocalSegment::String("abc".to_string()),
3832 LocalSegment::Number(123),
3833 ])
3834 );
3835 assert_eq!(
3836 p("5+123.abc"),
3837 Version::new([5]).with_local_segments(vec![
3838 LocalSegment::Number(123),
3839 LocalSegment::String("abc".to_string()),
3840 ])
3841 );
3842 assert_eq!(
3843 p("5+18446744073709551615.abc"),
3844 Version::new([5]).with_local_segments(vec![
3845 LocalSegment::Number(18_446_744_073_709_551_615),
3846 LocalSegment::String("abc".to_string()),
3847 ])
3848 );
3849 assert_eq!(
3850 p("5+18446744073709551616.abc"),
3851 Version::new([5]).with_local_segments(vec![
3852 LocalSegment::String("18446744073709551616".to_string()),
3853 LocalSegment::String("abc".to_string()),
3854 ])
3855 );
3856 assert_eq!(
3857 p("5+ABC.123"),
3858 Version::new([5]).with_local_segments(vec![
3859 LocalSegment::String("abc".to_string()),
3860 LocalSegment::Number(123),
3861 ])
3862 );
3863 assert_eq!(
3864 p("5+ABC-123.4_5_xyz-MNO"),
3865 Version::new([5]).with_local_segments(vec![
3866 LocalSegment::String("abc".to_string()),
3867 LocalSegment::Number(123),
3868 LocalSegment::Number(4),
3869 LocalSegment::Number(5),
3870 LocalSegment::String("xyz".to_string()),
3871 LocalSegment::String("mno".to_string()),
3872 ])
3873 );
3874 assert_eq!(
3875 p("5.6.7+abc-00123"),
3876 Version::new([5, 6, 7]).with_local_segments(vec![
3877 LocalSegment::String("abc".to_string()),
3878 LocalSegment::Number(123),
3879 ])
3880 );
3881 assert_eq!(
3882 p("5.6.7+abc-foo00123"),
3883 Version::new([5, 6, 7]).with_local_segments(vec![
3884 LocalSegment::String("abc".to_string()),
3885 LocalSegment::String("foo00123".to_string()),
3886 ])
3887 );
3888 assert_eq!(
3889 p("5.6.7+abc-00123a"),
3890 Version::new([5, 6, 7]).with_local_segments(vec![
3891 LocalSegment::String("abc".to_string()),
3892 LocalSegment::String("00123a".to_string()),
3893 ])
3894 );
3895
3896 assert_eq!(
3898 p("5a2post3"),
3899 Version::new([5])
3900 .with_pre(Some(Prerelease {
3901 kind: PrereleaseKind::Alpha,
3902 number: 2
3903 }))
3904 .with_post(Some(3))
3905 );
3906 assert_eq!(
3907 p("5.a-2_post-3"),
3908 Version::new([5])
3909 .with_pre(Some(Prerelease {
3910 kind: PrereleaseKind::Alpha,
3911 number: 2
3912 }))
3913 .with_post(Some(3))
3914 );
3915 assert_eq!(
3916 p("5a2-3"),
3917 Version::new([5])
3918 .with_pre(Some(Prerelease {
3919 kind: PrereleaseKind::Alpha,
3920 number: 2
3921 }))
3922 .with_post(Some(3))
3923 );
3924
3925 assert_eq!(p("v5"), Version::new([5]));
3927 assert_eq!(p("V5"), Version::new([5]));
3928 assert_eq!(p("v5.6.7"), Version::new([5, 6, 7]));
3929
3930 assert_eq!(p(" v5 "), Version::new([5]));
3932 assert_eq!(p(" 5 "), Version::new([5]));
3933 assert_eq!(
3934 p(" 5.6.7+abc.123.xyz "),
3935 Version::new([5, 6, 7]).with_local_segments(vec![
3936 LocalSegment::String("abc".to_string()),
3937 LocalSegment::Number(123),
3938 LocalSegment::String("xyz".to_string())
3939 ])
3940 );
3941 assert_eq!(p(" \n5\n \t"), Version::new([5]));
3942
3943 assert!(Parser::new("1.min0".as_bytes()).parse().is_err());
3945 }
3946
3947 #[test]
3955 fn parse_version_invalid() {
3956 let p = |s: &str| match Parser::new(s.as_bytes()).parse() {
3957 Err(err) => err,
3958 Ok(v) => unreachable!(
3959 "expected version parser error, but got: {v:?}",
3960 v = v.as_bloated_debug()
3961 ),
3962 };
3963
3964 assert_eq!(p(""), ErrorKind::NoLeadingNumber.into());
3965 assert_eq!(p("a"), ErrorKind::NoLeadingNumber.into());
3966 assert_eq!(p("v 5"), ErrorKind::NoLeadingNumber.into());
3967 assert_eq!(p("V 5"), ErrorKind::NoLeadingNumber.into());
3968 assert_eq!(p("x 5"), ErrorKind::NoLeadingNumber.into());
3969 assert_eq!(
3970 p("18446744073709551616"),
3971 ErrorKind::NumberTooBig {
3972 bytes: b"18446744073709551616".to_vec()
3973 }
3974 .into()
3975 );
3976 assert_eq!(p("5!"), ErrorKind::NoLeadingReleaseNumber.into());
3977 assert_eq!(
3978 p("5.6./"),
3979 ErrorKind::UnexpectedEnd {
3980 version: "5.6".to_string(),
3981 remaining: "./".to_string()
3982 }
3983 .into()
3984 );
3985 assert_eq!(
3986 p("5.6.-alpha2"),
3987 ErrorKind::UnexpectedEnd {
3988 version: "5.6".to_string(),
3989 remaining: ".-alpha2".to_string()
3990 }
3991 .into()
3992 );
3993 assert_eq!(
3994 p("1.2.3a18446744073709551616"),
3995 ErrorKind::NumberTooBig {
3996 bytes: b"18446744073709551616".to_vec()
3997 }
3998 .into()
3999 );
4000 assert_eq!(p("5+"), ErrorKind::LocalEmpty { precursor: '+' }.into());
4001 assert_eq!(p("5+ "), ErrorKind::LocalEmpty { precursor: '+' }.into());
4002 assert_eq!(p("5+abc."), ErrorKind::LocalEmpty { precursor: '.' }.into());
4003 assert_eq!(p("5+abc-"), ErrorKind::LocalEmpty { precursor: '-' }.into());
4004 assert_eq!(p("5+abc_"), ErrorKind::LocalEmpty { precursor: '_' }.into());
4005 assert_eq!(
4006 p("5+abc. "),
4007 ErrorKind::LocalEmpty { precursor: '.' }.into()
4008 );
4009 assert_eq!(
4010 p("5.6-"),
4011 ErrorKind::UnexpectedEnd {
4012 version: "5.6".to_string(),
4013 remaining: "-".to_string()
4014 }
4015 .into()
4016 );
4017 }
4018
4019 #[test]
4022 fn parse_version_single_digit_release() {
4023 for major in 0u8..=9 {
4024 for minor in 0u8..=9 {
4025 for patch in 0u8..=9 {
4026 let input = format!("{major}.{minor}.{patch}");
4027 assert_eq!(
4028 input.parse(),
4029 Ok(Version::new([
4030 u64::from(major),
4031 u64::from(minor),
4032 u64::from(patch),
4033 ])),
4034 "{input}"
4035 );
4036 }
4037 }
4038 }
4039
4040 assert!("a.1.2".parse::<Version>().is_err());
4041 assert_eq!(
4042 "1.a.2"
4043 .parse::<Version>()
4044 .map(|version| version.to_string()),
4045 Ok("1a2".to_string())
4046 );
4047 assert_eq!(
4048 "1.2.a"
4049 .parse::<Version>()
4050 .map(|version| version.to_string()),
4051 Ok("1.2a0".to_string())
4052 );
4053 }
4054
4055 #[test]
4056 fn parse_version_pattern_valid() {
4057 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
4058 Ok(v) => v,
4059 Err(err) => unreachable!("expected valid version, but got error: {err:?}"),
4060 };
4061
4062 assert_eq!(p("5.*"), VersionPattern::wildcard(Version::new([5])));
4063 assert_eq!(p("5.6.*"), VersionPattern::wildcard(Version::new([5, 6])));
4064 assert_eq!(
4065 p("2!5.6.*"),
4066 VersionPattern::wildcard(Version::new([5, 6]).with_epoch(2))
4067 );
4068 }
4069
4070 #[test]
4071 fn parse_version_pattern_invalid() {
4072 let p = |s: &str| match Parser::new(s.as_bytes()).parse_pattern() {
4073 Err(err) => err,
4074 Ok(vpat) => unreachable!("expected version pattern parser error, but got: {vpat:?}"),
4075 };
4076
4077 assert_eq!(p("*"), ErrorKind::NoLeadingNumber.into());
4078 assert_eq!(p("2!*"), ErrorKind::NoLeadingReleaseNumber.into());
4079 }
4080
4081 #[test]
4086 fn ordering() {
4087 let versions = &[
4088 "1.dev0",
4089 "1.0.dev456",
4090 "1.0a1",
4091 "1.0a2.dev456",
4092 "1.0a12.dev456",
4093 "1.0a12",
4094 "1.0b1.dev456",
4095 "1.0b2",
4096 "1.0b2.post345.dev456",
4097 "1.0b2.post345",
4098 "1.0rc1.dev456",
4099 "1.0rc1",
4100 "1.0",
4101 "1.0+abc.5",
4102 "1.0+abc.7",
4103 "1.0+5",
4104 "1.0.post456.dev34",
4105 "1.0.post456",
4106 "1.0.15",
4107 "1.1.dev1",
4108 ];
4109 for (i, v1) in versions.iter().enumerate() {
4110 for v2 in &versions[i + 1..] {
4111 let less = v1.parse::<Version>().unwrap();
4112 let greater = v2.parse::<Version>().unwrap();
4113 assert_eq!(
4114 less.cmp(&greater),
4115 Ordering::Less,
4116 "less: {:?}\ngreater: {:?}",
4117 less.as_bloated_debug(),
4118 greater.as_bloated_debug()
4119 );
4120 }
4121 }
4122 }
4123
4124 #[test]
4125 fn local_sentinel_version() {
4126 let sentinel = Version::new([1, 0]).with_local(LocalVersion::Max);
4127
4128 let versions = &["1.0.post0", "1.1"];
4130
4131 for greater in versions {
4132 let greater = greater.parse::<Version>().unwrap();
4133 assert_eq!(
4134 sentinel.cmp(&greater),
4135 Ordering::Less,
4136 "less: {:?}\ngreater: {:?}",
4137 greater.as_bloated_debug(),
4138 sentinel.as_bloated_debug(),
4139 );
4140 }
4141
4142 let versions = &["1.0", "1.0.a0", "1.0+local"];
4144
4145 for less in versions {
4146 let less = less.parse::<Version>().unwrap();
4147 assert_eq!(
4148 sentinel.cmp(&less),
4149 Ordering::Greater,
4150 "less: {:?}\ngreater: {:?}",
4151 sentinel.as_bloated_debug(),
4152 less.as_bloated_debug()
4153 );
4154 }
4155 }
4156
4157 #[test]
4158 fn min_version() {
4159 let less = Version::new([1, 0]).with_min(Some(0));
4161
4162 let versions = &[
4163 "1.dev0",
4164 "1.0.dev456",
4165 "1.0a1",
4166 "1.0a2.dev456",
4167 "1.0a12.dev456",
4168 "1.0a12",
4169 "1.0b1.dev456",
4170 "1.0b2",
4171 "1.0b2.post345.dev456",
4172 "1.0b2.post345",
4173 "1.0rc1.dev456",
4174 "1.0rc1",
4175 "1.0",
4176 "1.0+abc.5",
4177 "1.0+abc.7",
4178 "1.0+5",
4179 "1.0.post456.dev34",
4180 "1.0.post456",
4181 "1.0.15",
4182 "1.1.dev1",
4183 ];
4184
4185 for greater in versions {
4186 let greater = greater.parse::<Version>().unwrap();
4187 assert_eq!(
4188 less.cmp(&greater),
4189 Ordering::Less,
4190 "less: {:?}\ngreater: {:?}",
4191 less.as_bloated_debug(),
4192 greater.as_bloated_debug()
4193 );
4194 }
4195 }
4196
4197 #[test]
4198 fn max_version() {
4199 let greater = Version::new([1, 0]).with_max(Some(0));
4201
4202 let versions = &[
4203 "1.dev0",
4204 "1.0.dev456",
4205 "1.0a1",
4206 "1.0a2.dev456",
4207 "1.0a12.dev456",
4208 "1.0a12",
4209 "1.0b1.dev456",
4210 "1.0b2",
4211 "1.0b2.post345.dev456",
4212 "1.0b2.post345",
4213 "1.0rc1.dev456",
4214 "1.0rc1",
4215 "1.0",
4216 "1.0+abc.5",
4217 "1.0+abc.7",
4218 "1.0+5",
4219 "1.0.post456.dev34",
4220 "1.0.post456",
4221 "1.0",
4222 ];
4223
4224 for less in versions {
4225 let less = less.parse::<Version>().unwrap();
4226 assert_eq!(
4227 less.cmp(&greater),
4228 Ordering::Less,
4229 "less: {:?}\ngreater: {:?}",
4230 less.as_bloated_debug(),
4231 greater.as_bloated_debug()
4232 );
4233 }
4234
4235 let greater = Version::new([1, 0])
4237 .with_pre(Some(Prerelease {
4238 kind: PrereleaseKind::Alpha,
4239 number: 1,
4240 }))
4241 .with_max(Some(0));
4242
4243 let versions = &["1.0a1", "1.0a1+local", "1.0a1.post1"];
4244
4245 for less in versions {
4246 let less = less.parse::<Version>().unwrap();
4247 assert_eq!(
4248 less.cmp(&greater),
4249 Ordering::Less,
4250 "less: {:?}\ngreater: {:?}",
4251 less.as_bloated_debug(),
4252 greater.as_bloated_debug()
4253 );
4254 }
4255
4256 let less = Version::new([1, 0])
4258 .with_pre(Some(Prerelease {
4259 kind: PrereleaseKind::Alpha,
4260 number: 1,
4261 }))
4262 .with_max(Some(0));
4263
4264 let versions = &["1.0b1", "1.0b1+local", "1.0b1.post1", "1.0"];
4265
4266 for greater in versions {
4267 let greater = greater.parse::<Version>().unwrap();
4268 assert_eq!(
4269 less.cmp(&greater),
4270 Ordering::Less,
4271 "less: {:?}\ngreater: {:?}",
4272 less.as_bloated_debug(),
4273 greater.as_bloated_debug()
4274 );
4275 }
4276 }
4277
4278 #[test]
4280 fn parse_number_u64() {
4281 let p = |s: &str| parse_u64(s.as_bytes());
4282 assert_eq!(p("0"), Ok(0));
4283 assert_eq!(p("00"), Ok(0));
4284 assert_eq!(p("1"), Ok(1));
4285 assert_eq!(p("01"), Ok(1));
4286 assert_eq!(p("9"), Ok(9));
4287 assert_eq!(p("10"), Ok(10));
4288 assert_eq!(p("18446744073709551615"), Ok(18_446_744_073_709_551_615));
4289 assert_eq!(p("018446744073709551615"), Ok(18_446_744_073_709_551_615));
4290 assert_eq!(
4291 p("000000018446744073709551615"),
4292 Ok(18_446_744_073_709_551_615)
4293 );
4294
4295 assert_eq!(p("10a"), Err(ErrorKind::InvalidDigit { got: b'a' }.into()));
4296 assert_eq!(p("10["), Err(ErrorKind::InvalidDigit { got: b'[' }.into()));
4297 assert_eq!(p("10/"), Err(ErrorKind::InvalidDigit { got: b'/' }.into()));
4298 assert_eq!(
4300 p("18446744073709551616"),
4301 Err(ErrorKind::NumberTooBig {
4302 bytes: b"18446744073709551616".to_vec()
4303 }
4304 .into())
4305 );
4306 assert_eq!(
4307 p("18446744073799551615abc"),
4308 Err(ErrorKind::NumberTooBig {
4309 bytes: b"18446744073799551615abc".to_vec()
4310 }
4311 .into())
4312 );
4313 assert_eq!(
4314 parse_u64(b"18446744073799551615\xFF"),
4315 Err(ErrorKind::NumberTooBig {
4316 bytes: b"18446744073799551615\xFF".to_vec()
4317 }
4318 .into())
4319 );
4320 }
4321
4322 impl Version {
4323 pub(crate) fn as_bloated_debug(&self) -> impl std::fmt::Debug + '_ {
4333 std::fmt::from_fn(|f| {
4334 f.debug_struct("Version")
4335 .field("epoch", &self.epoch())
4336 .field("release", &&*self.release())
4337 .field("pre", &self.pre())
4338 .field("post", &self.post())
4339 .field("dev", &self.dev())
4340 .field("local", &self.local())
4341 .field("min", &self.min())
4342 .field("max", &self.max())
4343 .finish()
4344 })
4345 }
4346 }
4347
4348 #[test]
4352 fn preserve_trailing_zeros() {
4353 let v1: Version = "1.2.0".parse().unwrap();
4354 assert_eq!(&*v1.release(), &[1, 2, 0]);
4355 assert_eq!(v1.to_string(), "1.2.0");
4356
4357 let v2: Version = "1.2".parse().unwrap();
4358 assert_eq!(&*v2.release(), &[1, 2]);
4359 assert_eq!(v2.to_string(), "1.2");
4360 }
4361
4362 #[test]
4363 fn only_release_at_precision_preserves_epoch_and_discards_suffixes() {
4364 let version = "1!2.3rc1.post2.dev3+local"
4365 .parse::<Version>()
4366 .expect("valid version");
4367 assert_eq!(
4368 version
4369 .only_release_at_precision(4)
4370 .expect("non-zero precision")
4371 .to_string(),
4372 "1!2.3.0.0"
4373 );
4374 assert_eq!(version.only_release_at_precision(0), None);
4375 }
4376
4377 #[test]
4378 fn only_release_trimmed_discards_non_release_segments() {
4379 for version in ["1.2a1", "1.2.post1", "1!1.2", "1.2+local", "1.2.dev1"] {
4380 let version = version.parse::<Version>().unwrap();
4381 assert_eq!(version.only_release_trimmed(), Version::new([1, 2]));
4382 }
4383
4384 assert_eq!(
4385 Version::new([1, 2])
4386 .with_min(Some(0))
4387 .only_release_trimmed(),
4388 Version::new([1, 2])
4389 );
4390 assert_eq!(
4391 Version::new([1, 2])
4392 .with_max(Some(0))
4393 .only_release_trimmed(),
4394 Version::new([1, 2])
4395 );
4396 assert_eq!(
4397 Version::new([1, 2, 0]).only_release_trimmed(),
4398 Version::new([1, 2])
4399 );
4400 assert_eq!(
4401 Version::new([1, 2]).only_release_trimmed(),
4402 Version::new([1, 2])
4403 );
4404 }
4405
4406 #[test]
4407 fn type_size() {
4408 assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
4409 assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
4410 #[cfg(feature = "rkyv")]
4411 {
4412 assert_eq!(size_of::<rkyv::Archived<VersionSmall>>(), 16);
4413 assert_eq!(size_of::<rkyv::Archived<Version>>(), 24);
4414 }
4415 }
4416
4417 #[test]
4420 fn bump_major() {
4421 let mut version = "0".parse::<Version>().unwrap();
4423 version.bump(BumpCommand::BumpRelease {
4424 index: 0,
4425 value: None,
4426 });
4427 assert_eq!(version.to_string().as_str(), "1");
4428
4429 let mut version = "1.5".parse::<Version>().unwrap();
4431 version.bump(BumpCommand::BumpRelease {
4432 index: 0,
4433 value: None,
4434 });
4435 assert_eq!(version.to_string().as_str(), "2.0");
4436
4437 let mut version = "0.1.2".parse::<Version>().unwrap();
4439 version.bump(BumpCommand::BumpRelease {
4440 index: 0,
4441 value: None,
4442 });
4443 assert_eq!(version.to_string().as_str(), "1.0.0");
4444
4445 let mut version = "1.2.3".parse::<Version>().unwrap();
4447 version.bump(BumpCommand::BumpRelease {
4448 index: 0,
4449 value: None,
4450 });
4451 assert_eq!(version.to_string().as_str(), "2.0.0");
4452
4453 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4455 version.bump(BumpCommand::BumpRelease {
4456 index: 0,
4457 value: None,
4458 });
4459 assert_eq!(version.to_string().as_str(), "2.0.0.0");
4460
4461 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4463 .parse::<Version>()
4464 .unwrap();
4465 version.bump(BumpCommand::BumpRelease {
4466 index: 0,
4467 value: None,
4468 });
4469 assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
4470 version.bump(BumpCommand::BumpRelease {
4471 index: 0,
4472 value: None,
4473 });
4474 assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
4475 }
4476
4477 #[test]
4480 fn bump_minor() {
4481 let mut version = "0".parse::<Version>().unwrap();
4483 version.bump(BumpCommand::BumpRelease {
4484 index: 1,
4485 value: None,
4486 });
4487 assert_eq!(version.to_string().as_str(), "0.1");
4488
4489 let mut version = "1.5".parse::<Version>().unwrap();
4491 version.bump(BumpCommand::BumpRelease {
4492 index: 1,
4493 value: None,
4494 });
4495 assert_eq!(version.to_string().as_str(), "1.6");
4496
4497 let mut version = "5.3.6".parse::<Version>().unwrap();
4499 version.bump(BumpCommand::BumpRelease {
4500 index: 1,
4501 value: None,
4502 });
4503 assert_eq!(version.to_string().as_str(), "5.4.0");
4504
4505 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4507 version.bump(BumpCommand::BumpRelease {
4508 index: 1,
4509 value: None,
4510 });
4511 assert_eq!(version.to_string().as_str(), "1.3.0.0");
4512
4513 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4515 .parse::<Version>()
4516 .unwrap();
4517 version.bump(BumpCommand::BumpRelease {
4518 index: 1,
4519 value: None,
4520 });
4521 assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
4522 version.bump(BumpCommand::BumpRelease {
4523 index: 1,
4524 value: None,
4525 });
4526 assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
4527 }
4528
4529 #[test]
4532 fn bump_patch() {
4533 let mut version = "0".parse::<Version>().unwrap();
4535 version.bump(BumpCommand::BumpRelease {
4536 index: 2,
4537 value: None,
4538 });
4539 assert_eq!(version.to_string().as_str(), "0.0.1");
4540
4541 let mut version = "1.5".parse::<Version>().unwrap();
4543 version.bump(BumpCommand::BumpRelease {
4544 index: 2,
4545 value: None,
4546 });
4547 assert_eq!(version.to_string().as_str(), "1.5.1");
4548
4549 let mut version = "5.3.6".parse::<Version>().unwrap();
4551 version.bump(BumpCommand::BumpRelease {
4552 index: 2,
4553 value: None,
4554 });
4555 assert_eq!(version.to_string().as_str(), "5.3.7");
4556
4557 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4559 version.bump(BumpCommand::BumpRelease {
4560 index: 2,
4561 value: None,
4562 });
4563 assert_eq!(version.to_string().as_str(), "1.2.4.0");
4564
4565 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4567 .parse::<Version>()
4568 .unwrap();
4569 version.bump(BumpCommand::BumpRelease {
4570 index: 2,
4571 value: None,
4572 });
4573 assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
4574 version.bump(BumpCommand::BumpRelease {
4575 index: 2,
4576 value: None,
4577 });
4578 assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
4579 }
4580
4581 #[test]
4584 fn bump_alpha() {
4585 let mut version = "0".parse::<Version>().unwrap();
4587 version.bump(BumpCommand::BumpPrerelease {
4588 kind: PrereleaseKind::Alpha,
4589 value: None,
4590 });
4591 assert_eq!(version.to_string().as_str(), "0a1");
4592
4593 let mut version = "1.5".parse::<Version>().unwrap();
4595 version.bump(BumpCommand::BumpPrerelease {
4596 kind: PrereleaseKind::Alpha,
4597 value: None,
4598 });
4599 assert_eq!(version.to_string().as_str(), "1.5a1");
4600
4601 let mut version = "5.3.6".parse::<Version>().unwrap();
4603 version.bump(BumpCommand::BumpPrerelease {
4604 kind: PrereleaseKind::Alpha,
4605 value: None,
4606 });
4607 assert_eq!(version.to_string().as_str(), "5.3.6a1");
4608
4609 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4611 version.bump(BumpCommand::BumpPrerelease {
4612 kind: PrereleaseKind::Alpha,
4613 value: None,
4614 });
4615 assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
4616
4617 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4619 .parse::<Version>()
4620 .unwrap();
4621 version.bump(BumpCommand::BumpPrerelease {
4622 kind: PrereleaseKind::Alpha,
4623 value: None,
4624 });
4625 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
4626 version.bump(BumpCommand::BumpPrerelease {
4627 kind: PrereleaseKind::Alpha,
4628 value: None,
4629 });
4630 assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
4631 }
4632
4633 #[test]
4636 fn bump_beta() {
4637 let mut version = "0".parse::<Version>().unwrap();
4639 version.bump(BumpCommand::BumpPrerelease {
4640 kind: PrereleaseKind::Beta,
4641 value: None,
4642 });
4643 assert_eq!(version.to_string().as_str(), "0b1");
4644
4645 let mut version = "1.5".parse::<Version>().unwrap();
4647 version.bump(BumpCommand::BumpPrerelease {
4648 kind: PrereleaseKind::Beta,
4649 value: None,
4650 });
4651 assert_eq!(version.to_string().as_str(), "1.5b1");
4652
4653 let mut version = "5.3.6".parse::<Version>().unwrap();
4655 version.bump(BumpCommand::BumpPrerelease {
4656 kind: PrereleaseKind::Beta,
4657 value: None,
4658 });
4659 assert_eq!(version.to_string().as_str(), "5.3.6b1");
4660
4661 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4663 version.bump(BumpCommand::BumpPrerelease {
4664 kind: PrereleaseKind::Beta,
4665 value: None,
4666 });
4667 assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
4668
4669 let mut version = "5!1.7.3.5a2.post345.dev456+local"
4671 .parse::<Version>()
4672 .unwrap();
4673 version.bump(BumpCommand::BumpPrerelease {
4674 kind: PrereleaseKind::Beta,
4675 value: None,
4676 });
4677 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
4678 version.bump(BumpCommand::BumpPrerelease {
4679 kind: PrereleaseKind::Beta,
4680 value: None,
4681 });
4682 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
4683 }
4684
4685 #[test]
4688 fn bump_rc() {
4689 let mut version = "0".parse::<Version>().unwrap();
4691 version.bump(BumpCommand::BumpPrerelease {
4692 kind: PrereleaseKind::Rc,
4693 value: None,
4694 });
4695 assert_eq!(version.to_string().as_str(), "0rc1");
4696
4697 let mut version = "1.5".parse::<Version>().unwrap();
4699 version.bump(BumpCommand::BumpPrerelease {
4700 kind: PrereleaseKind::Rc,
4701 value: None,
4702 });
4703 assert_eq!(version.to_string().as_str(), "1.5rc1");
4704
4705 let mut version = "5.3.6".parse::<Version>().unwrap();
4707 version.bump(BumpCommand::BumpPrerelease {
4708 kind: PrereleaseKind::Rc,
4709 value: None,
4710 });
4711 assert_eq!(version.to_string().as_str(), "5.3.6rc1");
4712
4713 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4715 version.bump(BumpCommand::BumpPrerelease {
4716 kind: PrereleaseKind::Rc,
4717 value: None,
4718 });
4719 assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
4720
4721 let mut version = "5!1.7.3.5b2.post345.dev456+local"
4723 .parse::<Version>()
4724 .unwrap();
4725 version.bump(BumpCommand::BumpPrerelease {
4726 kind: PrereleaseKind::Rc,
4727 value: None,
4728 });
4729 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
4730 version.bump(BumpCommand::BumpPrerelease {
4731 kind: PrereleaseKind::Rc,
4732 value: None,
4733 });
4734 assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
4735 }
4736
4737 #[test]
4740 fn bump_post() {
4741 let mut version = "0".parse::<Version>().unwrap();
4743 version.bump(BumpCommand::BumpPost { value: None });
4744 assert_eq!(version.to_string().as_str(), "0.post1");
4745
4746 let mut version = "1.5".parse::<Version>().unwrap();
4748 version.bump(BumpCommand::BumpPost { value: None });
4749 assert_eq!(version.to_string().as_str(), "1.5.post1");
4750
4751 let mut version = "5.3.6".parse::<Version>().unwrap();
4753 version.bump(BumpCommand::BumpPost { value: None });
4754 assert_eq!(version.to_string().as_str(), "5.3.6.post1");
4755
4756 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4758 version.bump(BumpCommand::BumpPost { value: None });
4759 assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
4760
4761 let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
4763 version.bump(BumpCommand::BumpPost { value: None });
4764 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
4765 version.bump(BumpCommand::BumpPost { value: None });
4766 assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
4767 }
4768
4769 #[test]
4772 fn bump_dev() {
4773 let mut version = "0".parse::<Version>().unwrap();
4775 version.bump(BumpCommand::BumpDev { value: None });
4776 assert_eq!(version.to_string().as_str(), "0.dev1");
4777
4778 let mut version = "1.5".parse::<Version>().unwrap();
4780 version.bump(BumpCommand::BumpDev { value: None });
4781 assert_eq!(version.to_string().as_str(), "1.5.dev1");
4782
4783 let mut version = "5.3.6".parse::<Version>().unwrap();
4785 version.bump(BumpCommand::BumpDev { value: None });
4786 assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
4787
4788 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4790 version.bump(BumpCommand::BumpDev { value: None });
4791 assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
4792
4793 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4795 version.bump(BumpCommand::BumpDev { value: None });
4796 assert_eq!(
4797 version.to_string().as_str(),
4798 "5!1.7.3.5b2.post345.dev1+local"
4799 );
4800 version.bump(BumpCommand::BumpDev { value: None });
4801 assert_eq!(
4802 version.to_string().as_str(),
4803 "5!1.7.3.5b2.post345.dev2+local"
4804 );
4805 }
4806
4807 #[test]
4810 fn make_stable() {
4811 let mut version = "0".parse::<Version>().unwrap();
4813 version.bump(BumpCommand::MakeStable);
4814 assert_eq!(version.to_string().as_str(), "0");
4815
4816 let mut version = "1.5".parse::<Version>().unwrap();
4818 version.bump(BumpCommand::MakeStable);
4819 assert_eq!(version.to_string().as_str(), "1.5");
4820
4821 let mut version = "5.3.6".parse::<Version>().unwrap();
4823 version.bump(BumpCommand::MakeStable);
4824 assert_eq!(version.to_string().as_str(), "5.3.6");
4825
4826 let mut version = "1.2.3.4".parse::<Version>().unwrap();
4828 version.bump(BumpCommand::MakeStable);
4829 assert_eq!(version.to_string().as_str(), "1.2.3.4");
4830
4831 let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
4833 version.bump(BumpCommand::MakeStable);
4834 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4835 version.bump(BumpCommand::MakeStable);
4836 assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
4837 }
4838}