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, 10, 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
36impl Default for ManifestVersion {
37    fn default() -> Self {
38        Self::DEFAULT
39    }
40}
41
42impl fmt::Display for ManifestVersion {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        write!(f, "{}.{}.{}", self.0, self.1, self.2)
45    }
46}
47
48impl FromStr for ManifestVersion {
49    type Err = ManifestVersionError;
50
51    fn from_str(s: &str) -> Result<Self, Self::Err> {
52        let mut parts = s.splitn(Self::PARTS_COUNT as usize, Self::SEPARATOR);
53
54        let major = parts
55            .next()
56            .ok_or(ManifestVersionError::NoMajorVersion)?
57            .parse::<u16>()?;
58        let minor = parts
59            .next()
60            .ok_or(ManifestVersionError::NoMinorVersion)?
61            .parse::<u16>()?;
62        let patch = parts
63            .next()
64            .ok_or(ManifestVersionError::NoPatchVersion)?
65            .parse::<u16>()?;
66
67        Ok(Self(major, minor, patch))
68    }
69}
70
71impl TryFrom<CompactString> for ManifestVersion {
72    type Error = ManifestVersionError;
73
74    #[inline]
75    fn try_from(value: CompactString) -> Result<Self, Self::Error> {
76        value.parse()
77    }
78}
79
80#[cfg(feature = "serde")]
81impl serde::Serialize for ManifestVersion
82where
83    Self: fmt::Display,
84{
85    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86    where
87        S: serde::Serializer,
88    {
89        serializer.collect_str(&self)
90    }
91}