Initial refactor
This commit is contained in:
parent
12ac9a84ce
commit
98b74bd2a7
96
Cargo.lock
generated
96
Cargo.lock
generated
@ -46,9 +46,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.31"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
@ -56,7 +56,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -65,6 +65,14 @@ version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "epoch"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.hitchhiker-linux.org/jeang3nie/epoch-rs.git#9563b1da0d9e985555d2deff2ca0ee279bd04bee"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.59"
|
||||
@ -144,18 +152,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.195"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.195"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -184,6 +192,7 @@ name = "version"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"epoch",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -247,22 +256,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -271,93 +265,51 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
|
@ -7,4 +7,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
epoch = { git = "https://git.hitchhiker-linux.org/jeang3nie/epoch-rs.git", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
306
src/extended.rs
306
src/extended.rs
@ -1,306 +0,0 @@
|
||||
use {
|
||||
crate::{
|
||||
error::Error, gitrev::GitRev, prerelease::PreRelease, rapid::Rapid, semver::SemVer,
|
||||
simple::Simple, MAX_U12,
|
||||
},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp::Ordering, fmt, str::FromStr},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct Extended {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
pub patch: u16,
|
||||
pub build: u16,
|
||||
pub pre: PreRelease,
|
||||
}
|
||||
|
||||
impl fmt::Display for Extended {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}.{}.{}.{}",
|
||||
self.major, self.minor, self.patch, self.build
|
||||
)?;
|
||||
match self.pre {
|
||||
PreRelease::None => Ok(()),
|
||||
p => write!(f, "_{p}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Extended {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (s, pre) = match s.split_once('_') {
|
||||
Some((a, b)) => (a, b.parse::<PreRelease>()?),
|
||||
None => (s, PreRelease::None),
|
||||
};
|
||||
let split = s.split('.').collect::<Vec<_>>();
|
||||
match split.len() {
|
||||
4 => {
|
||||
let major = split.first().unwrap().parse::<u16>()?;
|
||||
let minor = split.get(1).unwrap().parse::<u16>()?;
|
||||
let patch = split.get(2).unwrap().parse::<u16>()?;
|
||||
let build = split.get(3).unwrap().parse::<u16>()?;
|
||||
if major > MAX_U12 || minor > MAX_U12 || patch > MAX_U12 || build > MAX_U12 {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
Ok(Self {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
build,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
_ => Err(Error::ParseSemver),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Extended> for u64 {
|
||||
fn from(value: Extended) -> Self {
|
||||
let major = u64::from(value.major) << 52;
|
||||
let minor = u64::from(value.minor) << 40;
|
||||
let patch = u64::from(value.patch) << 28;
|
||||
let build = u64::from(value.build) << 16;
|
||||
let pre = u64::from(u16::from(value.pre));
|
||||
major | minor | patch | build | pre
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for Extended {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
let mut mask: u64 = 0o7777 << 52;
|
||||
let major = (value & mask) >> 52;
|
||||
mask = 0o7777 << 40;
|
||||
let minor = (value & mask) >> 40;
|
||||
mask = 0o7777 << 28;
|
||||
let patch = (value & mask) >> 28;
|
||||
mask = 0o7777 << 16;
|
||||
let build = (value & mask) >> 16;
|
||||
mask = 0o37777;
|
||||
let p = u16::try_from(value & mask)?;
|
||||
let pre: PreRelease = p.try_into()?;
|
||||
Ok(Self {
|
||||
major: major.try_into()?,
|
||||
minor: minor.try_into()?,
|
||||
patch: patch.try_into()?,
|
||||
build: build.try_into()?,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Extended {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == other.patch
|
||||
&& self.build == other.build
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Extended {}
|
||||
|
||||
impl Ord for Extended {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Extended {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Simple> for Extended {
|
||||
fn from(value: Simple) -> Self {
|
||||
Self {
|
||||
major: value.major,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
build: 0,
|
||||
pre: value.pre,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rapid> for Extended {
|
||||
fn from(value: Rapid) -> Self {
|
||||
Self {
|
||||
major: value.major,
|
||||
minor: value.minor,
|
||||
patch: 0,
|
||||
build: 0,
|
||||
pre: value.pre,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemVer> for Extended {
|
||||
fn from(value: SemVer) -> Self {
|
||||
Self {
|
||||
major: value.major,
|
||||
minor: value.minor,
|
||||
patch: value.patch,
|
||||
build: 0,
|
||||
pre: value.pre,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<SemVer> for Extended {
|
||||
fn eq(&self, other: &SemVer) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == other.patch
|
||||
&& self.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Rapid> for Extended {
|
||||
fn eq(&self, other: &Rapid) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == 0
|
||||
&& self.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Simple> for Extended {
|
||||
fn eq(&self, other: &Simple) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == 0
|
||||
&& self.patch == 0
|
||||
&& self.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GitRev> for Extended {
|
||||
fn eq(&self, _other: &GitRev) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<SemVer> for Extended {
|
||||
fn partial_cmp(&self, other: &SemVer) -> Option<Ordering> {
|
||||
Some(u64::from(*self).cmp(&u64::from(*other)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Rapid> for Extended {
|
||||
fn partial_cmp(&self, other: &Rapid) -> Option<Ordering> {
|
||||
Some(u64::from(*self).cmp(&u64::from(*other)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Simple> for Extended {
|
||||
fn partial_cmp(&self, other: &Simple) -> Option<Ordering> {
|
||||
Some(u64::from(*self).cmp(&u64::from(*other)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GitRev> for Extended {
|
||||
fn partial_cmp(&self, _other: &GitRev) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::num::NonZeroU16;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
let mut ex: Extended = "1.2.3.4".parse().unwrap();
|
||||
assert_eq!(
|
||||
ex,
|
||||
Extended {
|
||||
major: 1,
|
||||
minor: 2,
|
||||
patch: 3,
|
||||
build: 4,
|
||||
pre: PreRelease::None,
|
||||
}
|
||||
);
|
||||
ex = "3.0.14.1_beta2".parse().unwrap();
|
||||
assert_eq!(
|
||||
ex,
|
||||
Extended {
|
||||
major: 3,
|
||||
minor: 0,
|
||||
patch: 14,
|
||||
build: 1,
|
||||
pre: PreRelease::Beta(Some(NonZeroU16::new(2).unwrap())),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_string() {
|
||||
let mut ex = Extended {
|
||||
major: 2,
|
||||
minor: 11,
|
||||
patch: 0,
|
||||
build: 1,
|
||||
pre: PreRelease::None,
|
||||
};
|
||||
assert_eq!(ex.to_string(), "2.11.0.1");
|
||||
ex.pre = PreRelease::RC(None);
|
||||
assert_eq!(ex.to_string(), "2.11.0.1_rc");
|
||||
ex.pre = PreRelease::Alpha(Some(NonZeroU16::new(3).unwrap()));
|
||||
assert_eq!(ex.to_string(), "2.11.0.1_alpha3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eq() {
|
||||
assert_eq!(
|
||||
"1.0.2.1_beta1".parse::<Extended>().unwrap(),
|
||||
"1.0.2.1_beta".parse::<Extended>().unwrap()
|
||||
);
|
||||
assert_ne!(
|
||||
"1.0.2.1_alpha".parse::<Extended>().unwrap(),
|
||||
"1.0.2.1_alpha2".parse::<Extended>().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ord() {
|
||||
let a: Extended = "1.0.14.1".parse().unwrap();
|
||||
let b: Extended = "1.0.14.1_alpha4".parse().unwrap();
|
||||
let c: Extended = "1.0.14.1_beta2".parse().unwrap();
|
||||
let d: Extended = "1.0.14.1_beta3".parse().unwrap();
|
||||
let e: Extended = "2.0.14.1".parse().unwrap();
|
||||
let f: Extended = "2.1.14.1".parse().unwrap();
|
||||
let g: Extended = "2.1.13.1".parse().unwrap();
|
||||
assert!(a > b);
|
||||
assert!(b < a);
|
||||
assert!(a > c);
|
||||
assert!(b < c);
|
||||
assert!(c < a);
|
||||
assert!(c > b);
|
||||
assert!(d > b);
|
||||
assert!(d < a);
|
||||
assert!(e > a);
|
||||
assert!(f > e);
|
||||
assert!(g < f);
|
||||
assert!(d < e);
|
||||
assert!(e < f);
|
||||
assert!(f > g);
|
||||
}
|
||||
}
|
175
src/gitrev.rs
175
src/gitrev.rs
@ -1,175 +0,0 @@
|
||||
use {
|
||||
crate::{
|
||||
error::Error, extended::Extended, rapid::Rapid, semver::SemVer, simple::Simple,
|
||||
version::Kind, version::Version,
|
||||
},
|
||||
chrono::{offset::Utc, DateTime},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp::Ordering, fmt, str::FromStr},
|
||||
};
|
||||
|
||||
/// Represents a Git revisionrather than a regular release.
|
||||
/// A `GitRev` release contains the revision's hash and the Date/Time of the release.
|
||||
/// Git revisions are not the preferred method of distribution for obvious reasons, as
|
||||
/// they generally do not represent a stable release of the code. Another drawback is
|
||||
/// that a Git revision can only be compared against another Git revision, making it
|
||||
/// impossible to properly order updates between a proper `SemVer` type release and a\
|
||||
/// Git revision.
|
||||
/// ### Notes on display formatting
|
||||
/// The hash as stored in this struct should be the short form revision hash (the first
|
||||
/// 7 characters of the full hash). The full date and time information is saved minus
|
||||
/// any fractional seconds. When displaying, the date and time should be converted to a
|
||||
/// Unix timestamp.
|
||||
/// ### Parsing from a string
|
||||
/// In order to parse this struct from a string, two fields `hash` and `datetime` should
|
||||
/// be separated by a period character '.' and the date/time take the form of a Unix
|
||||
/// timestamp. This information can be retrieved from git for a given commit using the
|
||||
/// following git commandline:
|
||||
/// ```Sh
|
||||
/// git show --pretty=format:"%h.%at" <hash> | head -n 1
|
||||
/// ```
|
||||
/// The resulting string can then be parsed using the `FromStr` trait, which provides
|
||||
/// both `from_str` and `parse`.
|
||||
/// ### Comparison - ordering
|
||||
/// Git revisions are ordered by date/time
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct GitRev {
|
||||
/// the short revision hash
|
||||
pub hash: String,
|
||||
/// the time of the revision commit
|
||||
pub datetime: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl fmt::Display for GitRev {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "git_{}.{}", self.hash, self.datetime.timestamp())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for GitRev {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for GitRev {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.datetime.cmp(&other.datetime)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GitRev {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if let Some(gitrev) = s.strip_prefix("git_") {
|
||||
if let Some((hash, datetime)) = gitrev.split_once('.') {
|
||||
if hash.len() == 7 {
|
||||
let secs: i64 = datetime.parse()?;
|
||||
let Some(datetime) = DateTime::<Utc>::from_timestamp(secs, 0) else {
|
||||
return Err(Error::ParseInt);
|
||||
};
|
||||
return Ok(Self {
|
||||
hash: hash.to_string(),
|
||||
datetime,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::ParseGitRev)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Extended> for GitRev {
|
||||
fn eq(&self, _other: &Extended) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Extended> for GitRev {
|
||||
fn partial_cmp(&self, _other: &Extended) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<SemVer> for GitRev {
|
||||
fn eq(&self, _other: &SemVer) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<SemVer> for GitRev {
|
||||
fn partial_cmp(&self, _other: &SemVer) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Rapid> for GitRev {
|
||||
fn eq(&self, _other: &Rapid) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Rapid> for GitRev {
|
||||
fn partial_cmp(&self, _other: &Rapid) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Simple> for GitRev {
|
||||
fn eq(&self, _other: &Simple) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Simple> for GitRev {
|
||||
fn partial_cmp(&self, _other: &Simple) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Version> for GitRev {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Version) -> Result<Self, Self::Error> {
|
||||
match value.0 {
|
||||
Kind::GitRev(g) => Ok(g),
|
||||
_ => Err(Error::ParseGitRev),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn ord() {
|
||||
let a = GitRev {
|
||||
hash: "aaabxxx".to_string(),
|
||||
datetime: Utc::now(),
|
||||
};
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
let b = GitRev {
|
||||
hash: "aaaaxxx".to_string(),
|
||||
datetime: Utc::now(),
|
||||
};
|
||||
assert!(a < b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
let now = DateTime::<Utc>::from_timestamp(Utc::now().timestamp(), 0).unwrap();
|
||||
let rev: GitRev = format!("git_r2d2xxx.{}", now.timestamp()).parse().unwrap();
|
||||
println!("Version = {rev}");
|
||||
assert_eq!(
|
||||
rev,
|
||||
GitRev {
|
||||
hash: "r2d2xxx".to_string(),
|
||||
datetime: now,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -3,13 +3,8 @@
|
||||
|
||||
mod arch;
|
||||
mod error;
|
||||
mod extended;
|
||||
mod gitrev;
|
||||
pub mod prelude;
|
||||
mod prerelease;
|
||||
mod rapid;
|
||||
mod semver;
|
||||
mod simple;
|
||||
mod version;
|
||||
|
||||
pub use version::Version;
|
||||
|
@ -1,4 +1 @@
|
||||
pub use crate::{
|
||||
arch::Arch, error::Error as VersionError, extended::Extended, gitrev::GitRev, rapid::Rapid,
|
||||
semver::SemVer, simple::Simple, version::Kind as VersionKind,
|
||||
};
|
||||
pub use crate::{arch::Arch, error::Error as VersionError, version::Kind as VersionKind};
|
||||
|
@ -1,5 +1,6 @@
|
||||
use {
|
||||
crate::{error::Error, MAX_U12},
|
||||
epoch::DateTime,
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp, convert::Into, fmt, num::NonZeroU16, str},
|
||||
};
|
||||
@ -10,31 +11,45 @@ pub enum PreRelease {
|
||||
Alpha(Option<NonZeroU16>),
|
||||
Beta(Option<NonZeroU16>),
|
||||
RC(Option<NonZeroU16>),
|
||||
Git {
|
||||
hash: [char; 7],
|
||||
datetime: DateTime,
|
||||
},
|
||||
/// `PreRelease::None` is equivalent to a normal release
|
||||
None,
|
||||
}
|
||||
|
||||
impl PreRelease {
|
||||
pub fn is_prerelease(self) -> bool {
|
||||
pub fn is_prerelease(&self) -> bool {
|
||||
!matches!(self, Self::None)
|
||||
}
|
||||
|
||||
pub fn is_alpha(self) -> bool {
|
||||
pub fn is_alpha(&self) -> bool {
|
||||
matches!(self, Self::Alpha(_))
|
||||
}
|
||||
|
||||
pub fn is_beta(self) -> bool {
|
||||
pub fn is_beta(&self) -> bool {
|
||||
matches!(self, Self::Beta(_))
|
||||
}
|
||||
|
||||
pub fn is_rc(self) -> bool {
|
||||
pub fn is_rc(&self) -> bool {
|
||||
matches!(self, Self::RC(_))
|
||||
}
|
||||
|
||||
pub fn is_gitrev(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Git {
|
||||
hash: _,
|
||||
datetime: _
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn number(self) -> Option<u16> {
|
||||
match self {
|
||||
Self::Alpha(n) | Self::Beta(n) | Self::RC(n) => n.map(Into::into),
|
||||
Self::None => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +67,7 @@ impl PreRelease {
|
||||
}
|
||||
None => *n = Some(NonZeroU16::new(2).unwrap()),
|
||||
},
|
||||
Self::None => {}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -65,7 +80,7 @@ impl PreRelease {
|
||||
Self::Alpha(_) => *self = Self::Beta(None),
|
||||
Self::Beta(_) => *self = Self::RC(None),
|
||||
Self::RC(_) => *self = Self::None,
|
||||
Self::None => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,12 +88,19 @@ impl PreRelease {
|
||||
impl fmt::Display for PreRelease {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Alpha(Some(v)) => write!(f, "alpha{v}"),
|
||||
Self::Alpha(None) => write!(f, "alpha"),
|
||||
Self::Beta(Some(v)) => write!(f, "beta{v}"),
|
||||
Self::Beta(None) => write!(f, "beta"),
|
||||
Self::RC(Some(v)) => write!(f, "rc{v}"),
|
||||
Self::RC(None) => write!(f, "rc"),
|
||||
Self::Alpha(Some(v)) => write!(f, "_alpha{v}"),
|
||||
Self::Alpha(None) => write!(f, "_alpha"),
|
||||
Self::Beta(Some(v)) => write!(f, "_beta{v}"),
|
||||
Self::Beta(None) => write!(f, "_beta"),
|
||||
Self::RC(Some(v)) => write!(f, "_rc{v}"),
|
||||
Self::RC(None) => write!(f, "_rc"),
|
||||
Self::Git { hash, datetime } => {
|
||||
write!(f, "_git_")?;
|
||||
for c in hash {
|
||||
write!(f, "{c}")?;
|
||||
}
|
||||
write!(f, ".{}", datetime.timestamp())
|
||||
}
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
}
|
||||
@ -142,57 +164,50 @@ impl str::FromStr for PreRelease {
|
||||
_ => Err(Error::ParsePreRelease),
|
||||
}
|
||||
}
|
||||
s if s.starts_with("git_") => {
|
||||
let s = s.strip_prefix("git_").unwrap();
|
||||
let Some((h, ts)) = s.split_once('.') else {
|
||||
return Err(Error::ParseGitRev);
|
||||
};
|
||||
if h.len() != 7 {
|
||||
return Err(Error::ParseGitRev);
|
||||
}
|
||||
let mut hash = ['x'; 7];
|
||||
for (idx, c) in h.chars().enumerate() {
|
||||
hash[idx] = c;
|
||||
}
|
||||
let ts: i64 = ts.parse()?;
|
||||
let datetime = DateTime::from_timestamp(ts);
|
||||
Ok(Self::Git { hash, datetime })
|
||||
}
|
||||
_ => Err(Error::ParsePreRelease),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PreRelease> for u16 {
|
||||
impl From<PreRelease> for u128 {
|
||||
fn from(value: PreRelease) -> Self {
|
||||
let mask: u16 = 0o1_777;
|
||||
let mask: u16 = 0o3_777;
|
||||
match value {
|
||||
PreRelease::Git { hash: _, datetime } => {
|
||||
0o4_000 << 64 | u128::try_from(datetime.timestamp()).unwrap()
|
||||
}
|
||||
PreRelease::Alpha(Some(v)) => {
|
||||
let v = u16::from(v) & mask;
|
||||
v | 0o10_000
|
||||
u128::from(v | 0o10_000) << 64
|
||||
}
|
||||
PreRelease::Alpha(None) => 0o2_000,
|
||||
PreRelease::Alpha(None) => 0o10_000 << 64,
|
||||
PreRelease::Beta(Some(v)) => {
|
||||
let v = u16::from(v) & mask;
|
||||
v | 0o20_000
|
||||
u128::from(v | 0o20_000) << 64
|
||||
}
|
||||
PreRelease::Beta(None) => 0o4_000,
|
||||
PreRelease::Beta(None) => 0o20_000 << 64,
|
||||
PreRelease::RC(Some(v)) => {
|
||||
let v = u16::from(v) & mask;
|
||||
v | 0o40_000
|
||||
u128::from(v | 0o40_000) << 64
|
||||
}
|
||||
PreRelease::RC(None) => 0o10_000,
|
||||
PreRelease::None => 0o100_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for PreRelease {
|
||||
type Error = crate::error::Error;
|
||||
|
||||
fn try_from(value: u16) -> Result<Self, crate::error::Error> {
|
||||
let mask = 0o1_777;
|
||||
let v = value & mask;
|
||||
let flag = value & !mask;
|
||||
match flag {
|
||||
0o10_000 => {
|
||||
let v = if v > 0 { Some(v.try_into()?) } else { None };
|
||||
Ok(Self::Alpha(v))
|
||||
}
|
||||
0o20_000 => {
|
||||
let v = if v > 0 { Some(v.try_into()?) } else { None };
|
||||
Ok(Self::Beta(v))
|
||||
}
|
||||
0o40_000 => {
|
||||
let v = if v > 0 { Some(v.try_into()?) } else { None };
|
||||
Ok(Self::RC(v))
|
||||
}
|
||||
0o100_000 => Ok(Self::None),
|
||||
_ => Err(Error::FromUint),
|
||||
PreRelease::RC(None) => 0o40_000 << 64,
|
||||
PreRelease::None => 0o100_000 << 64,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,8 +226,8 @@ impl PartialEq for PreRelease {
|
||||
n == 1
|
||||
}
|
||||
_ => {
|
||||
let a: u16 = (*self).into();
|
||||
let b: u16 = (*other).into();
|
||||
let a: u128 = (*self).into();
|
||||
let b: u128 = (*other).into();
|
||||
a == b
|
||||
}
|
||||
}
|
||||
@ -223,8 +238,8 @@ impl Eq for PreRelease {}
|
||||
|
||||
impl cmp::Ord for PreRelease {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
let a: u16 = (*self).into();
|
||||
let b: u16 = (*other).into();
|
||||
let a: u128 = (*self).into();
|
||||
let b: u128 = (*other).into();
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
159
src/rapid.rs
159
src/rapid.rs
@ -1,159 +0,0 @@
|
||||
use {
|
||||
crate::{
|
||||
error::Error, extended::Extended, gitrev::GitRev, prerelease::PreRelease, semver::SemVer,
|
||||
simple::Simple, MAX_U12,
|
||||
},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp::Ordering, fmt, str::FromStr},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct Rapid {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
pub pre: PreRelease,
|
||||
}
|
||||
|
||||
impl fmt::Display for Rapid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}.{}", self.major, self.minor)?;
|
||||
match self.pre {
|
||||
PreRelease::None => Ok(()),
|
||||
p => write!(f, "_{p}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Rapid {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (s, pre) = match s.split_once('_') {
|
||||
Some((a, b)) => (a, b.parse::<PreRelease>()?),
|
||||
None => (s, PreRelease::None),
|
||||
};
|
||||
let split = s.split('.').collect::<Vec<_>>();
|
||||
match split.len() {
|
||||
2 => {
|
||||
let major = split.first().unwrap().parse::<u16>()?;
|
||||
let minor = split.get(1).unwrap().parse::<u16>()?;
|
||||
if major > MAX_U12 || minor > MAX_U12 {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
Ok(Self { major, minor, pre })
|
||||
}
|
||||
_ => Err(Error::ParseSemver),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rapid> for u64 {
|
||||
fn from(value: Rapid) -> Self {
|
||||
let major = u64::from(value.major) << 52;
|
||||
let minor = u64::from(value.minor) << 40;
|
||||
let pre = u64::from(u16::from(value.pre));
|
||||
major | minor | pre
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for Rapid {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
let mut mask: u64 = 0o7777 << 52;
|
||||
let major = (value & mask) >> 52;
|
||||
mask = 0o7777 << 40;
|
||||
let minor = (value & mask) >> 40;
|
||||
mask = 0o37777;
|
||||
let p = u16::try_from(value & mask)?;
|
||||
let pre: PreRelease = p.try_into()?;
|
||||
Ok(Self {
|
||||
major: major.try_into()?,
|
||||
minor: minor.try_into()?,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Rapid {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.major == other.major && self.minor == other.minor && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Rapid {}
|
||||
|
||||
impl Ord for Rapid {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Rapid {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Extended> for Rapid {
|
||||
fn eq(&self, other: &Extended) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& other.patch == 0
|
||||
&& other.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<SemVer> for Rapid {
|
||||
fn eq(&self, other: &SemVer) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& other.patch == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Simple> for Rapid {
|
||||
fn eq(&self, other: &Simple) -> bool {
|
||||
self.major == other.major && self.minor == 0 && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GitRev> for Rapid {
|
||||
fn eq(&self, _other: &GitRev) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Extended> for Rapid {
|
||||
fn partial_cmp(&self, other: &Extended) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.partial_cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<SemVer> for Rapid {
|
||||
fn partial_cmp(&self, other: &SemVer) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.partial_cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Simple> for Rapid {
|
||||
fn partial_cmp(&self, other: &Simple) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.partial_cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GitRev> for Rapid {
|
||||
fn partial_cmp(&self, _other: &GitRev) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
260
src/semver.rs
260
src/semver.rs
@ -1,260 +0,0 @@
|
||||
use {
|
||||
crate::{
|
||||
error::Error, extended::Extended, gitrev::GitRev, prerelease::PreRelease, rapid::Rapid,
|
||||
simple::Simple, MAX_U12,
|
||||
},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp::Ordering, fmt, str::FromStr},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct SemVer {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
pub patch: u16,
|
||||
pub pre: PreRelease,
|
||||
}
|
||||
|
||||
impl fmt::Display for SemVer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
|
||||
match self.pre {
|
||||
PreRelease::None => Ok(()),
|
||||
p => write!(f, "_{p}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SemVer {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (s, pre) = match s.split_once('_') {
|
||||
Some((a, b)) => (a, b.parse::<PreRelease>()?),
|
||||
None => (s, PreRelease::None),
|
||||
};
|
||||
let split = s.split('.').collect::<Vec<_>>();
|
||||
match split.len() {
|
||||
3 => {
|
||||
let major = split.first().unwrap().parse::<u16>()?;
|
||||
let minor = split.get(1).unwrap().parse::<u16>()?;
|
||||
let patch = split.get(2).unwrap().parse::<u16>()?;
|
||||
if major > MAX_U12 || minor > MAX_U12 || patch > MAX_U12 {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
Ok(Self {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
_ => Err(Error::ParseSemver),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemVer> for u64 {
|
||||
fn from(value: SemVer) -> Self {
|
||||
let major = u64::from(value.major) << 52;
|
||||
let minor = u64::from(value.minor) << 40;
|
||||
let patch = u64::from(value.patch) << 28;
|
||||
let pre = u64::from(u16::from(value.pre));
|
||||
major | minor | patch | pre
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for SemVer {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
let mut mask: u64 = 0o7777 << 52;
|
||||
let major = (value & mask) >> 52;
|
||||
mask = 0o7777 << 40;
|
||||
let minor = (value & mask) >> 40;
|
||||
mask = 0o7777 << 28;
|
||||
let patch = (value & mask) >> 28;
|
||||
mask = 0o37777;
|
||||
let p = u16::try_from(value & mask)?;
|
||||
let pre: PreRelease = p.try_into()?;
|
||||
Ok(Self {
|
||||
major: major.try_into()?,
|
||||
minor: minor.try_into()?,
|
||||
patch: patch.try_into()?,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SemVer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == other.patch
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SemVer {}
|
||||
|
||||
impl Ord for SemVer {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for SemVer {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Extended> for SemVer {
|
||||
fn eq(&self, other: &Extended) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == other.patch
|
||||
&& other.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Rapid> for SemVer {
|
||||
fn eq(&self, other: &Rapid) -> bool {
|
||||
self.major == other.major
|
||||
&& self.minor == other.minor
|
||||
&& self.patch == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Simple> for SemVer {
|
||||
fn eq(&self, other: &Simple) -> bool {
|
||||
self.major == other.major && self.minor == 0 && self.patch == 0 && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GitRev> for SemVer {
|
||||
fn eq(&self, _other: &GitRev) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Extended> for SemVer {
|
||||
fn partial_cmp(&self, other: &Extended) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Rapid> for SemVer {
|
||||
fn partial_cmp(&self, other: &Rapid) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Simple> for SemVer {
|
||||
fn partial_cmp(&self, other: &Simple) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GitRev> for SemVer {
|
||||
fn partial_cmp(&self, _other: &GitRev) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::num::NonZeroU16;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
let mut s: SemVer = "1.2.3".parse().unwrap();
|
||||
assert_eq!(
|
||||
s,
|
||||
SemVer {
|
||||
major: 1,
|
||||
minor: 2,
|
||||
patch: 3,
|
||||
pre: PreRelease::None,
|
||||
}
|
||||
);
|
||||
s = "0.3.0_alpha4".parse().unwrap();
|
||||
assert_eq!(
|
||||
s,
|
||||
SemVer {
|
||||
major: 0,
|
||||
minor: 3,
|
||||
patch: 0,
|
||||
pre: PreRelease::Alpha(Some(NonZeroU16::new(4).unwrap())),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_string() {
|
||||
let mut s = SemVer {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 2,
|
||||
pre: PreRelease::None,
|
||||
};
|
||||
assert_eq!(s.to_string(), "1.0.2");
|
||||
s = SemVer {
|
||||
major: 2,
|
||||
minor: 1,
|
||||
patch: 14,
|
||||
pre: PreRelease::Beta(Some(NonZeroU16::new(2).unwrap())),
|
||||
};
|
||||
assert_eq!(s.to_string(), "2.1.14_beta2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_from_u64() {
|
||||
let sem = SemVer {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 11,
|
||||
pre: PreRelease::Beta(Some(NonZeroU16::new(2).unwrap())),
|
||||
};
|
||||
assert_eq!(SemVer::try_from(u64::from(sem)).unwrap(), sem);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eq() {
|
||||
assert_eq!(
|
||||
"1.0.0_alpha".parse::<SemVer>().unwrap(),
|
||||
"1.0.0_alpha1".parse::<SemVer>().unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
"2.1.3_beta".parse::<SemVer>().unwrap(),
|
||||
"2.1.3_beta1".parse::<SemVer>().unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
"1.11.0_rc".parse::<SemVer>().unwrap(),
|
||||
"1.11.0_rc1".parse::<SemVer>().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ord() {
|
||||
let a: SemVer = "1.0.2".parse().unwrap();
|
||||
let b: SemVer = "1.0.3".parse().unwrap();
|
||||
let c: SemVer = "1.0.2_alpha1".parse().unwrap();
|
||||
let d: SemVer = "1.0.2_alpha2".parse().unwrap();
|
||||
assert!(a < b);
|
||||
assert!(c < a);
|
||||
assert!(d > c);
|
||||
}
|
||||
}
|
144
src/simple.rs
144
src/simple.rs
@ -1,144 +0,0 @@
|
||||
use {
|
||||
crate::{
|
||||
error::Error, extended::Extended, gitrev::GitRev, prerelease::PreRelease, rapid::Rapid,
|
||||
semver::SemVer, MAX_U12,
|
||||
},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{cmp::Ordering, fmt, str::FromStr},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct Simple {
|
||||
pub major: u16,
|
||||
pub pre: PreRelease,
|
||||
}
|
||||
|
||||
impl fmt::Display for Simple {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.major)?;
|
||||
match self.pre {
|
||||
PreRelease::None => Ok(()),
|
||||
p => write!(f, "_{p}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Simple {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let (s, pre) = match s.split_once('_') {
|
||||
Some((a, b)) => (a, b.parse::<PreRelease>()?),
|
||||
None => (s, PreRelease::None),
|
||||
};
|
||||
let major = s.parse::<u16>()?;
|
||||
if major > MAX_U12 {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
Ok(Self { major, pre })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Simple> for u64 {
|
||||
fn from(value: Simple) -> Self {
|
||||
let major = u64::from(value.major) << 52;
|
||||
let pre = u64::from(u16::from(value.pre));
|
||||
major | pre
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for Simple {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
let mut mask: u64 = 0o7777 << 52;
|
||||
let major = (value & mask) >> 52;
|
||||
mask = 0o37777;
|
||||
let p = u16::try_from(value & mask)?;
|
||||
let pre: PreRelease = p.try_into()?;
|
||||
Ok(Self {
|
||||
major: major.try_into()?,
|
||||
pre,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Simple {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.major == other.major && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Simple {}
|
||||
|
||||
impl Ord for Simple {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Simple {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Extended> for Simple {
|
||||
fn eq(&self, other: &Extended) -> bool {
|
||||
self.major == other.major
|
||||
&& other.minor == 0
|
||||
&& other.patch == 0
|
||||
&& other.build == 0
|
||||
&& self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<SemVer> for Simple {
|
||||
fn eq(&self, other: &SemVer) -> bool {
|
||||
self.major == other.major && other.minor == 0 && other.patch == 0 && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Rapid> for Simple {
|
||||
fn eq(&self, other: &Rapid) -> bool {
|
||||
self.major == other.major && other.minor == 0 && self.pre == other.pre
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GitRev> for Simple {
|
||||
fn eq(&self, _other: &GitRev) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Extended> for Simple {
|
||||
fn partial_cmp(&self, other: &Extended) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<SemVer> for Simple {
|
||||
fn partial_cmp(&self, other: &SemVer) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Rapid> for Simple {
|
||||
fn partial_cmp(&self, other: &Rapid) -> Option<Ordering> {
|
||||
let a = u64::from(*self);
|
||||
let b = u64::from(*other);
|
||||
Some(a.cmp(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GitRev> for Simple {
|
||||
fn partial_cmp(&self, _other: &GitRev) -> Option<Ordering> {
|
||||
None
|
||||
}
|
||||
}
|
351
src/version.rs
351
src/version.rs
@ -1,202 +1,215 @@
|
||||
use {
|
||||
crate::{
|
||||
arch::Arch, error::Error, extended::Extended, gitrev::GitRev, rapid::Rapid, semver::SemVer,
|
||||
simple::Simple,
|
||||
},
|
||||
crate::{arch::Arch, error::Error, prerelease::PreRelease, MAX_U12},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{fmt, str::FromStr},
|
||||
std::{cmp, fmt, str},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub enum Kind {
|
||||
Simple(Simple),
|
||||
Rapid(Rapid),
|
||||
SemVer(SemVer),
|
||||
Extended(Extended),
|
||||
GitRev(GitRev),
|
||||
Simple {
|
||||
major: u16,
|
||||
},
|
||||
Rapid {
|
||||
major: u16,
|
||||
minor: u16,
|
||||
},
|
||||
SemVer {
|
||||
major: u16,
|
||||
minor: u16,
|
||||
patch: u16,
|
||||
},
|
||||
Extended {
|
||||
major: u16,
|
||||
minor: u16,
|
||||
patch: u16,
|
||||
build: u16,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Version(pub Kind, pub Arch);
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct Version {
|
||||
pub kind: Kind,
|
||||
pub pre: PreRelease,
|
||||
pub arch: Arch,
|
||||
}
|
||||
|
||||
impl fmt::Display for Kind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Simple { major } => write!(f, "{major}"),
|
||||
Self::Rapid { major, minor } => write!(f, "{major}.{minor}"),
|
||||
Self::SemVer {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
} => write!(f, "{major}.{minor}.{patch}"),
|
||||
Self::Extended {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
build,
|
||||
} => write!(f, "{major}.{minor}.{patch}.{build}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Kind> for u128 {
|
||||
fn from(value: Kind) -> Self {
|
||||
match value {
|
||||
Kind::Simple { major } => u128::from(major) << (64 + 52),
|
||||
Kind::Rapid { major, minor } => {
|
||||
let major = u64::from(major) << 52;
|
||||
let minor = u64::from(minor) << 40;
|
||||
u128::from(major | minor) << 64
|
||||
}
|
||||
Kind::SemVer {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
} => {
|
||||
let major = u64::from(major) << 52;
|
||||
let minor = u64::from(minor) << 40;
|
||||
let patch = u64::from(patch) << 28;
|
||||
u128::from(major | minor | patch) << 64
|
||||
}
|
||||
Kind::Extended {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
build,
|
||||
} => {
|
||||
let major = u64::from(major) << 52;
|
||||
let minor = u64::from(minor) << 40;
|
||||
let patch = u64::from(patch) << 28;
|
||||
let build = u64::from(build) << 16;
|
||||
u128::from(major | minor | patch | build) << 64
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self.0 {
|
||||
Kind::Simple(s) => write!(f, "{s}-{}", self.1),
|
||||
Kind::Rapid(r) => write!(f, "{r}-{}", self.1),
|
||||
Kind::SemVer(s) => write!(f, "{s}-{}", self.1),
|
||||
Kind::Extended(x) => write!(f, "{x}-{}", self.1),
|
||||
Kind::GitRev(g) => write!(f, "{g}-{}", self.1),
|
||||
}
|
||||
write!(f, "{}{}-{}", self.kind, self.pre, self.arch)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Version {
|
||||
impl From<Version> for u128 {
|
||||
fn from(value: Version) -> Self {
|
||||
u128::from(value.kind) | u128::from(value.pre)
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for Version {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let Some((s, Some(arch))) = s.split_once('-').map(|(s, a)| (s, a.parse::<Arch>().ok()))
|
||||
else {
|
||||
let Some((s, arch)) = s.split_once('-') else {
|
||||
return Err(Error::ParseArch);
|
||||
};
|
||||
if let Ok(v) = Simple::from_str(s) {
|
||||
Ok(Self(Kind::Simple(v), arch))
|
||||
} else if let Ok(v) = Rapid::from_str(s) {
|
||||
Ok(Self(Kind::Rapid(v), arch))
|
||||
} else if let Ok(v) = SemVer::from_str(s) {
|
||||
Ok(Self(Kind::SemVer(v), arch))
|
||||
} else if let Ok(v) = Extended::from_str(s) {
|
||||
Ok(Self(Kind::Extended(v), arch))
|
||||
} else if let Ok(v) = GitRev::from_str(s) {
|
||||
Ok(Self(Kind::GitRev(v), arch))
|
||||
} else {
|
||||
Err(Error::ParseVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Simple> for Kind {
|
||||
fn from(value: Simple) -> Self {
|
||||
Self::Simple(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rapid> for Kind {
|
||||
fn from(value: Rapid) -> Self {
|
||||
Self::Rapid(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemVer> for Kind {
|
||||
fn from(value: SemVer) -> Self {
|
||||
Self::SemVer(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Extended> for Kind {
|
||||
fn from(value: Extended) -> Self {
|
||||
Self::Extended(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitRev> for Kind {
|
||||
fn from(value: GitRev) -> Self {
|
||||
Self::GitRev(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Kind {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Simple(a), Self::Simple(b)) => a == b,
|
||||
(Self::Simple(a), Self::Rapid(b)) => a == b,
|
||||
(Self::Simple(a), Self::SemVer(b)) => a == b,
|
||||
(Self::Simple(a), Self::Extended(b)) => a == b,
|
||||
(Self::Rapid(a), Self::Simple(b)) => a == b,
|
||||
(Self::Rapid(a), Self::Rapid(b)) => a == b,
|
||||
(Self::Rapid(a), Self::SemVer(b)) => a == b,
|
||||
(Self::Rapid(a), Self::Extended(b)) => a == b,
|
||||
(Self::SemVer(a), Self::Simple(b)) => a == b,
|
||||
(Self::SemVer(a), Self::Rapid(b)) => a == b,
|
||||
(Self::SemVer(a), Self::SemVer(b)) => a == b,
|
||||
(Self::SemVer(a), Self::Extended(b)) => a == b,
|
||||
(Self::Extended(a), Self::Simple(b)) => a == b,
|
||||
(Self::Extended(a), Self::Rapid(b)) => a == b,
|
||||
(Self::Extended(a), Self::SemVer(b)) => a == b,
|
||||
(Self::Extended(a), Self::Extended(b)) => a == b,
|
||||
(Self::GitRev(a), Self::GitRev(b)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Kind {}
|
||||
|
||||
impl PartialOrd for Kind {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match (self, other) {
|
||||
(Self::Simple(a), Self::Simple(b)) => a.partial_cmp(b),
|
||||
(Self::Simple(a), Self::Rapid(b)) => a.partial_cmp(b),
|
||||
(Self::Simple(a), Self::SemVer(b)) => a.partial_cmp(b),
|
||||
(Self::Simple(a), Self::Extended(b)) => a.partial_cmp(b),
|
||||
(Self::Rapid(a), Self::Simple(b)) => a.partial_cmp(b),
|
||||
(Self::Rapid(a), Self::Rapid(b)) => a.partial_cmp(b),
|
||||
(Self::Rapid(a), Self::SemVer(b)) => a.partial_cmp(b),
|
||||
(Self::Rapid(a), Self::Extended(b)) => a.partial_cmp(b),
|
||||
(Self::SemVer(a), Self::Simple(b)) => a.partial_cmp(b),
|
||||
(Self::SemVer(a), Self::Rapid(b)) => a.partial_cmp(b),
|
||||
(Self::SemVer(a), Self::SemVer(b)) => a.partial_cmp(b),
|
||||
(Self::SemVer(a), Self::Extended(b)) => a.partial_cmp(b),
|
||||
(Self::Extended(a), Self::Simple(b)) => a.partial_cmp(b),
|
||||
(Self::Extended(a), Self::Rapid(b)) => a.partial_cmp(b),
|
||||
(Self::Extended(a), Self::SemVer(b)) => a.partial_cmp(b),
|
||||
(Self::Extended(a), Self::Extended(b)) => a.partial_cmp(b),
|
||||
(Self::GitRev(a), Self::GitRev(b)) => a.partial_cmp(b),
|
||||
_ => None,
|
||||
let arch: Arch = arch.parse()?;
|
||||
let (s, pre) = match s.split_once('_') {
|
||||
Some((a, b)) => (a, b.parse::<PreRelease>()?),
|
||||
None => (s, PreRelease::None),
|
||||
};
|
||||
let mut split = s.split('.');
|
||||
let Some(Ok(major)) = split.next().map(|m| m.parse::<u16>()) else {
|
||||
return Err(Error::ParseSemver);
|
||||
};
|
||||
if major > MAX_U12 {
|
||||
return Err(Error::Range);
|
||||
};
|
||||
let minor: u16 = match split.next().map(|m| m.parse()) {
|
||||
Some(Ok(m)) => {
|
||||
if m <= MAX_U12 {
|
||||
m
|
||||
} else {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => return Err(e.into()),
|
||||
None => {
|
||||
return Ok(Self {
|
||||
kind: Kind::Simple { major },
|
||||
pre,
|
||||
arch,
|
||||
})
|
||||
}
|
||||
};
|
||||
let patch: u16 = match split.next().map(|p| p.parse()) {
|
||||
Some(Ok(p)) => {
|
||||
if p < MAX_U12 {
|
||||
p
|
||||
} else {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => return Err(e.into()),
|
||||
None => {
|
||||
return Ok(Self {
|
||||
kind: Kind::Rapid { major, minor },
|
||||
pre,
|
||||
arch,
|
||||
})
|
||||
}
|
||||
};
|
||||
let build: u16 = match split.next().map(|b| b.parse()) {
|
||||
Some(Ok(b)) => {
|
||||
if b <= MAX_U12 {
|
||||
b
|
||||
} else {
|
||||
return Err(Error::Range);
|
||||
}
|
||||
}
|
||||
Some(Err(e)) => return Err(e.into()),
|
||||
None => {
|
||||
return Ok(Self {
|
||||
kind: Kind::SemVer {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
},
|
||||
pre,
|
||||
arch,
|
||||
})
|
||||
}
|
||||
};
|
||||
match split.next() {
|
||||
Some(_) => Err(Error::ParseVersion),
|
||||
None => Ok(Self {
|
||||
kind: Kind::Extended {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
build,
|
||||
},
|
||||
pre,
|
||||
arch,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Version {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0 && self.1 == other.1
|
||||
u128::from(*self) == u128::from(*other) && self.arch == other.arch
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Version {}
|
||||
|
||||
impl Ord for Version {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
u128::from(*self).cmp(&u128::from(*other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Version {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
if self.1 == other.1 {
|
||||
self.0.partial_cmp(&other.0)
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
if self.arch == other.arch {
|
||||
Some(self.cmp(other))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::num::NonZeroU16;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
let mut version: Version = "2.4.1_alpha2-aarch64".parse().unwrap();
|
||||
assert_eq!(
|
||||
version,
|
||||
Version(
|
||||
Kind::SemVer(SemVer {
|
||||
major: 2,
|
||||
minor: 4,
|
||||
patch: 1,
|
||||
pre: crate::prerelease::PreRelease::Alpha(Some(NonZeroU16::new(2).unwrap()))
|
||||
}),
|
||||
Arch::Arm64
|
||||
)
|
||||
);
|
||||
version = "6.4-i486".parse().unwrap();
|
||||
assert_eq!(
|
||||
version,
|
||||
Version(
|
||||
Kind::Rapid(Rapid {
|
||||
major: 6,
|
||||
minor: 4,
|
||||
pre: crate::prerelease::PreRelease::None,
|
||||
}),
|
||||
Arch::X86,
|
||||
)
|
||||
);
|
||||
version = "git_r2d2xxx.1705881493-amd64".parse().unwrap();
|
||||
assert_eq!(
|
||||
version,
|
||||
Version(
|
||||
Kind::GitRev(GitRev {
|
||||
hash: "r2d2xxx".to_string(),
|
||||
datetime: DateTime::<Utc>::from_timestamp(1705881493, 0).unwrap(),
|
||||
}),
|
||||
Arch::X86_64,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user