substrate_wasm_builder/
version.rs1use std::cmp::Ordering;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct Version {
23 pub major: u32,
24 pub minor: u32,
25 pub patch: u32,
26 pub is_nightly: bool,
27 pub year: Option<u32>,
28 pub month: Option<u32>,
29 pub day: Option<u32>,
30}
31
32impl Version {
33 pub fn is_stable(&self) -> bool {
35 !self.is_nightly
36 }
37
38 pub fn is_nightly(&self) -> bool {
40 self.is_nightly
41 }
42
43 pub fn extract(version: &str) -> Option<Self> {
45 let mut is_nightly = false;
46 let version_parts = version
47 .trim()
48 .split(" ")
49 .nth(1)?
50 .split(".")
51 .filter_map(|v| {
52 if let Some(rest) = v.strip_suffix("-nightly") {
53 is_nightly = true;
54 rest.parse().ok()
55 } else {
56 v.parse().ok()
57 }
58 })
59 .collect::<Vec<u32>>();
60
61 if version_parts.len() != 3 {
62 return None
63 }
64
65 let date_parts = version
66 .split(" ")
67 .nth(3)
68 .map(|date| {
69 date.split("-")
70 .filter_map(|v| v.trim().strip_suffix(")").unwrap_or(v).parse().ok())
71 .collect::<Vec<u32>>()
72 })
73 .unwrap_or_default();
74
75 Some(Version {
76 major: version_parts[0],
77 minor: version_parts[1],
78 patch: version_parts[2],
79 is_nightly,
80 year: date_parts.get(0).copied(),
81 month: date_parts.get(1).copied(),
82 day: date_parts.get(2).copied(),
83 })
84 }
85}
86
87impl Ord for Version {
93 fn cmp(&self, other: &Self) -> Ordering {
94 if self == other {
95 return Ordering::Equal
96 }
97
98 if self.is_stable() && other.is_nightly() {
100 return Ordering::Greater
101 } else if self.is_nightly() && other.is_stable() {
102 return Ordering::Less
103 }
104
105 let to_compare = [
106 (Some(self.major), Some(other.major)),
107 (Some(self.minor), Some(other.minor)),
108 (Some(self.patch), Some(other.patch)),
109 (self.year, other.year),
110 (self.month, other.month),
111 (self.day, other.day),
112 ];
113
114 to_compare
115 .iter()
116 .find_map(|(l, r)| if l != r { l.partial_cmp(&r) } else { None })
117 .unwrap_or(Ordering::Equal)
120 }
121}
122
123impl PartialOrd for Version {
124 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
125 Some(self.cmp(other))
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn version_compare_and_extract_works() {
135 let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap();
136 let version_1_66_1 = Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap();
137 let version_1_66_0_nightly =
138 Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)").unwrap();
139 let version_1_66_0_nightly_older_date =
140 Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)").unwrap();
141 let version_1_65_0 = Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap();
142 let version_1_65_0_older_date =
143 Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap();
144
145 assert!(version_1_66_1 > version_1_66_0);
146 assert!(version_1_66_1 > version_1_65_0);
147 assert!(version_1_66_1 > version_1_66_0_nightly);
148 assert!(version_1_66_1 > version_1_66_0_nightly_older_date);
149 assert!(version_1_66_1 > version_1_65_0_older_date);
150
151 assert!(version_1_66_0 > version_1_65_0);
152 assert!(version_1_66_0 > version_1_66_0_nightly);
153 assert!(version_1_66_0 > version_1_66_0_nightly_older_date);
154 assert!(version_1_66_0 > version_1_65_0_older_date);
155
156 assert!(version_1_65_0 > version_1_66_0_nightly);
157 assert!(version_1_65_0 > version_1_66_0_nightly_older_date);
158 assert!(version_1_65_0 > version_1_65_0_older_date);
159
160 let mut versions = vec![
161 version_1_66_0,
162 version_1_66_0_nightly,
163 version_1_66_0_nightly_older_date,
164 version_1_65_0_older_date,
165 version_1_65_0,
166 version_1_66_1,
167 ];
168 versions.sort_by(|a, b| b.cmp(a));
169
170 let expected_versions_order = vec![
171 version_1_66_1,
172 version_1_66_0,
173 version_1_65_0,
174 version_1_65_0_older_date,
175 version_1_66_0_nightly,
176 version_1_66_0_nightly_older_date,
177 ];
178 assert_eq!(expected_versions_order, versions);
179 }
180
181 #[test]
182 fn parse_with_newline() {
183 let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap();
184 assert_eq!(
185 Version {
186 major: 1,
187 minor: 66,
188 patch: 0,
189 is_nightly: false,
190 year: Some(2022),
191 month: Some(11),
192 day: Some(15),
193 },
194 version_1_66_0,
195 );
196 }
197
198 #[test]
199 fn version_without_hash_and_date() {
200 let version_1_69_0 = Version::extract("cargo 1.69.0-nightly").unwrap();
202 assert_eq!(
203 Version {
204 major: 1,
205 minor: 69,
206 patch: 0,
207 is_nightly: true,
208 year: None,
209 month: None,
210 day: None,
211 },
212 version_1_69_0,
213 );
214 }
215
216 #[test]
217 fn parse_rustc_version() {
218 let version = Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap();
219 assert_eq!(
220 version,
221 Version {
222 major: 1,
223 minor: 73,
224 patch: 0,
225 is_nightly: false,
226 year: Some(2023),
227 month: Some(10),
228 day: Some(03),
229 }
230 );
231 }
232}