diff --git a/src/extended.rs b/src/extended.rs index 670bfee..63fcf6e 100644 --- a/src/extended.rs +++ b/src/extended.rs @@ -37,7 +37,7 @@ impl FromStr for Extended { }; let split = s.split('.').collect::>(); match split.len() { - 3 => { + 4 => { let major = split.first().unwrap().parse::()?; let minor = split.get(1).unwrap().parse::()?; let patch = split.get(2).unwrap().parse::()?; diff --git a/src/lib.rs b/src/lib.rs index 3558809..66249d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,13 @@ mod error; mod extended; mod prerelease; +mod rapid; mod semver; +mod simple; -pub use {error::Error, extended::Extended, prerelease::PreRelease, semver::SemVer}; +pub use { + error::Error, extended::Extended, prerelease::PreRelease, rapid::Rapid, semver::SemVer, + simple::Simple, +}; pub static MAX_U12: u16 = 4096; diff --git a/src/rapid.rs b/src/rapid.rs index e69de29..ef179a2 100644 --- a/src/rapid.rs +++ b/src/rapid.rs @@ -0,0 +1,95 @@ +use { + crate::{Error, PreRelease, 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 { + let (s, pre) = match s.split_once('_') { + Some((a, b)) => (a, b.parse::()?), + None => (s, PreRelease::None), + }; + let split = s.split('.').collect::>(); + match split.len() { + 2 => { + let major = split.first().unwrap().parse::()?; + let minor = split.get(1).unwrap().parse::()?; + if major > MAX_U12 || minor > MAX_U12 { + return Err(Error::Range); + } + Ok(Self { major, minor, pre }) + } + _ => Err(Error::ParseSemver), + } + } +} + +impl From 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 for Rapid { + type Error = Error; + + fn try_from(value: u64) -> Result { + 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 { + Some(self.cmp(other)) + } +} diff --git a/src/simple.rs b/src/simple.rs index e69de29..38fb3b9 100644 --- a/src/simple.rs +++ b/src/simple.rs @@ -0,0 +1,83 @@ +use { + crate::{Error, PreRelease, 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 { + let (s, pre) = match s.split_once('_') { + Some((a, b)) => (a, b.parse::()?), + None => (s, PreRelease::None), + }; + let major = s.parse::()?; + if major > MAX_U12 { + return Err(Error::Range); + } + Ok(Self { major, pre }) + } +} + +impl From 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 for Simple { + type Error = Error; + + fn try_from(value: u64) -> Result { + 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 { + Some(self.cmp(other)) + } +}