winget_types/shared/
manifest_version.rs

1use core::{fmt, num::ParseIntError, str::FromStr};
2
3use compact_str::CompactString;
4use thiserror::Error;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(try_from = "CompactString"))]
9pub struct ManifestVersion(u16, u16, u16);
10
11#[derive(Error, Debug, Eq, PartialEq)]
12pub enum ManifestVersionError {
13    #[error("Manifest version must have a major part")]
14    NoMajorVersion,
15    #[error("Manifest version must have a minor part")]
16    NoMinorVersion,
17    #[error("Manifest version must have a patch part")]
18    NoPatchVersion,
19    #[error(transparent)]
20    InvalidPart(#[from] ParseIntError),
21}
22
23impl ManifestVersion {
24    pub const DEFAULT: Self = Self(1, 12, 0);
25    const PARTS_COUNT: u8 = 3;
26    const SEPARATOR: char = '.';
27
28    /// Creates a new `ManifestVersion` from a `major`, `minor`, and `patch` part.
29    #[must_use]
30    #[inline]
31    pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
32        Self(major, minor, patch)
33    }
34
35    /// Returns the major version.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// # use winget_types::ManifestVersion;
41    /// let minimum_os_version = ManifestVersion::new(1, 9, 0);
42    /// assert_eq!(minimum_os_version.major(), 1);
43    /// ```
44    #[must_use]
45    #[inline]
46    pub const fn major(&self) -> u16 {
47        self.0
48    }
49
50    /// Returns the minor version.
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// # use winget_types::ManifestVersion;
56    /// let minimum_os_version = ManifestVersion::new(1, 9, 0);
57    /// assert_eq!(minimum_os_version.minor(), 9);
58    /// ```
59    #[must_use]
60    #[inline]
61    pub const fn minor(&self) -> u16 {
62        self.1
63    }
64
65    /// Returns the patch version.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// # use winget_types::ManifestVersion;
71    /// let minimum_os_version = ManifestVersion::new(1, 9, 0);
72    /// assert_eq!(minimum_os_version.patch(), 0);
73    /// ```
74    #[must_use]
75    #[inline]
76    pub const fn patch(&self) -> u16 {
77        self.2
78    }
79}
80
81impl Default for ManifestVersion {
82    fn default() -> Self {
83        Self::DEFAULT
84    }
85}
86
87impl fmt::Display for ManifestVersion {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        write!(f, "{}.{}.{}", self.0, self.1, self.2)
90    }
91}
92
93impl FromStr for ManifestVersion {
94    type Err = ManifestVersionError;
95
96    fn from_str(s: &str) -> Result<Self, Self::Err> {
97        let mut parts = s.splitn(Self::PARTS_COUNT as usize, Self::SEPARATOR);
98
99        let major = parts
100            .next()
101            .ok_or(ManifestVersionError::NoMajorVersion)?
102            .parse::<u16>()?;
103        let minor = parts
104            .next()
105            .ok_or(ManifestVersionError::NoMinorVersion)?
106            .parse::<u16>()?;
107        let patch = parts
108            .next()
109            .ok_or(ManifestVersionError::NoPatchVersion)?
110            .parse::<u16>()?;
111
112        Ok(Self::new(major, minor, patch))
113    }
114}
115
116impl From<(u16, u16, u16)> for ManifestVersion {
117    fn from((major, minor, patch): (u16, u16, u16)) -> Self {
118        Self::new(major, minor, patch)
119    }
120}
121
122impl TryFrom<CompactString> for ManifestVersion {
123    type Error = ManifestVersionError;
124
125    #[inline]
126    fn try_from(value: CompactString) -> Result<Self, Self::Error> {
127        value.parse()
128    }
129}
130
131#[cfg(feature = "serde")]
132impl serde::Serialize for ManifestVersion
133where
134    Self: fmt::Display,
135{
136    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137    where
138        S: serde::Serializer,
139    {
140        serializer.collect_str(&self)
141    }
142}