206 lines
5.8 KiB
Rust
206 lines
5.8 KiB
Rust
use {
|
|
crate::{Rapid, Version},
|
|
serde::{Deserialize, Serialize},
|
|
std::{cmp::Ordering, error::Error, fmt, num::ParseIntError, str::FromStr},
|
|
};
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct SemVer {
|
|
pub major: u32,
|
|
pub minor: u32,
|
|
pub patch: u32,
|
|
}
|
|
|
|
impl fmt::Display for SemVer {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for SemVer {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
match self.major.partial_cmp(&other.major) {
|
|
Some(Ordering::Greater) => Some(Ordering::Greater),
|
|
Some(Ordering::Less) => Some(Ordering::Less),
|
|
None => None,
|
|
Some(Ordering::Equal) => match self.minor.partial_cmp(&other.minor) {
|
|
Some(Ordering::Greater) => Some(Ordering::Greater),
|
|
Some(Ordering::Less) => Some(Ordering::Less),
|
|
None => None,
|
|
Some(Ordering::Equal) => self.patch.partial_cmp(&other.patch),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ord for SemVer {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
match self.major.cmp(&other.major) {
|
|
Ordering::Greater => Ordering::Greater,
|
|
Ordering::Less => Ordering::Less,
|
|
Ordering::Equal => match self.minor.cmp(&other.minor) {
|
|
Ordering::Greater => Ordering::Greater,
|
|
Ordering::Less => Ordering::Less,
|
|
Ordering::Equal => self.patch.cmp(&other.patch),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq<Rapid> for SemVer {
|
|
fn eq(&self, other: &Rapid) -> bool {
|
|
self.major == other.major && self.minor == other.minor && self.patch == 0
|
|
}
|
|
}
|
|
|
|
impl PartialOrd<Rapid> for SemVer {
|
|
fn partial_cmp(&self, other: &Rapid) -> Option<std::cmp::Ordering> {
|
|
match self.major.partial_cmp(&other.major) {
|
|
Some(Ordering::Greater) => Some(Ordering::Greater),
|
|
Some(Ordering::Less) => Some(Ordering::Less),
|
|
None => None,
|
|
Some(Ordering::Equal) => match self.minor.partial_cmp(&other.minor) {
|
|
Some(Ordering::Greater) => Some(Ordering::Greater),
|
|
Some(Ordering::Less) => Some(Ordering::Less),
|
|
None => None,
|
|
Some(Ordering::Equal) => match self.patch {
|
|
0 => Some(Ordering::Equal),
|
|
_ => Some(Ordering::Greater),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq<u32> for SemVer {
|
|
fn eq(&self, other: &u32) -> bool {
|
|
self.major == *other && self.minor == 0 && self.patch == 0
|
|
}
|
|
}
|
|
|
|
impl PartialOrd<u32> for SemVer {
|
|
fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
|
|
match self.major.cmp(other) {
|
|
Ordering::Greater => Some(Ordering::Greater),
|
|
Ordering::Less => Some(Ordering::Less),
|
|
Ordering::Equal => {
|
|
if self.minor == 0 && self.patch == 0 {
|
|
Some(Ordering::Equal)
|
|
} else {
|
|
Some(Ordering::Greater)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq<SemVer> for u32 {
|
|
fn eq(&self, other: &SemVer) -> bool {
|
|
other.eq(self)
|
|
}
|
|
}
|
|
|
|
impl PartialOrd<SemVer> for u32 {
|
|
fn partial_cmp(&self, other: &SemVer) -> Option<Ordering> {
|
|
match other.partial_cmp(self) {
|
|
Some(Ordering::Less) => Some(Ordering::Greater),
|
|
Some(Ordering::Greater) => Some(Ordering::Less),
|
|
Some(Ordering::Equal) => Some(Ordering::Equal),
|
|
None => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub struct ParseSemVerError;
|
|
|
|
impl fmt::Display for ParseSemVerError {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Error parsing SemVer")
|
|
}
|
|
}
|
|
|
|
impl Error for ParseSemVerError {}
|
|
|
|
impl From<ParseIntError> for ParseSemVerError {
|
|
fn from(_value: ParseIntError) -> Self {
|
|
Self
|
|
}
|
|
}
|
|
|
|
impl FromStr for SemVer {
|
|
type Err = ParseSemVerError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let split = s.split('.').collect::<Vec<_>>();
|
|
match split.len() {
|
|
3 => {
|
|
let major = split.first().unwrap().parse::<u32>()?;
|
|
let minor = split.get(1).unwrap().parse::<u32>()?;
|
|
let patch = split.get(2).unwrap().parse::<u32>()?;
|
|
Ok(Self {
|
|
major,
|
|
minor,
|
|
patch,
|
|
})
|
|
}
|
|
_ => Err(ParseSemVerError),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<Version> for SemVer {
|
|
type Error = ParseSemVerError;
|
|
fn try_from(value: Version) -> Result<Self, Self::Error> {
|
|
match value {
|
|
Version::SemVer(s) => Ok(SemVer {
|
|
major: s.major,
|
|
minor: s.minor,
|
|
patch: s.patch,
|
|
}),
|
|
Version::Rapid(r) => Ok(SemVer {
|
|
major: r.major,
|
|
minor: r.minor,
|
|
patch: 0,
|
|
}),
|
|
Version::Number(n) => Ok(Self {
|
|
major: n,
|
|
minor: 0,
|
|
patch: 0,
|
|
}),
|
|
Version::Git(_) => Err(ParseSemVerError),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn parse_semver() {
|
|
assert_eq!(
|
|
"1.0.3".parse::<SemVer>(),
|
|
Ok(SemVer {
|
|
major: 1,
|
|
minor: 0,
|
|
patch: 3
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cmp_semver_num_gt() {
|
|
let sem = "42.69.0".parse::<SemVer>().unwrap();
|
|
let num = 42;
|
|
assert!(sem > num);
|
|
}
|
|
|
|
#[test]
|
|
fn cmp_semver_num_eq() {
|
|
let sem = "42.0.0".parse::<SemVer>().unwrap();
|
|
let num = 42;
|
|
assert_eq!(sem, num);
|
|
}
|
|
}
|