fast_version_core/
version.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use std::str::FromStr;
4use thiserror::Error;
5
6
7/// Version in a SemVer **like** way.
8///
9/// ## Example:
10/// ```
11/// # use fast_version_core::version::Version;
12/// use std::str::FromStr;
13///
14/// const version_str: &'static str = "1.2.3";
15///
16/// let version = Version::from_str(version_str).unwrap();
17/// assert_eq!(version.major, 1);
18/// assert_eq!(version.minor, 2);
19/// assert_eq!(version.patch, 3);
20///
21/// let version_out_str = version.to_string();
22/// assert_eq!(&version_out_str, version_str);
23/// ```
24///
25/// This crate is heavily optimized to allow compile-time evaluation:
26/// ```
27/// # use fast_version_core::version::Version;
28/// const VERSION: Version = Version::new(1, 2, 3);
29///
30/// assert_eq!(VERSION.major, 1);
31/// assert_eq!(VERSION.minor, 2);
32/// assert_eq!(VERSION.patch, 3);
33/// ```
34#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub struct Version {
37    pub major: u64,
38    pub minor: u64,
39    pub patch: u64,
40}
41
42impl PartialOrd for Version {
43    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
44        let major_ordering = self.major.partial_cmp(&other.major);
45        if let Some(d) = major_ordering {
46            if d.is_ne() {
47                return Some(d);
48            }
49        }
50        let minor_ordering = self.minor.partial_cmp(&other.minor);
51        if let Some(d) = minor_ordering {
52            if d.is_ne() {
53                return Some(d);
54            }
55        }
56        self.patch.partial_cmp(&other.patch)
57    }
58}
59
60impl Ord for Version {
61    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
62        let major_ordering = self.major.cmp(&other.major);
63        if major_ordering.is_ne() {
64            return major_ordering;
65        }
66        let minor_ordering = self.minor.cmp(&other.minor);
67        if minor_ordering.is_ne() {
68            return minor_ordering;
69        }
70        self.patch.cmp(&other.patch)
71    }
72}
73
74impl Version {
75    /// Create a new version from major, minor and patch.
76    /// ```
77    /// # use fast_version_core::version::Version;
78    ///
79    /// let version = Version::new(1, 2, 3);
80    ///
81    /// assert_eq!(version.major, 1);
82    /// assert_eq!(version.minor, 2);
83    /// assert_eq!(version.patch, 3);
84    /// ```
85    #[inline]
86    pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
87        Version {
88            major,
89            minor,
90            patch,
91        }
92    }
93
94    pub fn new_from_str(input: &str) -> Result<Self, VersionParseError> {
95        let splits: Vec<&str> = input.split('.').collect();
96        if splits.len() != 3 {
97            return Err(VersionParseError::FormatWrong);
98        }
99        let major_str = splits.get(0).unwrap();
100        let major = u64::from_str(major_str).map_err(|_| VersionParseError::MajorParseError)?;
101        let minor_str = splits.get(1).unwrap();
102        let minor = u64::from_str(minor_str).map_err(|_| VersionParseError::MinorParseError)?;
103        let patch_str = splits.get(2).unwrap();
104        let patch = u64::from_str(patch_str).map_err(|_| VersionParseError::PatchParseError)?;
105        Ok(Self::new(major, minor, patch))
106    }
107}
108
109#[derive(Error, Debug)]
110pub enum VersionParseError {
111    #[error("Format of version string is wrong")]
112    FormatWrong,
113    #[error("Parsing error in major")]
114    MajorParseError,
115    #[error("Major element was not found")]
116    MajorNotFound,
117    #[error("Minor Parse Error")]
118    MinorParseError,
119    #[error("Minor element was not found")]
120    MinorNotFound,
121    #[error("Patch Parse Error")]
122    PatchParseError,
123    #[error("Patch element was not found")]
124    PatchNotFound,
125}
126
127impl FromStr for Version {
128    type Err = VersionParseError;
129    fn from_str(s: &str) -> Result<Self, Self::Err> {
130        Self::new_from_str(s)
131    }
132}
133
134#[cfg(feature = "alloc")]
135impl ToString for Version {
136    fn to_string(&self) -> String {
137        format!("{}.{}.{}", self.major, self.minor, self.patch)
138    }
139}