#![deny(missing_docs)]
use std::fmt;
use std::str::FromStr;
use crate::parsers::original;
pub use parsers::{BaseVersionParser, FullVersionParser, ParserError, VersionParser};
pub use version::{BaseVersion, FullVersion};
pub mod parsers;
mod version;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
ParserError(#[from] ParserError),
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub enum Version {
Base(BaseVersion),
Full(FullVersion),
}
impl Version {
pub fn parse(input: &str) -> Result<Self, Error> {
original::Parser::from(input.as_bytes())
.parse()
.map_err(|e| Error::from(Into::<ParserError>::into(e)))
}
pub fn new_base_version(major: u64, minor: u64) -> Self {
Self::Base(BaseVersion { major, minor })
}
pub fn new_full_version(major: u64, minor: u64, patch: u64) -> Self {
Self::Full(FullVersion {
major,
minor,
patch,
})
}
pub fn major(&self) -> u64 {
match self {
Self::Base(inner) => inner.major,
Self::Full(inner) => inner.major,
}
}
pub fn minor(&self) -> u64 {
match self {
Self::Base(inner) => inner.minor,
Self::Full(inner) => inner.minor,
}
}
pub fn patch(&self) -> Option<u64> {
match self {
Self::Base(_) => None,
Self::Full(inner) => Some(inner.patch),
}
}
pub fn is(&self, variant: Variant) -> bool {
match self {
Version::Base(_) => matches!(variant, Variant::Base),
Version::Full(_) => matches!(variant, Variant::Full),
}
}
#[inline]
pub fn map<U, F>(self, fun: F) -> U
where
F: FnOnce(Self) -> U,
{
fun(self)
}
#[inline]
pub fn map_major<F>(self, fun: F) -> Self
where
F: FnOnce(u64) -> u64,
{
self.map(|v| match v {
Self::Base(base) => Version::Base(BaseVersion::new(fun(base.major), base.minor)),
Self::Full(full) => {
Version::Full(FullVersion::new(fun(full.major), full.minor, full.patch))
}
})
}
#[inline]
pub fn map_minor<F>(self, fun: F) -> Self
where
F: FnOnce(u64) -> u64,
{
self.map(|v| match v {
Self::Base(base) => Version::Base(BaseVersion::new(base.major, fun(base.minor))),
Self::Full(full) => {
Version::Full(FullVersion::new(full.major, fun(full.minor), full.patch))
}
})
}
#[inline]
pub fn map_patch<F>(self, fun: F) -> Self
where
F: FnOnce(u64) -> u64,
{
self.map(|v| match v {
Self::Base(base) => Version::Base(BaseVersion::new(base.major, base.minor)),
Self::Full(full) => {
Version::Full(FullVersion::new(full.major, full.minor, fun(full.patch)))
}
})
}
}
impl FromStr for Version {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Error> {
original::Parser::from_slice(input.as_bytes())
.parse()
.map_err(|e| Error::from(Into::<ParserError>::into(e)))
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Base(inner) => fmt::Display::fmt(&inner, f),
Self::Full(inner) => fmt::Display::fmt(&inner, f),
}
}
}
impl From<(u64, u64)> for Version {
fn from(tuple: (u64, u64)) -> Self {
Self::Base(BaseVersion::from(tuple))
}
}
impl From<(u64, u64, u64)> for Version {
fn from(tuple: (u64, u64, u64)) -> Self {
Self::Full(FullVersion::from(tuple))
}
}
#[derive(Copy, Clone, Debug)]
pub enum Variant {
Base,
Full,
}
#[cfg(test)]
mod tests {
use crate::{BaseVersion, FullVersion, Variant, Version};
#[test]
fn is_base_variant() {
let version = Version::Base(BaseVersion::new(0, 0));
assert!(version.is(Variant::Base));
assert!(!version.is(Variant::Full));
}
#[test]
fn is_full_variant() {
let version = Version::Full(FullVersion::new(0, 0, 0));
assert!(version.is(Variant::Full));
assert!(!version.is(Variant::Base));
}
#[test]
fn map() {
let version = Version::Base(BaseVersion::new(0, 0));
let mapped = version.map(|v| match v {
Version::Base(base) => Version::Full(FullVersion::new(base.major, base.minor, 999)),
v => v,
});
assert_eq!(mapped, Version::Full(FullVersion::new(0, 0, 999)));
}
#[yare::parameterized(
base = { Version::Base(BaseVersion::new(0, 0)) },
full = { Version::Full(FullVersion::new(0, 0, 0)) },
)]
fn map_major(version: Version) {
let mapped = version.map_major(|_v| 999);
assert_eq!(mapped.major(), 999);
}
#[yare::parameterized(
base = { Version::Base(BaseVersion::new(0, 0)) },
full = { Version::Full(FullVersion::new(0, 0, 0)) },
)]
fn map_minor(version: Version) {
let mapped = version.map_minor(|_v| 999);
assert_eq!(mapped.minor(), 999);
}
#[test]
fn map_patch_base() {
let version = Version::Base(BaseVersion::new(0, 0));
let mapped = version.map_patch(|_v| 999);
assert!(mapped.patch().is_none());
}
#[test]
fn map_patch_full() {
let version = Version::Full(FullVersion::new(0, 0, 0));
let mapped = version.map_patch(|_v| 999);
assert_eq!(mapped.patch().unwrap(), 999);
}
}