alfred_workflow_rust_project/
version.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Serialize, Deserialize, PartialEq)]
5pub struct Version {
6 major: u8,
7 minor: u8,
8 patch: u8,
9 build: Option<String>,
10}
11
12const SUFFIX_CANDIDATE: [&str; 2] = ["M", "RC"];
13
14impl Version {
15 pub fn new(version_str: &str) -> Result<Version, &'static str> {
16 let vp: Vec<&str> = version_str.split(".").collect();
17 if vp.len() != 3 {
18 return Err("version should be like 1.0.0 or 1.2.3 or 1.2.3-RC");
19 }
20
21 let path_with_build = vp.get(2).unwrap();
22 let vb: Vec<&str> = path_with_build.split("-").collect();
23 if vb.len() > 2 {
24 return Err("version should be like 1.0.0 or 1.2.3 or 1.2.3-RC");
25 }
26
27 let major_with_prefix = vp.get(0).unwrap();
28 let mut major_str = major_with_prefix.to_string();
29 if major_str.starts_with("v") {
30 major_str = major_str.to_uppercase().replace("V", "");
31 }
32
33 let version = Version {
34 major: major_str.parse().unwrap(),
35 minor: vp.get(1).unwrap().parse().unwrap(),
36 patch: vb.get(0).unwrap().parse().unwrap(),
37 build: if vb.len() == 2 {
38 Some(vb.get(1).unwrap().to_string())
39 } else {
40 None
41 },
42 };
43
44 if version.build.is_some() {
45 let suffix = version.build.as_ref().unwrap();
46 let mut build_valid = false;
47 for suf in SUFFIX_CANDIDATE {
48 if suffix.starts_with(suf) {
49 build_valid = true;
50 }
51 }
52 if !build_valid {
53 return Err("Version suffix should be like RC1 or RC2");
54 }
55 }
56 Ok(version)
57 }
58
59 fn compare(&self, comparison: &Version) -> i8 {
60 let self_v_num = self.major * 100 + self.minor * 10 + self.patch;
61 let comp_v_num = comparison.major * 100 + comparison.minor * 10 + comparison.patch;
62 if self_v_num > comp_v_num {
63 return 1;
64 }
65
66 if self_v_num < comp_v_num {
67 return -1;
68 }
69
70 if self.build.is_some() && comparison.build.is_none() {
72 return -1;
73 }
74
75 if self.build.is_none() && comparison.build.is_some() {
76 return 1;
77 }
78
79 if self.build.is_none() && comparison.build.is_none() {
80 return 0;
81 }
82
83 let self_build_v: u8 = self
84 .build
85 .as_ref()
86 .unwrap()
87 .replace("RC", "0")
88 .parse()
89 .unwrap();
90 let comparison_build_v: u8 = comparison
91 .build
92 .as_ref()
93 .unwrap()
94 .replace("RC", "0")
95 .parse()
96 .unwrap();
97
98 return if self_build_v == comparison_build_v {
99 0
100 } else if self_build_v > comparison_build_v {
101 1
102 } else {
103 -1
104 };
105 }
106
107 pub fn gt(&self, com: &Version) -> bool {
108 if self.compare(com) == 1 {
109 true
110 } else {
111 false
112 }
113 }
114
115 pub fn eq(&self, com: &Version) -> bool {
116 if self.compare(com) == 0 {
117 true
118 } else {
119 false
120 }
121 }
122
123 pub fn lt(&self, com: &Version) -> bool {
124 !self.gt(com)
125 }
126}
127
128#[cfg(test)]
129mod version_unit_test {
130 use crate::version::Version;
131
132 #[test]
133 fn test_parse_version() {
134 let v = Version::new("1.2.3").unwrap();
135 assert_eq!(v.major, 1);
136 assert_eq!(v.minor, 2);
137 assert_eq!(v.patch, 3);
138 }
139
140 #[test]
141 fn test_parse_version_with_invalid() {
142 let v = Version::new("r1.2.3");
143 assert_eq!(v.is_err(), true);
144
145 let v2 = Version::new("1.2.3.RC");
146 assert_eq!(v2.is_err(), true);
147
148 let v3 = Version::new("1.2.3-RCX");
149 assert_eq!(v3.is_err(), true);
150
151 let v4 = Version::new("1.2.3.4-RC");
152 assert_eq!(v4.is_err(), true);
153 }
154
155 #[test]
156 fn test_parse_version_with_build() {
157 let v = Version::new("1.2.3-RC").unwrap();
158 assert_eq!(v.major, 1);
159 assert_eq!(v.minor, 2);
160 assert_eq!(v.patch, 3);
161 assert_eq!(v.build, Some("RC".to_string()));
162 }
163
164 #[test]
165 fn test_parse_version_with_prefix() {
166 let v = Version::new("v1.2.3").unwrap();
167 assert_eq!(v.major, 1);
168 assert_eq!(v.minor, 2);
169 assert_eq!(v.patch, 3);
170 }
171
172 #[test]
173 fn test_parse_version_with_prefix_build() {
174 let v = Version::new("v1.2.3-RC").unwrap();
175 assert_eq!(v.major, 1);
176 assert_eq!(v.minor, 2);
177 assert_eq!(v.patch, 3);
178 assert_eq!(v.build, Some("RC".to_string()))
179 }
180
181 #[test]
182 fn test_version_newer() {
183 let v = Version::new("1.2.3").unwrap();
184 let v2 = Version::new("2.2.3").unwrap();
185 assert_eq!(v.compare(&v2), -1);
186
187 let v3 = Version::new("1.3.3").unwrap();
188 assert_eq!(v.compare(&v3), -1);
189
190 let v4 = Version::new("1.2.4").unwrap();
191 assert_eq!(v.compare(&v4), -1);
192 }
193
194 #[test]
195 fn test_version_newer_with_prefix() {
196 let v = Version::new("v1.2.3").unwrap();
197 let v2 = Version::new("v2.2.3").unwrap();
198 assert_eq!(v.compare(&v2), -1);
199
200 let v3 = Version::new("v1.3.3").unwrap();
201 assert_eq!(v.compare(&v3), -1);
202
203 let v4 = Version::new("1.2.4").unwrap();
204 assert_eq!(v.compare(&v4), -1);
205 }
206
207 #[test]
208 fn test_version_newer_with_build() {
209 let v = Version::new("v1.2.3").unwrap();
210 let v2 = Version::new("v2.2.3").unwrap();
211 assert_eq!(v.compare(&v2), -1);
212
213 let v3 = Version::new("v1.3.3").unwrap();
214 assert_eq!(v.compare(&v3), -1);
215
216 let v4 = Version::new("1.2.4").unwrap();
217 assert_eq!(v.compare(&v4), -1);
218
219 let v5 = Version::new("1.2.3-RC").unwrap();
220 assert_eq!(v.compare(&v5), 1);
221
222 let v6 = Version::new("1.2.3-RC1").unwrap();
223 assert_eq!(v6.compare(&v5), 1);
224
225 let v7 = Version::new("1.2.3-RC2").unwrap();
226 assert_eq!(v7.compare(&v6), 1);
227 }
228
229 #[test]
230 fn test_version_equal() {
231 let _v = Version::new("1.2.3").unwrap();
232 let _v1 = Version::new("v1.2.3").unwrap();
233 }
234}