kellnr_common/
version.rs

1use std::cmp::Ordering;
2use std::convert::TryFrom;
3use std::fmt;
4use std::ops::Deref;
5
6use thiserror::Error;
7
8#[derive(Debug, Eq, Clone, serde::Serialize, serde::Deserialize)]
9pub struct Version(String);
10
11#[derive(Debug, Eq, PartialEq, Error)]
12pub enum VersionError {
13    #[error("Invalid SemVer")]
14    InvalidSemVer,
15}
16
17impl Version {
18    pub fn from_unchecked_str(version: &str) -> Self {
19        Self(version.to_string())
20    }
21}
22
23impl TryFrom<&str> for Version {
24    type Error = VersionError;
25
26    fn try_from(version: &str) -> Result<Self, Self::Error> {
27        Version::try_from(&version.to_string())
28    }
29}
30
31impl TryFrom<&String> for Version {
32    type Error = VersionError;
33
34    fn try_from(version: &String) -> Result<Self, Self::Error> {
35        match semver::Version::parse(version) {
36            Ok(sv) => Ok(Version(sv.to_string())),
37            Err(_) => Err(VersionError::InvalidSemVer),
38        }
39    }
40}
41
42impl AsRef<Version> for Version {
43    fn as_ref(&self) -> &Version {
44        self
45    }
46}
47
48impl Deref for Version {
49    type Target = String;
50
51    fn deref(&self) -> &Self::Target {
52        &self.0
53    }
54}
55
56impl Default for Version {
57    fn default() -> Self {
58        Version(semver::Version::new(0, 0, 0).to_string())
59    }
60}
61
62impl Ord for Version {
63    fn cmp(&self, other: &Self) -> Ordering {
64        let sv1 = semver::Version::parse(&self.to_string()).unwrap();
65        let sv2 = semver::Version::parse(&other.to_string()).unwrap();
66        sv1.cmp(&sv2)
67    }
68}
69
70impl PartialOrd for Version {
71    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
72        Some(self.cmp(other))
73    }
74}
75
76impl PartialEq for Version {
77    fn eq(&self, other: &Self) -> bool {
78        let sv1 = semver::Version::parse(&self.to_string()).unwrap();
79        let sv2 = semver::Version::parse(&other.to_string()).unwrap();
80        sv1 == sv2
81    }
82}
83
84impl fmt::Display for Version {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        write!(f, "{}", self.0)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn valid_package_versions() {
96        assert_eq!(Version::try_from("0.0.0").unwrap().to_string(), "0.0.0");
97        assert_eq!(Version::try_from("1.0.1").unwrap().to_string(), "1.0.1");
98        assert_eq!(
99            Version::try_from("23.123.343").unwrap().to_string(),
100            "23.123.343"
101        );
102        assert_eq!(
103            Version::try_from("2.43.3-alpha34").unwrap().to_string(),
104            "2.43.3-alpha34"
105        );
106        assert_eq!(
107            Version::try_from("0.1.1-45rdfsd-45").unwrap().to_string(),
108            "0.1.1-45rdfsd-45"
109        );
110    }
111
112    #[test]
113    fn invalid_package_versions() {
114        assert_eq!(
115            Version::try_from("a.1.2").unwrap_err(),
116            VersionError::InvalidSemVer
117        );
118        assert_eq!(
119            Version::try_from("002.23.1").unwrap_err(),
120            VersionError::InvalidSemVer
121        );
122        assert_eq!(
123            Version::try_from("3.2fg.3").unwrap_err(),
124            VersionError::InvalidSemVer
125        );
126        assert_eq!(
127            Version::try_from("5.3.2.3").unwrap_err(),
128            VersionError::InvalidSemVer
129        );
130    }
131}