miden_assembly/library/
version.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use core::{
    fmt,
    str::{self, FromStr},
};

use crate::{
    diagnostics::Diagnostic, ByteReader, ByteWriter, Deserializable, DeserializationError,
    Serializable,
};

/// Represents a _Semantic Versioning_ version string, without pre-releases.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Version {
    /// The major version, incremented when breaking changes occur.
    pub major: u16,
    /// The minor version, incremented when new features or functionality is introduced.
    pub minor: u16,
    /// The patch version, incremented when non-breaking changes are made.
    pub patch: u16,
}

/// Construction
impl Version {
    /// Returns the current minimal version supported by the code in this crate.
    #[inline(always)]
    pub const fn min() -> Self {
        Self { major: 0, minor: 1, patch: 0 }
    }
}

/// Arithmetic
impl Version {
    /// Returns a new [Version] clamped to the major version
    ///
    /// This is useful for comparing two versions at major version granularity
    pub const fn to_nearest_major(self) -> Self {
        Self { minor: 0, patch: 0, ..self }
    }

    /// Returns a new [Version] clamped to the minor version
    ///
    /// This is useful for comparing two versions at minor version granularity
    pub const fn to_nearest_minor(self) -> Self {
        Self { patch: 0, ..self }
    }

    /// Return a new [Version] representing the next major version release
    pub const fn next_major(self) -> Self {
        Self {
            major: self.major + 1,
            minor: 0,
            patch: 0,
        }
    }

    /// Return a new [Version] representing the next minor version release
    pub const fn next_minor(self) -> Self {
        Self { minor: self.minor + 1, patch: 0, ..self }
    }

    /// Return a new [Version] representing the next patch release
    pub const fn next_patch(self) -> Self {
        Self { patch: self.patch + 1, ..self }
    }
}

impl Default for Version {
    fn default() -> Self {
        Self::min()
    }
}
impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}
impl Serializable for Version {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        target.write_u16(self.major);
        target.write_u16(self.minor);
        target.write_u16(self.patch);
    }
}
impl Deserializable for Version {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let major = source.read_u16()?;
        let minor = source.read_u16()?;
        let patch = source.read_u16()?;
        Ok(Self { major, minor, patch })
    }
}

/// Represents errors that occur when parsing a [Version]
#[derive(Debug, thiserror::Error, Diagnostic)]
pub enum VersionError {
    #[error("invalid version string: cannot be empty")]
    #[diagnostic()]
    Empty,
    #[error("invalid version string: missing minor component, expected MAJOR.MINOR.PATCH")]
    #[diagnostic()]
    MissingMinor,
    #[error("invalid version string: missing patch component, expected MAJOR.MINOR.PATCH")]
    #[diagnostic()]
    MissingPatch,
    #[error("invalid version string: could not parse major version: {0}")]
    #[diagnostic()]
    Major(core::num::ParseIntError),
    #[error("invalid version string: could not parse minor version: {0}")]
    #[diagnostic()]
    Minor(core::num::ParseIntError),
    #[error("invalid version string: could not parse patch version: {0}")]
    #[diagnostic()]
    Patch(core::num::ParseIntError),
    #[error(
        "invalid version string: unsupported pre-release version, \
        only MAJOR.MINOR.PATCH components are allowed"
    )]
    #[diagnostic()]
    Unsupported,
}

impl FromStr for Version {
    type Err = VersionError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        let mut components = value.split('.');

        let major = components
            .next()
            .ok_or(VersionError::Empty)?
            .parse::<u16>()
            .map_err(VersionError::Major)?;
        let minor = components
            .next()
            .ok_or(VersionError::MissingMinor)?
            .parse::<u16>()
            .map_err(VersionError::Minor)?;
        let patch = components
            .next()
            .ok_or(VersionError::MissingPatch)?
            .parse::<u16>()
            .map_err(VersionError::Patch)?;

        if components.next().is_some() {
            Err(VersionError::Unsupported)
        } else {
            Ok(Self { major, minor, patch })
        }
    }
}