1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! The `version` module gives you tools to create and compare SemVer-compliant
14 use std
::cmp
::{self, Ordering}
;
17 use std
::error
::Error
;
24 #[cfg(feature = "serde")]
25 use serde
::ser
::{Serialize, Serializer}
;
26 #[cfg(feature = "serde")]
27 use serde
::de
::{self, Deserialize, Deserializer, Visitor}
;
29 /// An identifier in the pre-release or build metadata.
31 /// See sections 9 and 10 of the spec for more about pre-release identifers and
33 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
35 /// An identifier that's solely numbers.
37 /// An identifier with letters and numbers.
41 impl From
<semver_parser
::version
::Identifier
> for Identifier
{
42 fn from(other
: semver_parser
::version
::Identifier
) -> Identifier
{
44 semver_parser
::version
::Identifier
::Numeric(n
) => Identifier
::Numeric(n
),
45 semver_parser
::version
::Identifier
::AlphaNumeric(s
) => Identifier
::AlphaNumeric(s
),
50 impl fmt
::Display
for Identifier
{
52 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
54 Identifier
::Numeric(ref n
) => fmt
::Display
::fmt(n
, f
),
55 Identifier
::AlphaNumeric(ref s
) => fmt
::Display
::fmt(s
, f
),
60 #[cfg(feature = "serde")]
61 impl Serialize
for Identifier
{
62 fn serialize
<S
>(&self, serializer
: S
) -> result
::Result
<S
::Ok
, S
::Error
>
65 // Serialize Identifier as a number or string.
67 Identifier
::Numeric(n
) => serializer
.serialize_u64(n
),
68 Identifier
::AlphaNumeric(ref s
) => serializer
.serialize_str(s
),
73 #[cfg(feature = "serde")]
74 impl<'de
> Deserialize
<'de
> for Identifier
{
75 fn deserialize
<D
>(deserializer
: D
) -> result
::Result
<Self, D
::Error
>
76 where D
: Deserializer
<'de
>
78 struct IdentifierVisitor
;
80 // Deserialize Identifier from a number or string.
81 impl<'de
> Visitor
<'de
> for IdentifierVisitor
{
82 type Value
= Identifier
;
84 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
85 formatter
.write_str("a SemVer pre-release or build identifier")
88 fn visit_u64
<E
>(self, numeric
: u64) -> result
::Result
<Self::Value
, E
>
91 Ok(Identifier
::Numeric(numeric
))
94 fn visit_str
<E
>(self, alphanumeric
: &str) -> result
::Result
<Self::Value
, E
>
97 Ok(Identifier
::AlphaNumeric(alphanumeric
.to_owned()))
101 deserializer
.deserialize_any(IdentifierVisitor
)
105 /// Represents a version number conforming to the semantic versioning scheme.
106 #[derive(Clone, Eq, Debug)]
108 /// The major version, to be incremented on incompatible changes.
110 /// The minor version, to be incremented when functionality is added in a
111 /// backwards-compatible manner.
113 /// The patch version, to be incremented when backwards-compatible bug
116 /// The pre-release version identifier, if one exists.
117 pub pre
: Vec
<Identifier
>,
118 /// The build metadata, ignored when determining version precedence.
119 pub build
: Vec
<Identifier
>,
122 impl From
<semver_parser
::version
::Version
> for Version
{
123 fn from(other
: semver_parser
::version
::Version
) -> Version
{
128 pre
: other
.pre
.into_iter().map(From
::from
).collect(),
129 build
: other
.build
.into_iter().map(From
::from
).collect(),
134 #[cfg(feature = "serde")]
135 impl Serialize
for Version
{
136 fn serialize
<S
>(&self, serializer
: S
) -> result
::Result
<S
::Ok
, S
::Error
>
139 // Serialize Version as a string.
140 serializer
.collect_str(self)
144 #[cfg(feature = "serde")]
145 impl<'de
> Deserialize
<'de
> for Version
{
146 fn deserialize
<D
>(deserializer
: D
) -> result
::Result
<Self, D
::Error
>
147 where D
: Deserializer
<'de
>
149 struct VersionVisitor
;
151 // Deserialize Version from a string.
152 impl<'de
> Visitor
<'de
> for VersionVisitor
{
153 type Value
= Version
;
155 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
156 formatter
.write_str("a SemVer version as a string")
159 fn visit_str
<E
>(self, v
: &str) -> result
::Result
<Self::Value
, E
>
162 Version
::parse(v
).map_err(de
::Error
::custom
)
166 deserializer
.deserialize_str(VersionVisitor
)
170 /// An error type for this crate
172 /// Currently, just a generic error. Will make this nicer later.
173 #[derive(Clone,PartialEq,Debug,PartialOrd)]
174 pub enum SemVerError
{
175 /// An error ocurred while parsing.
179 impl fmt
::Display
for SemVerError
{
180 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
182 &SemVerError
::ParseError(ref m
) => write
!(f
, "{}", m
),
187 impl Error
for SemVerError
{
188 fn description(&self) -> &str {
190 &SemVerError
::ParseError(ref m
) => m
,
195 /// A Result type for errors
196 pub type Result
<T
> = result
::Result
<T
, SemVerError
>;
200 /// Contructs the simple case without pre or build.
201 pub fn new(major
: u64, minor
: u64, patch
: u64) -> Version
{
211 /// Parse a string into a semver object.
212 pub fn parse(version
: &str) -> Result
<Version
> {
213 let res
= semver_parser
::version
::parse(version
);
216 // Convert plain String error into proper ParseError
217 Err(e
) => Err(SemVerError
::ParseError(e
)),
218 Ok(v
) => Ok(From
::from(v
)),
222 /// Clears the build metadata
223 fn clear_metadata(&mut self) {
224 self.build
= Vec
::new();
225 self.pre
= Vec
::new();
228 /// Increments the patch number for this Version (Must be mutable)
229 pub fn increment_patch(&mut self) {
231 self.clear_metadata();
234 /// Increments the minor version number for this Version (Must be mutable)
236 /// As instructed by section 7 of the spec, the patch number is reset to 0.
237 pub fn increment_minor(&mut self) {
240 self.clear_metadata();
243 /// Increments the major version number for this Version (Must be mutable)
245 /// As instructed by section 8 of the spec, the minor and patch numbers are
247 pub fn increment_major(&mut self) {
251 self.clear_metadata();
254 /// Checks to see if the current Version is in pre-release status
255 pub fn is_prerelease(&self) -> bool
{
260 impl str::FromStr
for Version
{
261 type Err
= SemVerError
;
263 fn from_str(s
: &str) -> Result
<Version
> {
268 impl fmt
::Display
for Version
{
270 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
271 try
!(write
!(f
, "{}.{}.{}", self.major
, self.minor
, self.patch
));
272 if !self.pre
.is_empty() {
273 try
!(write
!(f
, "-"));
274 for (i
, x
) in self.pre
.iter().enumerate() {
278 try
!(write
!(f
, "{}", x
));
281 if !self.build
.is_empty() {
282 try
!(write
!(f
, "+"));
283 for (i
, x
) in self.build
.iter().enumerate() {
287 try
!(write
!(f
, "{}", x
));
294 impl cmp
::PartialEq
for Version
{
296 fn eq(&self, other
: &Version
) -> bool
{
297 // We should ignore build metadata here, otherwise versions v1 and v2
298 // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
299 // violate strict total ordering rules.
300 self.major
== other
.major
&& self.minor
== other
.minor
&& self.patch
== other
.patch
&&
301 self.pre
== other
.pre
305 impl cmp
::PartialOrd
for Version
{
306 fn partial_cmp(&self, other
: &Version
) -> Option
<Ordering
> {
307 Some(self.cmp(other
))
311 impl cmp
::Ord
for Version
{
312 fn cmp(&self, other
: &Version
) -> Ordering
{
313 match self.major
.cmp(&other
.major
) {
314 Ordering
::Equal
=> {}
318 match self.minor
.cmp(&other
.minor
) {
319 Ordering
::Equal
=> {}
323 match self.patch
.cmp(&other
.patch
) {
324 Ordering
::Equal
=> {}
328 // NB: semver spec says 0.0.0-pre < 0.0.0
329 // but the version of ord defined for vec
330 // says that [] < [pre] so we alter it here
331 match (self.pre
.len(), other
.pre
.len()) {
332 (0, 0) => Ordering
::Equal
,
333 (0, _
) => Ordering
::Greater
,
334 (_
, 0) => Ordering
::Less
,
335 (_
, _
) => self.pre
.cmp(&other
.pre
),
340 impl hash
::Hash
for Version
{
341 fn hash
<H
: hash
::Hasher
>(&self, into
: &mut H
) {
342 self.major
.hash(into
);
343 self.minor
.hash(into
);
344 self.patch
.hash(into
);
349 impl From
<(u64,u64,u64)> for Version
{
350 fn from(tuple
: (u64,u64,u64)) -> Version
{
351 let (major
, minor
, patch
) = tuple
;
352 Version
::new(major
, minor
, patch
)
360 use super::Identifier
;
361 use super::SemVerError
;
365 fn parse_error(e
: &str) -> result
::Result
<Version
, SemVerError
> {
366 return Err(SemVerError
::ParseError(e
.to_string()));
369 assert_eq
!(Version
::parse(""),
370 parse_error("Error parsing major identifier"));
371 assert_eq
!(Version
::parse(" "),
372 parse_error("Error parsing major identifier"));
373 assert_eq
!(Version
::parse("1"),
374 parse_error("Expected dot"));
375 assert_eq
!(Version
::parse("1.2"),
376 parse_error("Expected dot"));
377 assert_eq
!(Version
::parse("1.2.3-"),
378 parse_error("Error parsing prerelease"));
379 assert_eq
!(Version
::parse("a.b.c"),
380 parse_error("Error parsing major identifier"));
381 assert_eq
!(Version
::parse("1.2.3 abc"),
382 parse_error("Extra junk after valid version: abc"));
384 assert_eq
!(Version
::parse("1.2.3"),
393 assert_eq
!(Version
::parse("1.2.3"),
394 Ok(Version
::new(1,2,3)));
396 assert_eq
!(Version
::parse(" 1.2.3 "),
404 assert_eq
!(Version
::parse("1.2.3-alpha1"),
409 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
412 assert_eq
!(Version
::parse(" 1.2.3-alpha1 "),
417 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
420 assert_eq
!(Version
::parse("1.2.3+build5"),
426 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
428 assert_eq
!(Version
::parse(" 1.2.3+build5 "),
434 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
436 assert_eq
!(Version
::parse("1.2.3-alpha1+build5"),
441 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
442 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
444 assert_eq
!(Version
::parse(" 1.2.3-alpha1+build5 "),
449 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
450 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
452 assert_eq
!(Version
::parse("1.2.3-1.alpha1.9+build5.7.3aedf "),
457 pre
: vec
![Identifier
::Numeric(1),
458 Identifier
::AlphaNumeric(String
::from("alpha1")),
459 Identifier
::Numeric(9),
461 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5")),
462 Identifier
::Numeric(7),
463 Identifier
::AlphaNumeric(String
::from("3aedf")),
466 assert_eq
!(Version
::parse("0.4.0-beta.1+0851523"),
471 pre
: vec
![Identifier
::AlphaNumeric(String
::from("beta")),
472 Identifier
::Numeric(1),
474 build
: vec
![Identifier
::AlphaNumeric(String
::from("0851523"))],
480 fn test_increment_patch() {
481 let mut buggy_release
= Version
::parse("0.1.0").unwrap();
482 buggy_release
.increment_patch();
483 assert_eq
!(buggy_release
, Version
::parse("0.1.1").unwrap());
487 fn test_increment_minor() {
488 let mut feature_release
= Version
::parse("1.4.6").unwrap();
489 feature_release
.increment_minor();
490 assert_eq
!(feature_release
, Version
::parse("1.5.0").unwrap());
494 fn test_increment_major() {
495 let mut chrome_release
= Version
::parse("46.1.246773").unwrap();
496 chrome_release
.increment_major();
497 assert_eq
!(chrome_release
, Version
::parse("47.0.0").unwrap());
501 fn test_increment_keep_prerelease() {
502 let mut release
= Version
::parse("1.0.0-alpha").unwrap();
503 release
.increment_patch();
505 assert_eq
!(release
, Version
::parse("1.0.1").unwrap());
507 release
.increment_minor();
509 assert_eq
!(release
, Version
::parse("1.1.0").unwrap());
511 release
.increment_major();
513 assert_eq
!(release
, Version
::parse("2.0.0").unwrap());
518 fn test_increment_clear_metadata() {
519 let mut release
= Version
::parse("1.0.0+4442").unwrap();
520 release
.increment_patch();
522 assert_eq
!(release
, Version
::parse("1.0.1").unwrap());
523 release
= Version
::parse("1.0.1+hello").unwrap();
525 release
.increment_minor();
527 assert_eq
!(release
, Version
::parse("1.1.0").unwrap());
528 release
= Version
::parse("1.1.3747+hello").unwrap();
530 release
.increment_major();
532 assert_eq
!(release
, Version
::parse("2.0.0").unwrap());
537 assert_eq
!(Version
::parse("1.2.3"), Version
::parse("1.2.3"));
538 assert_eq
!(Version
::parse("1.2.3-alpha1"),
539 Version
::parse("1.2.3-alpha1"));
540 assert_eq
!(Version
::parse("1.2.3+build.42"),
541 Version
::parse("1.2.3+build.42"));
542 assert_eq
!(Version
::parse("1.2.3-alpha1+42"),
543 Version
::parse("1.2.3-alpha1+42"));
544 assert_eq
!(Version
::parse("1.2.3+23"), Version
::parse("1.2.3+42"));
549 assert
!(Version
::parse("0.0.0") != Version
::parse("0.0.1"));
550 assert
!(Version
::parse("0.0.0") != Version
::parse("0.1.0"));
551 assert
!(Version
::parse("0.0.0") != Version
::parse("1.0.0"));
552 assert
!(Version
::parse("1.2.3-alpha") != Version
::parse("1.2.3-beta"));
557 assert_eq
!(format
!("{}", Version
::parse("1.2.3").unwrap()),
558 "1.2.3".to_string());
559 assert_eq
!(format
!("{}", Version
::parse("1.2.3-alpha1").unwrap()),
560 "1.2.3-alpha1".to_string());
561 assert_eq
!(format
!("{}", Version
::parse("1.2.3+build.42").unwrap()),
562 "1.2.3+build.42".to_string());
563 assert_eq
!(format
!("{}", Version
::parse("1.2.3-alpha1+42").unwrap()),
564 "1.2.3-alpha1+42".to_string());
568 fn test_to_string() {
569 assert_eq
!(Version
::parse("1.2.3").unwrap().to_string(),
570 "1.2.3".to_string());
571 assert_eq
!(Version
::parse("1.2.3-alpha1").unwrap().to_string(),
572 "1.2.3-alpha1".to_string());
573 assert_eq
!(Version
::parse("1.2.3+build.42").unwrap().to_string(),
574 "1.2.3+build.42".to_string());
575 assert_eq
!(Version
::parse("1.2.3-alpha1+42").unwrap().to_string(),
576 "1.2.3-alpha1+42".to_string());
581 assert
!(Version
::parse("0.0.0") < Version
::parse("1.2.3-alpha2"));
582 assert
!(Version
::parse("1.0.0") < Version
::parse("1.2.3-alpha2"));
583 assert
!(Version
::parse("1.2.0") < Version
::parse("1.2.3-alpha2"));
584 assert
!(Version
::parse("1.2.3-alpha1") < Version
::parse("1.2.3"));
585 assert
!(Version
::parse("1.2.3-alpha1") < Version
::parse("1.2.3-alpha2"));
586 assert
!(!(Version
::parse("1.2.3-alpha2") < Version
::parse("1.2.3-alpha2")));
587 assert
!(!(Version
::parse("1.2.3+23") < Version
::parse("1.2.3+42")));
592 assert
!(Version
::parse("0.0.0") <= Version
::parse("1.2.3-alpha2"));
593 assert
!(Version
::parse("1.0.0") <= Version
::parse("1.2.3-alpha2"));
594 assert
!(Version
::parse("1.2.0") <= Version
::parse("1.2.3-alpha2"));
595 assert
!(Version
::parse("1.2.3-alpha1") <= Version
::parse("1.2.3-alpha2"));
596 assert
!(Version
::parse("1.2.3-alpha2") <= Version
::parse("1.2.3-alpha2"));
597 assert
!(Version
::parse("1.2.3+23") <= Version
::parse("1.2.3+42"));
602 assert
!(Version
::parse("1.2.3-alpha2") > Version
::parse("0.0.0"));
603 assert
!(Version
::parse("1.2.3-alpha2") > Version
::parse("1.0.0"));
604 assert
!(Version
::parse("1.2.3-alpha2") > Version
::parse("1.2.0"));
605 assert
!(Version
::parse("1.2.3-alpha2") > Version
::parse("1.2.3-alpha1"));
606 assert
!(Version
::parse("1.2.3") > Version
::parse("1.2.3-alpha2"));
607 assert
!(!(Version
::parse("1.2.3-alpha2") > Version
::parse("1.2.3-alpha2")));
608 assert
!(!(Version
::parse("1.2.3+23") > Version
::parse("1.2.3+42")));
613 assert
!(Version
::parse("1.2.3-alpha2") >= Version
::parse("0.0.0"));
614 assert
!(Version
::parse("1.2.3-alpha2") >= Version
::parse("1.0.0"));
615 assert
!(Version
::parse("1.2.3-alpha2") >= Version
::parse("1.2.0"));
616 assert
!(Version
::parse("1.2.3-alpha2") >= Version
::parse("1.2.3-alpha1"));
617 assert
!(Version
::parse("1.2.3-alpha2") >= Version
::parse("1.2.3-alpha2"));
618 assert
!(Version
::parse("1.2.3+23") >= Version
::parse("1.2.3+42"));
622 fn test_prerelease_check() {
623 assert
!(Version
::parse("1.0.0").unwrap().is_prerelease() == false);
624 assert
!(Version
::parse("0.0.1").unwrap().is_prerelease() == false);
625 assert
!(Version
::parse("4.1.4-alpha").unwrap().is_prerelease());
626 assert
!(Version
::parse("1.0.0-beta294296").unwrap().is_prerelease());
630 fn test_spec_order() {
631 let vs
= ["1.0.0-alpha",
641 let a
= Version
::parse(vs
[i
- 1]);
642 let b
= Version
::parse(vs
[i
]);
643 assert
!(a
< b
, "nope {:?} < {:?}", a
, b
);
650 assert_eq
!("1.2.3".parse(),
658 assert_eq
!(" 1.2.3 ".parse(),
666 assert_eq
!("1.2.3-alpha1".parse(),
671 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
674 assert_eq
!(" 1.2.3-alpha1 ".parse(),
679 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
682 assert_eq
!("1.2.3+build5".parse(),
688 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
690 assert_eq
!(" 1.2.3+build5 ".parse(),
696 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
698 assert_eq
!("1.2.3-alpha1+build5".parse(),
703 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
704 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
706 assert_eq
!(" 1.2.3-alpha1+build5 ".parse(),
711 pre
: vec
![Identifier
::AlphaNumeric(String
::from("alpha1"))],
712 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5"))],
714 assert_eq
!("1.2.3-1.alpha1.9+build5.7.3aedf ".parse(),
719 pre
: vec
![Identifier
::Numeric(1),
720 Identifier
::AlphaNumeric(String
::from("alpha1")),
721 Identifier
::Numeric(9),
723 build
: vec
![Identifier
::AlphaNumeric(String
::from("build5")),
724 Identifier
::Numeric(7),
725 Identifier
::AlphaNumeric(String
::from("3aedf")),
728 assert_eq
!("0.4.0-beta.1+0851523".parse(),
733 pre
: vec
![Identifier
::AlphaNumeric(String
::from("beta")),
734 Identifier
::Numeric(1),
736 build
: vec
![Identifier
::AlphaNumeric(String
::from("0851523"))],
742 fn test_from_str_errors() {
743 fn parse_error(e
: &str) -> result
::Result
<Version
, SemVerError
> {
744 return Err(SemVerError
::ParseError(e
.to_string()));
747 assert_eq
!("".parse(), parse_error("Error parsing major identifier"));
748 assert_eq
!(" ".parse(), parse_error("Error parsing major identifier"));
749 assert_eq
!("1".parse(), parse_error("Expected dot"));
750 assert_eq
!("1.2".parse(),
751 parse_error("Expected dot"));
752 assert_eq
!("1.2.3-".parse(),
753 parse_error("Error parsing prerelease"));
754 assert_eq
!("a.b.c".parse(),
755 parse_error("Error parsing major identifier"));
756 assert_eq
!("1.2.3 abc".parse(),
757 parse_error("Extra junk after valid version: abc"));