use std::fmt;
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
pub struct Version {
major: u16,
minor: u16,
patch: u16,
}
impl Version {
pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
Self {
major,
minor,
patch,
}
}
pub const fn major(&self) -> u16 {
self.major
}
pub const fn minor(&self) -> u16 {
self.minor
}
pub const fn patch(&self) -> u16 {
self.patch
}
pub fn increment_patch(&mut self) {
self.patch += 1;
}
pub fn increment_minor(&mut self) {
self.minor += 1;
self.patch = 0;
}
pub fn increment_major(&mut self) {
self.major += 1;
self.minor = 0;
self.patch = 0;
}
pub fn is_compatible(&self, other: &Self) -> bool {
self.major == other.major
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl From<(u16, u16, u16)> for Version {
fn from(tuple: (u16, u16, u16)) -> Self {
Version::new(tuple.0, tuple.1, tuple.2)
}
}
#[derive(Debug)]
pub enum VersionError {
ParseIntError(ParseIntError),
InvalidFormat,
}
impl From<ParseIntError> for VersionError {
fn from(error: ParseIntError) -> Self {
VersionError::ParseIntError(error)
}
}
impl fmt::Display for VersionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VersionError::InvalidFormat => write!(f, "Invalid version format"),
VersionError::ParseIntError(err) => write!(f, "Parse error: {}", err),
}
}
}
impl std::error::Error for VersionError {}
impl FromStr for Version {
type Err = VersionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() != 3 {
return Err(VersionError::InvalidFormat);
}
let major = parts[0].parse::<u16>()?;
let minor = parts[1].parse::<u16>()?;
let patch = parts[2].parse::<u16>()?;
Ok(Version::new(major, minor, patch))
}
}
pub trait VersionProvider {
fn version() -> Version;
}