simple_version/
lib.rs

1#![no_std]
2
3
4#[cfg(test)]
5mod tests;
6
7
8/// A struct that represents a version consisting of major, minor, patch, and an optional build number.
9/// 
10/// The generic parameter `T` specifies the numerical type to use for each version component.
11/// 
12/// ***
13/// # Examples
14///
15/// Creating a version without a build number:
16///
17/// ```rust
18/// use simple_version::Version;
19///
20/// let version: Version<u32> = Version::new(1, 2, 3);
21/// ```
22/// 
23/// ***
24///
25/// Creating a version with a build number:
26///
27/// ```rust
28/// use simple_version::Version;
29///
30/// let version: Version<u32> = Version::new(1, 2, 3).build(4);
31/// ```
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
33pub struct Version<T: Ord> {
34    /// The major version component.
35    /// 
36    /// ***
37    /// # Examples
38    /// 
39    /// ```rust
40    /// use simple_version::Version;
41    ///
42    /// let mut version = Version::<u32>::new(1, 2, 3);
43    /// 
44    /// // read major version
45    /// println!("{}", version.major);
46    /// 
47    /// // set major version
48    /// version.major = 4;
49    /// ```
50    pub major: T,
51
52    /// The minor version component.
53    /// 
54    /// ***
55    /// # Examples
56    /// 
57    /// ```rust
58    /// use simple_version::Version;
59    /// 
60    /// let mut version = Version::<u32>::new(1, 2, 3);
61    /// 
62    /// // read minor version
63    /// println!("{}", version.minor);
64    /// 
65    /// // set minor version
66    /// version.minor = 4;
67    /// ```
68    pub minor: T,
69
70    /// The patch version component.
71    /// 
72    /// ***
73    /// # Examples
74    /// 
75    /// ```rust
76    /// use simple_version::Version;
77    /// 
78    /// let mut version = Version::<u32>::new(1, 2, 3);
79    /// 
80    /// // read patch version
81    /// println!("{}", version.patch);
82    /// 
83    /// // set patch version
84    /// version.patch = 4;
85    /// ```
86    pub patch: T,
87
88    /// The optional build number.
89    /// 
90    /// ***
91    /// # Examples
92    /// 
93    /// ```rust
94    /// use simple_version::Version;
95    /// 
96    /// // version with a build number
97    /// let mut version = Version::<u32>::new(1, 2, 3).build(4);
98    /// 
99    /// // read build number
100    /// if let Some(build) = version.build {
101    ///     println!("{}", build);
102    /// }
103    /// 
104    /// // set build number
105    /// version.build = Some(5);
106    /// ```
107    pub build: Option<T>,
108}
109
110
111impl<T: Ord> Version<T> {
112    /// Creates a new `Version<T>` without a build number.
113    /// 
114    /// ***
115    /// # Arguments
116    /// 
117    /// - `major`: the major version component
118    /// - `minor`: the minor version component
119    /// - `patch`: the patch version component
120    /// 
121    /// ***
122    /// # Examples
123    /// 
124    /// ```rust
125    /// use simple_version::Version;
126    /// 
127    /// let version: Version<u32> = Version::new(1, 2, 3);
128    /// ```
129    pub fn new(major: T, minor: T, patch: T) -> Version<T> {
130        Version { major, minor, patch, build: None }
131    }
132
133    /// Adds a build number to the existing version object and returns it.
134    /// 
135    /// ***
136    /// # Arguments
137    /// 
138    /// - `build`: the build number
139    /// 
140    /// ***
141    /// # Examples
142    /// 
143    /// ```rust
144    /// use simple_version::Version;
145    /// 
146    /// let version: Version<u32> = Version::new(1, 2, 3).build(4);
147    /// ```
148    pub fn build(mut self, build: T) -> Version<T> {
149        self.build = Some(build);
150        self
151    }
152}
153
154
155impl<T: Ord + core::str::FromStr> Version<T> {
156    /// Creates a `Version<T>` from a string in the `major.minor.patch[+build]` format.
157    ///
158    /// Returns `None` if the string does not contain exactly three dot-separated segments
159    /// for the core version or if any component fails to parse into `T`.
160    ///
161    /// ***
162    /// # Examples
163    ///
164    /// ```rust
165    /// use simple_version::Version;
166    ///
167    /// let version = Version::<u32>::from_string("1.2.3").unwrap();
168    /// assert_eq!(version, Version::new(1, 2, 3));
169    ///
170    /// let version_with_build = Version::<u32>::from_string("1.2.3+4").unwrap();
171    /// assert_eq!(version_with_build, Version::new(1, 2, 3).build(4));
172    /// ```
173    pub fn from_string(version: &str) -> Option<Self> {
174        let (core_parts, build_part) = match version.split_once('+') {
175            Some((core, build)) => (core, Some(build)),
176            None => (version, None),
177        };
178
179        let mut iter = core_parts.split('.');
180        let major = iter.next()?.parse().ok()?;
181        let minor = iter.next()?.parse().ok()?;
182        let patch = iter.next()?.parse().ok()?;
183
184        // Ensure there are exactly three core components.
185        if iter.next().is_some() {
186            return None;
187        }
188
189        let build = match build_part {
190            Some(raw_build) => Some(raw_build.parse().ok()?),
191            None => None,
192        };
193
194        Some(Version { major, minor, patch, build })
195    }
196}
197
198
199impl<T: Ord + core::fmt::Display> core::fmt::Display for Version<T> {
200    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
201        if let Some(build) = &self.build {
202            write!(f, "{}.{}.{}+{}", self.major, self.minor, self.patch, build)
203        } else {
204            write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
205        }
206    }
207}
208
209
210/// Creates a new `Version<T>` from the `CARGO_PKG_VERSION` environment variable
211/// at compile time (i.e., from your crate's `Cargo.toml`).
212/// 
213/// ***
214/// # Examples
215/// 
216/// ```rust
217/// use simple_version::{Version, version_from_pkg};
218///
219/// let version: Version<u32> = version_from_pkg!(u32);
220/// // Now `version` might be e.g. 1.2.3 if your crate's version is "1.2.3"
221/// ```
222#[macro_export]
223macro_rules! version_from_pkg {
224    ($t:ty) => {{
225        let _major: $t = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap();
226        let _minor: $t = env!("CARGO_PKG_VERSION_MINOR").parse().unwrap();
227        let _patch: $t = env!("CARGO_PKG_VERSION_PATCH").parse().unwrap();
228        $crate::Version::new(_major, _minor, _patch)
229    }};
230}