use std::fmt::Display;
#[derive(Debug, thiserror::Error)]
pub enum VersionError {
#[error("the version cannot be negative: {major}.{minor}")]
Negative {
major: i32,
minor: i32,
},
#[error("the version of an interface cannot be 0.0")]
Zero,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InterfaceVersion {
version_major: i32,
version_minor: i32,
}
impl InterfaceVersion {
pub fn try_new(version_major: i32, version_minor: i32) -> Result<Self, VersionError> {
if version_major.is_negative() || version_minor.is_negative() {
return Err(VersionError::Negative {
major: version_major,
minor: version_minor,
});
}
if version_major == 0 && version_minor == 0 {
return Err(VersionError::Zero);
}
Ok(Self {
version_major,
version_minor,
})
}
#[must_use]
pub fn version_major(&self) -> i32 {
self.version_major
}
#[must_use]
pub fn version_minor(&self) -> i32 {
self.version_minor
}
}
impl Display for InterfaceVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}", self.version_major, self.version_minor)
}
}
impl From<&InterfaceVersion> for (i32, i32) {
fn from(value: &InterfaceVersion) -> Self {
(value.version_major, value.version_minor)
}
}
impl From<InterfaceVersion> for (i32, i32) {
fn from(value: InterfaceVersion) -> Self {
(value.version_major, value.version_minor)
}
}
impl TryFrom<(i32, i32)> for InterfaceVersion {
type Error = VersionError;
fn try_from((major, minor): (i32, i32)) -> Result<Self, Self::Error> {
Self::try_new(major, minor)
}
}
impl Default for InterfaceVersion {
fn default() -> Self {
Self {
version_major: 0,
version_minor: 1,
}
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn check_into() {
let ver = InterfaceVersion::try_from((0, 1)).unwrap();
let ver: (i32, i32) = ver.into();
assert_eq!(ver, (0, 1));
}
#[test]
fn check_negative() {
InterfaceVersion::try_from((0, -1)).unwrap_err();
InterfaceVersion::try_from((-1, 0)).unwrap_err();
InterfaceVersion::try_from((-1, -1)).unwrap_err();
}
#[test]
fn check_zero() {
InterfaceVersion::try_from((0, 0)).unwrap_err();
}
#[test]
fn check_default() {
assert_eq!(
InterfaceVersion::default(),
InterfaceVersion {
version_major: 0,
version_minor: 1
}
);
}
#[test]
fn check_getters() {
let ver = InterfaceVersion::default();
assert_eq!(ver.version_major(), 0);
assert_eq!(ver.version_minor(), 1);
}
#[test]
fn check_display() {
let ver = InterfaceVersion::try_from((0, 1)).unwrap().to_string();
assert_eq!(ver, "0.1");
}
}