Add SemVer struct and related impl's

This commit is contained in:
Nathan Fisher 2024-01-05 19:05:34 -05:00
parent bb187d4f8c
commit 8009575765
3 changed files with 103 additions and 2 deletions

View File

@ -1,8 +1,13 @@
use std::{fmt, num::TryFromIntError}; use std::{
fmt,
num::{ParseIntError, TryFromIntError},
};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
FromUint, FromUint,
Range,
ParseInt,
ParsePreRelease, ParsePreRelease,
ParseSemver, ParseSemver,
TryFromInt, TryFromInt,
@ -21,3 +26,9 @@ impl From<TryFromIntError> for Error {
Self::TryFromInt Self::TryFromInt
} }
} }
impl From<ParseIntError> for Error {
fn from(_value: ParseIntError) -> Self {
Self::ParseInt
}
}

View File

@ -1,4 +1,7 @@
mod error; mod error;
mod prerelease; mod prerelease;
mod semver;
pub use {error::Error, prerelease::PreRelease}; pub use {error::Error, prerelease::PreRelease, semver::SemVer};
pub static MAX_U12: u16 = 4096;

View File

@ -0,0 +1,87 @@
use {
crate::{Error, PreRelease, 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 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))
}
}