use std::cmp::Ordering;
#[cfg(feature = "macros")]
#[macro_use]
mod macros;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Identifier {
Numeric(u64),
Alphanumeric(&'static str),
}
#[derive(Clone, Eq, Debug)]
pub struct Version {
pub major: u64,
pub minor: u64,
pub patch: u64,
pub pre: &'static [Identifier],
pub build: &'static [Identifier],
}
impl Version {
pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
Self {
major,
minor,
patch,
pre: &[],
build: &[],
}
}
pub const fn pre(self, identifiers: &'static [Identifier]) -> Self {
Self {
major: self.major,
minor: self.minor,
patch: self.patch,
pre: identifiers,
build: self.build,
}
}
pub const fn build(self, build: &'static [Identifier]) -> Self {
Self {
major: self.major,
minor: self.minor,
patch: self.patch,
pre: self.pre,
build,
}
}
}
#[cfg(feature = "semver")]
impl From<&Identifier> for semver::Identifier {
fn from(ident: &Identifier) -> Self {
match ident {
Identifier::Numeric(n) => semver::Identifier::Numeric(*n),
Identifier::Alphanumeric(s) => semver::Identifier::AlphaNumeric(s.to_string()),
}
}
}
#[cfg(feature = "semver")]
impl From<Identifier> for semver::Identifier {
fn from(ident: Identifier) -> Self {
match ident {
Identifier::Numeric(n) => semver::Identifier::Numeric(n),
Identifier::Alphanumeric(s) => semver::Identifier::AlphaNumeric(s.to_string()),
}
}
}
#[cfg(feature = "semver")]
impl From<Version> for semver::Version {
fn from(version: Version) -> semver::Version {
semver::Version {
major: version.major,
minor: version.minor,
patch: version.patch,
pre: version.pre.iter().map(From::from).collect(),
build: version.build.iter().map(From::from).collect(),
}
}
}
impl std::hash::Hash for Version {
fn hash<H: std::hash::Hasher>(&self, into: &mut H) {
self.major.hash(into);
self.minor.hash(into);
self.patch.hash(into);
self.pre.hash(into);
}
}
impl std::cmp::PartialEq for Version {
#[inline]
fn eq(&self, other: &Version) -> bool {
self.major == other.major
&& self.minor == other.minor
&& self.patch == other.patch
&& self.pre == other.pre
}
}
impl std::cmp::PartialOrd for Version {
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for Version {
fn cmp(&self, other: &Version) -> Ordering {
match self.major.cmp(&other.major) {
Ordering::Equal => {}
r => return r,
}
match self.minor.cmp(&other.minor) {
Ordering::Equal => {}
r => return r,
}
match self.patch.cmp(&other.patch) {
Ordering::Equal => {}
r => return r,
}
match (self.pre.len(), other.pre.len()) {
(0, 0) => Ordering::Equal,
(0, _) => Ordering::Greater,
(_, 0) => Ordering::Less,
(_, _) => self.pre.cmp(&other.pre),
}
}
}
#[cfg(test)]
mod tests {
use super::{Identifier, Version};
#[test]
fn build() {
let constructed = Version::new(1, 2, 3)
.pre(&[Identifier::Alphanumeric("alpha")])
.build(&[Identifier::Alphanumeric("amd64")]);
let with_build = Version {
major: 1,
minor: 2,
patch: 3,
pre: &[Identifier::Alphanumeric("alpha")],
build: &[Identifier::Alphanumeric("amd64")],
};
let without_build = Version {
major: 1,
minor: 2,
patch: 3,
pre: &[Identifier::Alphanumeric("alpha")],
build: &[],
};
assert_eq!(with_build, constructed);
assert_eq!(without_build, constructed);
}
#[test]
fn convert() {
let version = semver::Version::parse("1.2.3-alpha.3+amd64").unwrap();
let const_correct: semver::Version = Version::new(1, 2, 3)
.pre(&[Identifier::Alphanumeric("alpha"), Identifier::Numeric(3)])
.build(&[Identifier::Alphanumeric("amd64")])
.into();
assert_eq!(version, const_correct);
}
#[test]
#[cfg(feature = "macros")]
fn test_macro() {
let handmade = Version {
major: 1,
minor: 2,
patch: 3,
pre: &[Identifier::Alphanumeric("alpha"), Identifier::Numeric(4)],
build: &[],
};
let version = version!(1, 2, 3 - alpha, 4);
assert_eq!(version, handmade);
}
}