app_version/lib.rs
1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/piot/app-version
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use std::fmt;
6use std::num::ParseIntError;
7use std::str::FromStr;
8
9/// A struct representing a semantic version.
10///
11/// This struct contains three components of a version: major, minor, and patch.
12/// It derives common traits for easy comparison and manipulation.
13///
14/// # Examples
15///
16/// Creating a new version:
17///
18/// ```
19/// use app_version::Version;
20///
21/// let version = Version::new(1,0,0);
22/// assert_eq!(version.major(), 1);
23/// assert_eq!(version.minor(), 0);
24/// assert_eq!(version.patch(), 0);
25/// ```
26///
27/// ## Comparison
28///
29/// Versions can be compared for equality:
30///
31/// ```
32/// use app_version::Version;
33///
34/// let version1 = Version::new(1,0,0);
35/// let version2 = Version::new(1,0,1);
36/// assert_ne!(version1, version2);
37/// ```
38#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
39pub struct Version {
40 major: u16,
41 minor: u16,
42 patch: u16,
43}
44
45impl Version {
46 /// Creates a new version.
47 ///
48 /// # Parameters
49 /// - `major`: The major version number.
50 /// - `minor`: The minor version number.
51 /// - `patch`: The patch version number.
52 ///
53 /// # Returns
54 /// A `Version` instance.
55 pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
56 Self {
57 major,
58 minor,
59 patch,
60 }
61 }
62
63 /// Returns the major version number.
64 pub const fn major(&self) -> u16 {
65 self.major
66 }
67
68 /// Returns the minor version number.
69 pub const fn minor(&self) -> u16 {
70 self.minor
71 }
72
73 /// Returns the patch version number.
74 pub const fn patch(&self) -> u16 {
75 self.patch
76 }
77
78 /// Increments the patch version.
79 pub fn increment_patch(&mut self) {
80 self.patch += 1;
81 }
82
83 /// Increments the minor version and resets patch to 0.
84 pub fn increment_minor(&mut self) {
85 self.minor += 1;
86 self.patch = 0;
87 }
88
89 /// Increments the major version and resets minor and patch to 0.
90 pub fn increment_major(&mut self) {
91 self.major += 1;
92 self.minor = 0;
93 self.patch = 0;
94 }
95
96 /// Checks if the current version is compatible with another version.
97 ///
98 /// # Parameters
99 /// - `other`: The other version to check compatibility against.
100 ///
101 /// # Returns
102 /// `true` if the versions are compatible, otherwise `false`.
103 pub fn is_compatible(&self, other: &Self) -> bool {
104 self.major == other.major
105 }
106}
107
108// Implement the `fmt::Display` trait for `Version`
109impl fmt::Display for Version {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
112 }
113}
114
115impl From<(u16, u16, u16)> for Version {
116 fn from(tuple: (u16, u16, u16)) -> Self {
117 Version::new(tuple.0, tuple.1, tuple.2)
118 }
119}
120
121#[derive(Debug)]
122pub enum VersionError {
123 ParseIntError(ParseIntError),
124 InvalidFormat,
125}
126
127impl From<ParseIntError> for VersionError {
128 fn from(error: ParseIntError) -> Self {
129 VersionError::ParseIntError(error)
130 }
131}
132
133impl fmt::Display for VersionError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 VersionError::InvalidFormat => write!(f, "Invalid version format"),
137 VersionError::ParseIntError(err) => write!(f, "Parse error: {}", err),
138 }
139 }
140}
141
142impl std::error::Error for VersionError {}
143
144impl FromStr for Version {
145 type Err = VersionError;
146
147 fn from_str(s: &str) -> Result<Self, Self::Err> {
148 let parts: Vec<&str> = s.split('.').collect();
149 if parts.len() != 3 {
150 return Err(VersionError::InvalidFormat);
151 }
152
153 let major = parts[0].parse::<u16>()?;
154 let minor = parts[1].parse::<u16>()?;
155 let patch = parts[2].parse::<u16>()?;
156
157 Ok(Version::new(major, minor, patch))
158 }
159}
160
161/// A trait that provides a version.
162///
163/// Implementers of this trait must define how to return the version
164/// associated with them. This is useful for encapsulating versioning
165/// logic within various components or libraries.
166///
167/// # Examples
168///
169/// A simple implementation of `VersionProvider`:
170///
171/// ```
172/// use app_version::{Version, VersionProvider};
173///
174/// struct MySoftware;
175///
176/// impl VersionProvider for MySoftware {
177/// fn version() -> Version {
178/// Version::new(1, 0, 0)
179/// }
180/// }
181///
182/// let my_version = MySoftware::version();
183/// assert_eq!(my_version, Version::new(1, 0, 0 ));
184/// ```
185
186pub trait VersionProvider {
187 fn version() -> Version;
188}