]> git.proxmox.com Git - rustc.git/blobdiff - vendor/semver-parser/src/version.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / semver-parser / src / version.rs
diff --git a/vendor/semver-parser/src/version.rs b/vendor/semver-parser/src/version.rs
new file mode 100644 (file)
index 0000000..26c220f
--- /dev/null
@@ -0,0 +1,511 @@
+//! Version data and functions.\r
+//!\r
+//! This module contains [`Version`] struct, [`parse`] function for building\r
+//! [`Version`] struct from string and some helper data structures and functions.\r
+//!\r
+//! # Examples\r
+//!\r
+//! Parsing `Version` from string and checking its fields:\r
+//!\r
+//! ```\r
+//! use semver_parser::version;\r
+//!\r
+//! # fn try_main() -> Result<(), String> {\r
+//! let version = version::parse("1.2.3-alpha1")?;\r
+//!\r
+//! assert_eq!(version.major, 1);\r
+//! assert_eq!(version.minor, 2);\r
+//! assert_eq!(version.patch, 3);\r
+//!\r
+//! let expected_pre = vec![\r
+//!     version::Identifier::AlphaNumeric(String::from("alpha1")),\r
+//! ];\r
+//!\r
+//! assert_eq!(expected_pre, version.pre);\r
+//! # Ok(())\r
+//! # }\r
+//! #\r
+//! # try_main().unwrap();\r
+//! ```\r
+//! [`Version`]: ./struct.Version.html\r
+//! [`parse`]: ./fn.parse.html\r
+\r
+use crate::parser::{self, Parser};\r
+use std::fmt;\r
+\r
+/// Structure representing version data.\r
+///\r
+/// `Version` struct has some public fields representing version data, like major/minor version\r
+/// string, patch number and vectors of prefix and build identifiers.\r
+///\r
+/// # Examples\r
+///\r
+/// Parsing `Version` from string and checking its fields:\r
+///\r
+/// ```\r
+/// use semver_parser::version;\r
+///\r
+/// # fn try_main() -> Result<(), String> {\r
+/// let version = version::parse("0.1.2-alpha1")?;\r
+/// assert_eq!(version.major, 0);\r
+/// assert_eq!(version.minor, 1);\r
+/// assert_eq!(version.patch, 2);\r
+/// let expected_pre = vec![version::Identifier::AlphaNumeric(String::from("alpha1"))];\r
+/// assert_eq!(expected_pre, version.pre);\r
+/// # Ok(())\r
+/// # }\r
+/// #\r
+/// # try_main().unwrap();\r
+/// ```\r
+#[derive(Clone, PartialOrd, Ord, Hash, Debug, PartialEq, Eq)]\r
+pub struct Version {\r
+    /// Major version as number (`0` in `"0.1.2"`).\r
+    pub major: u64,\r
+    /// Minor version as number (`1` in `"0.1.2"`).\r
+    pub minor: u64,\r
+    /// Patch version as number (`2` in `"0.1.2"`).\r
+    pub patch: u64,\r
+    /// Pre-release metadata as a vector of `Identifier` (`"alpha1"` in `"0.1.2-alpha1"`\r
+    /// or `7` (numeric) in `"0.1.2-7"`, `"pre"` and `0` (numeric) in `"0.1.2-pre.0"`).\r
+    pub pre: Vec<Identifier>,\r
+    /// Build metadata as a vector of `Identifier` (`"build1"` in `"0.1.2+build1"`\r
+    /// or `7` (numeric) in `"0.1.2+7"`, `"build"` and `0` (numeric) in `"0.1.2+pre.0"`).\r
+    pub build: Vec<Identifier>,\r
+}\r
+\r
+/// Helper enum for holding data of alphanumeric or numeric suffix identifiers.\r
+///\r
+/// This enum is used to hold suffix parts of `pre` and `build` fields of\r
+/// [`Version`] struct. Theses suffixes may be either numeric or alphanumeric.\r
+///\r
+/// # Examples\r
+///\r
+/// Parsing [`Version`] with pre-release part composed of two `Identifier`s:\r
+///\r
+/// ```\r
+/// use semver_parser::version;\r
+///\r
+/// # fn try_main() -> Result<(), String> {\r
+/// let version = version::parse("0.1.2-alpha1.0")?;\r
+///\r
+/// let expected_pre = vec![\r
+///     version::Identifier::AlphaNumeric(String::from("alpha1")),\r
+///     version::Identifier::Numeric(0),\r
+/// ];\r
+///\r
+/// assert_eq!(expected_pre, version.pre);\r
+/// # Ok(())\r
+/// # }\r
+/// #\r
+/// # try_main().unwrap();\r
+/// ```\r
+/// [`Version`]: ./struct.Version.html\r
+#[derive(Clone, PartialOrd, Ord, Hash, Debug, PartialEq, Eq)]\r
+pub enum Identifier {\r
+    /// An identifier that's solely numbers.\r
+    Numeric(u64),\r
+    /// An identifier with letters and numbers.\r
+    AlphaNumeric(String),\r
+}\r
+\r
+impl Identifier {\r
+    pub fn concat(self, add_str: &str) -> Identifier {\r
+        match self {\r
+            Identifier::Numeric(n) => Identifier::AlphaNumeric(format!("{}{}", n, add_str)),\r
+            Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(format!("{}{}", s, add_str)),\r
+        }\r
+    }\r
+}\r
+\r
+/// Function for parsing version string to [`Version`].\r
+///\r
+/// Returns `Result<`[`Version`]`, String>`, where `String` represents an error while parsing.\r
+///\r
+/// # Examples\r
+///\r
+/// Parsing [`Version`] from string and checking its fields:\r
+///\r
+/// ```\r
+/// use semver_parser::version;\r
+///\r
+/// # fn try_main() -> Result<(), String> {\r
+/// let version = version::parse("0.1.2-alpha1")?;\r
+/// assert_eq!(version.major, 0);\r
+/// assert_eq!(version.minor, 1);\r
+/// assert_eq!(version.patch, 2);\r
+/// let expected_pre = vec![version::Identifier::AlphaNumeric(String::from("alpha1"))];\r
+/// assert_eq!(expected_pre, version.pre);\r
+/// # Ok(())\r
+/// # }\r
+/// #\r
+/// # try_main().unwrap();\r
+/// ```\r
+/// [`Version`]: ./struct.Version.html\r
+pub fn parse(input: &str) -> Result<Version, parser::Error> {\r
+    let mut parser = Parser::new(input)?;\r
+    let version = parser.version()?;\r
+\r
+    if !parser.is_eof() {\r
+        return Err(parser::Error::MoreInput(parser.tail()?));\r
+    }\r
+\r
+    Ok(version)\r
+}\r
+\r
+impl fmt::Display for Version {\r
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r
+        write!(f, "{}.{}.{}", self.major, self.minor, self.patch).expect("write failed");\r
+        if !self.pre.is_empty() {\r
+            let strs: Vec<_> = self.pre.iter().map(ToString::to_string).collect();\r
+            write!(f, "-{}", strs.join(".")).expect("write failed");\r
+        }\r
+        if !self.build.is_empty() {\r
+            let strs: Vec<_> = self.build.iter().map(ToString::to_string).collect();\r
+            write!(f, "+{}", strs.join(".")).expect("write failed");\r
+        }\r
+        Ok(())\r
+    }\r
+}\r
+\r
+impl fmt::Display for Identifier {\r
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r
+        match *self {\r
+            Identifier::Numeric(ref id) => id.fmt(f),\r
+            Identifier::AlphaNumeric(ref id) => id.fmt(f),\r
+        }\r
+    }\r
+}\r
+\r
+#[cfg(test)]\r
+mod tests {\r
+    use super::*;\r
+    use crate::version;\r
+\r
+    #[test]\r
+    fn parse_empty() {\r
+        let version = "";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "empty string incorrectly considered a valid parse"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_blank() {\r
+        let version = "  ";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "blank string incorrectly considered a valid parse"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_minor_patch() {\r
+        let version = "1";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            format!("'{}' incorrectly considered a valid parse", version)\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_patch() {\r
+        let version = "1.2";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            format!("'{}' incorrectly considered a valid parse", version)\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_empty_pre() {\r
+        let version = "1.2.3-";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            format!("'{}' incorrectly considered a valid parse", version)\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_letters() {\r
+        let version = "a.b.c";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            format!("'{}' incorrectly considered a valid parse", version)\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_with_letters() {\r
+        let version = "1.2.3 a.b.c";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            format!("'{}' incorrectly considered a valid parse", version)\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_basic_version() {\r
+        let version = "1.2.3";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        assert_eq!(1, parsed.major);\r
+        assert_eq!(2, parsed.minor);\r
+        assert_eq!(3, parsed.patch);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_trims_input() {\r
+        let version = "  1.2.3  ";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        assert_eq!(1, parsed.major);\r
+        assert_eq!(2, parsed.minor);\r
+        assert_eq!(3, parsed.patch);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_major_leading_zeroes() {\r
+        let version = "01.0.0";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "01 incorrectly considered a valid major version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_minor_leading_zeroes() {\r
+        let version = "0.01.0";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "01 incorrectly considered a valid minor version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_patch_leading_zeroes() {\r
+        let version = "0.0.01";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "01 incorrectly considered a valid patch version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_major_overflow() {\r
+        let version = "98765432109876543210.0.0";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "98765432109876543210 incorrectly considered a valid major version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_minor_overflow() {\r
+        let version = "0.98765432109876543210.0";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "98765432109876543210 incorrectly considered a valid minor version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_no_patch_overflow() {\r
+        let version = "0.0.98765432109876543210";\r
+\r
+        let parsed = version::parse(version);\r
+\r
+        assert!(\r
+            parsed.is_err(),\r
+            "98765432109876543210 incorrectly considered a valid patch version"\r
+        );\r
+    }\r
+\r
+    #[test]\r
+    fn parse_basic_prerelease() {\r
+        let version = "1.2.3-pre";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_prerelease_alphanumeric() {\r
+        let version = "1.2.3-alpha1";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_prerelease_zero() {\r
+        let version = "1.2.3-pre.0";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![\r
+            Identifier::AlphaNumeric(String::from("pre")),\r
+            Identifier::Numeric(0),\r
+        ];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_basic_build() {\r
+        let version = "1.2.3+build";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_build_alphanumeric() {\r
+        let version = "1.2.3+build5";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_pre_and_build() {\r
+        let version = "1.2.3-alpha1+build5";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+\r
+        let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_complex_metadata_01() {\r
+        let version = "1.2.3-1.alpha1.9+build5.7.3aedf  ";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![\r
+            Identifier::Numeric(1),\r
+            Identifier::AlphaNumeric(String::from("alpha1")),\r
+            Identifier::Numeric(9),\r
+        ];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+\r
+        let expected_build = vec![\r
+            Identifier::AlphaNumeric(String::from("build5")),\r
+            Identifier::Numeric(7),\r
+            Identifier::AlphaNumeric(String::from("3aedf")),\r
+        ];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_complex_metadata_02() {\r
+        let version = "0.4.0-beta.1+0851523";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![\r
+            Identifier::AlphaNumeric(String::from("beta")),\r
+            Identifier::Numeric(1),\r
+        ];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+\r
+        let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_metadata_overflow() {\r
+        let version = "0.4.0-beta.1+98765432109876543210";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        let expected_pre = vec![\r
+            Identifier::AlphaNumeric(String::from("beta")),\r
+            Identifier::Numeric(1),\r
+        ];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+\r
+        let expected_build = vec![Identifier::AlphaNumeric(String::from(\r
+            "98765432109876543210",\r
+        ))];\r
+        assert_eq!(expected_build, parsed.build);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_regression_01() {\r
+        let version = "0.0.0-WIP";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        assert_eq!(0, parsed.major);\r
+        assert_eq!(0, parsed.minor);\r
+        assert_eq!(0, parsed.patch);\r
+\r
+        let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+    }\r
+\r
+    #[test]\r
+    fn parse_regression_02() {\r
+        // this is used by really old versions of npm, and is valid according to semver.org\r
+        let version = "1.2.3-beta-1";\r
+\r
+        let parsed = version::parse(version).unwrap();\r
+\r
+        assert_eq!(1, parsed.major);\r
+        assert_eq!(2, parsed.minor);\r
+        assert_eq!(3, parsed.patch);\r
+\r
+        let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta-1"))];\r
+        assert_eq!(expected_pre, parsed.pre);\r
+    }\r
+}\r