]> git.proxmox.com Git - rustc.git/blame - vendor/semver-parser/src/version.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / vendor / semver-parser / src / version.rs
CommitLineData
f20569fa
XL
1//! Version data and functions.\r
2//!\r
3//! This module contains [`Version`] struct, [`parse`] function for building\r
4//! [`Version`] struct from string and some helper data structures and functions.\r
5//!\r
6//! # Examples\r
7//!\r
8//! Parsing `Version` from string and checking its fields:\r
9//!\r
10//! ```\r
11//! use semver_parser::version;\r
12//!\r
13//! # fn try_main() -> Result<(), String> {\r
14//! let version = version::parse("1.2.3-alpha1")?;\r
15//!\r
16//! assert_eq!(version.major, 1);\r
17//! assert_eq!(version.minor, 2);\r
18//! assert_eq!(version.patch, 3);\r
19//!\r
20//! let expected_pre = vec![\r
21//! version::Identifier::AlphaNumeric(String::from("alpha1")),\r
22//! ];\r
23//!\r
24//! assert_eq!(expected_pre, version.pre);\r
25//! # Ok(())\r
26//! # }\r
27//! #\r
28//! # try_main().unwrap();\r
29//! ```\r
30//! [`Version`]: ./struct.Version.html\r
31//! [`parse`]: ./fn.parse.html\r
32\r
33use crate::parser::{self, Parser};\r
34use std::fmt;\r
35\r
36/// Structure representing version data.\r
37///\r
38/// `Version` struct has some public fields representing version data, like major/minor version\r
39/// string, patch number and vectors of prefix and build identifiers.\r
40///\r
41/// # Examples\r
42///\r
43/// Parsing `Version` from string and checking its fields:\r
44///\r
45/// ```\r
46/// use semver_parser::version;\r
47///\r
48/// # fn try_main() -> Result<(), String> {\r
49/// let version = version::parse("0.1.2-alpha1")?;\r
50/// assert_eq!(version.major, 0);\r
51/// assert_eq!(version.minor, 1);\r
52/// assert_eq!(version.patch, 2);\r
53/// let expected_pre = vec![version::Identifier::AlphaNumeric(String::from("alpha1"))];\r
54/// assert_eq!(expected_pre, version.pre);\r
55/// # Ok(())\r
56/// # }\r
57/// #\r
58/// # try_main().unwrap();\r
59/// ```\r
60#[derive(Clone, PartialOrd, Ord, Hash, Debug, PartialEq, Eq)]\r
61pub struct Version {\r
62 /// Major version as number (`0` in `"0.1.2"`).\r
63 pub major: u64,\r
64 /// Minor version as number (`1` in `"0.1.2"`).\r
65 pub minor: u64,\r
66 /// Patch version as number (`2` in `"0.1.2"`).\r
67 pub patch: u64,\r
68 /// Pre-release metadata as a vector of `Identifier` (`"alpha1"` in `"0.1.2-alpha1"`\r
69 /// or `7` (numeric) in `"0.1.2-7"`, `"pre"` and `0` (numeric) in `"0.1.2-pre.0"`).\r
70 pub pre: Vec<Identifier>,\r
71 /// Build metadata as a vector of `Identifier` (`"build1"` in `"0.1.2+build1"`\r
72 /// or `7` (numeric) in `"0.1.2+7"`, `"build"` and `0` (numeric) in `"0.1.2+pre.0"`).\r
73 pub build: Vec<Identifier>,\r
74}\r
75\r
76/// Helper enum for holding data of alphanumeric or numeric suffix identifiers.\r
77///\r
78/// This enum is used to hold suffix parts of `pre` and `build` fields of\r
79/// [`Version`] struct. Theses suffixes may be either numeric or alphanumeric.\r
80///\r
81/// # Examples\r
82///\r
83/// Parsing [`Version`] with pre-release part composed of two `Identifier`s:\r
84///\r
85/// ```\r
86/// use semver_parser::version;\r
87///\r
88/// # fn try_main() -> Result<(), String> {\r
89/// let version = version::parse("0.1.2-alpha1.0")?;\r
90///\r
91/// let expected_pre = vec![\r
92/// version::Identifier::AlphaNumeric(String::from("alpha1")),\r
93/// version::Identifier::Numeric(0),\r
94/// ];\r
95///\r
96/// assert_eq!(expected_pre, version.pre);\r
97/// # Ok(())\r
98/// # }\r
99/// #\r
100/// # try_main().unwrap();\r
101/// ```\r
102/// [`Version`]: ./struct.Version.html\r
103#[derive(Clone, PartialOrd, Ord, Hash, Debug, PartialEq, Eq)]\r
104pub enum Identifier {\r
105 /// An identifier that's solely numbers.\r
106 Numeric(u64),\r
107 /// An identifier with letters and numbers.\r
108 AlphaNumeric(String),\r
109}\r
110\r
111impl Identifier {\r
112 pub fn concat(self, add_str: &str) -> Identifier {\r
113 match self {\r
114 Identifier::Numeric(n) => Identifier::AlphaNumeric(format!("{}{}", n, add_str)),\r
115 Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(format!("{}{}", s, add_str)),\r
116 }\r
117 }\r
118}\r
119\r
120/// Function for parsing version string to [`Version`].\r
121///\r
122/// Returns `Result<`[`Version`]`, String>`, where `String` represents an error while parsing.\r
123///\r
124/// # Examples\r
125///\r
126/// Parsing [`Version`] from string and checking its fields:\r
127///\r
128/// ```\r
129/// use semver_parser::version;\r
130///\r
131/// # fn try_main() -> Result<(), String> {\r
132/// let version = version::parse("0.1.2-alpha1")?;\r
133/// assert_eq!(version.major, 0);\r
134/// assert_eq!(version.minor, 1);\r
135/// assert_eq!(version.patch, 2);\r
136/// let expected_pre = vec![version::Identifier::AlphaNumeric(String::from("alpha1"))];\r
137/// assert_eq!(expected_pre, version.pre);\r
138/// # Ok(())\r
139/// # }\r
140/// #\r
141/// # try_main().unwrap();\r
142/// ```\r
143/// [`Version`]: ./struct.Version.html\r
144pub fn parse(input: &str) -> Result<Version, parser::Error> {\r
145 let mut parser = Parser::new(input)?;\r
146 let version = parser.version()?;\r
147\r
148 if !parser.is_eof() {\r
149 return Err(parser::Error::MoreInput(parser.tail()?));\r
150 }\r
151\r
152 Ok(version)\r
153}\r
154\r
155impl fmt::Display for Version {\r
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r
157 write!(f, "{}.{}.{}", self.major, self.minor, self.patch).expect("write failed");\r
158 if !self.pre.is_empty() {\r
159 let strs: Vec<_> = self.pre.iter().map(ToString::to_string).collect();\r
160 write!(f, "-{}", strs.join(".")).expect("write failed");\r
161 }\r
162 if !self.build.is_empty() {\r
163 let strs: Vec<_> = self.build.iter().map(ToString::to_string).collect();\r
164 write!(f, "+{}", strs.join(".")).expect("write failed");\r
165 }\r
166 Ok(())\r
167 }\r
168}\r
169\r
170impl fmt::Display for Identifier {\r
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r
172 match *self {\r
173 Identifier::Numeric(ref id) => id.fmt(f),\r
174 Identifier::AlphaNumeric(ref id) => id.fmt(f),\r
175 }\r
176 }\r
177}\r
178\r
179#[cfg(test)]\r
180mod tests {\r
181 use super::*;\r
182 use crate::version;\r
183\r
184 #[test]\r
185 fn parse_empty() {\r
186 let version = "";\r
187\r
188 let parsed = version::parse(version);\r
189\r
190 assert!(\r
191 parsed.is_err(),\r
192 "empty string incorrectly considered a valid parse"\r
193 );\r
194 }\r
195\r
196 #[test]\r
197 fn parse_blank() {\r
198 let version = " ";\r
199\r
200 let parsed = version::parse(version);\r
201\r
202 assert!(\r
203 parsed.is_err(),\r
204 "blank string incorrectly considered a valid parse"\r
205 );\r
206 }\r
207\r
208 #[test]\r
209 fn parse_no_minor_patch() {\r
210 let version = "1";\r
211\r
212 let parsed = version::parse(version);\r
213\r
214 assert!(\r
215 parsed.is_err(),\r
216 format!("'{}' incorrectly considered a valid parse", version)\r
217 );\r
218 }\r
219\r
220 #[test]\r
221 fn parse_no_patch() {\r
222 let version = "1.2";\r
223\r
224 let parsed = version::parse(version);\r
225\r
226 assert!(\r
227 parsed.is_err(),\r
228 format!("'{}' incorrectly considered a valid parse", version)\r
229 );\r
230 }\r
231\r
232 #[test]\r
233 fn parse_empty_pre() {\r
234 let version = "1.2.3-";\r
235\r
236 let parsed = version::parse(version);\r
237\r
238 assert!(\r
239 parsed.is_err(),\r
240 format!("'{}' incorrectly considered a valid parse", version)\r
241 );\r
242 }\r
243\r
244 #[test]\r
245 fn parse_letters() {\r
246 let version = "a.b.c";\r
247\r
248 let parsed = version::parse(version);\r
249\r
250 assert!(\r
251 parsed.is_err(),\r
252 format!("'{}' incorrectly considered a valid parse", version)\r
253 );\r
254 }\r
255\r
256 #[test]\r
257 fn parse_with_letters() {\r
258 let version = "1.2.3 a.b.c";\r
259\r
260 let parsed = version::parse(version);\r
261\r
262 assert!(\r
263 parsed.is_err(),\r
264 format!("'{}' incorrectly considered a valid parse", version)\r
265 );\r
266 }\r
267\r
268 #[test]\r
269 fn parse_basic_version() {\r
270 let version = "1.2.3";\r
271\r
272 let parsed = version::parse(version).unwrap();\r
273\r
274 assert_eq!(1, parsed.major);\r
275 assert_eq!(2, parsed.minor);\r
276 assert_eq!(3, parsed.patch);\r
277 }\r
278\r
279 #[test]\r
280 fn parse_trims_input() {\r
281 let version = " 1.2.3 ";\r
282\r
283 let parsed = version::parse(version).unwrap();\r
284\r
285 assert_eq!(1, parsed.major);\r
286 assert_eq!(2, parsed.minor);\r
287 assert_eq!(3, parsed.patch);\r
288 }\r
289\r
290 #[test]\r
291 fn parse_no_major_leading_zeroes() {\r
292 let version = "01.0.0";\r
293\r
294 let parsed = version::parse(version);\r
295\r
296 assert!(\r
297 parsed.is_err(),\r
298 "01 incorrectly considered a valid major version"\r
299 );\r
300 }\r
301\r
302 #[test]\r
303 fn parse_no_minor_leading_zeroes() {\r
304 let version = "0.01.0";\r
305\r
306 let parsed = version::parse(version);\r
307\r
308 assert!(\r
309 parsed.is_err(),\r
310 "01 incorrectly considered a valid minor version"\r
311 );\r
312 }\r
313\r
314 #[test]\r
315 fn parse_no_patch_leading_zeroes() {\r
316 let version = "0.0.01";\r
317\r
318 let parsed = version::parse(version);\r
319\r
320 assert!(\r
321 parsed.is_err(),\r
322 "01 incorrectly considered a valid patch version"\r
323 );\r
324 }\r
325\r
326 #[test]\r
327 fn parse_no_major_overflow() {\r
328 let version = "98765432109876543210.0.0";\r
329\r
330 let parsed = version::parse(version);\r
331\r
332 assert!(\r
333 parsed.is_err(),\r
334 "98765432109876543210 incorrectly considered a valid major version"\r
335 );\r
336 }\r
337\r
338 #[test]\r
339 fn parse_no_minor_overflow() {\r
340 let version = "0.98765432109876543210.0";\r
341\r
342 let parsed = version::parse(version);\r
343\r
344 assert!(\r
345 parsed.is_err(),\r
346 "98765432109876543210 incorrectly considered a valid minor version"\r
347 );\r
348 }\r
349\r
350 #[test]\r
351 fn parse_no_patch_overflow() {\r
352 let version = "0.0.98765432109876543210";\r
353\r
354 let parsed = version::parse(version);\r
355\r
356 assert!(\r
357 parsed.is_err(),\r
358 "98765432109876543210 incorrectly considered a valid patch version"\r
359 );\r
360 }\r
361\r
362 #[test]\r
363 fn parse_basic_prerelease() {\r
364 let version = "1.2.3-pre";\r
365\r
366 let parsed = version::parse(version).unwrap();\r
367\r
368 let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))];\r
369 assert_eq!(expected_pre, parsed.pre);\r
370 }\r
371\r
372 #[test]\r
373 fn parse_prerelease_alphanumeric() {\r
374 let version = "1.2.3-alpha1";\r
375\r
376 let parsed = version::parse(version).unwrap();\r
377\r
378 let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];\r
379 assert_eq!(expected_pre, parsed.pre);\r
380 }\r
381\r
382 #[test]\r
383 fn parse_prerelease_zero() {\r
384 let version = "1.2.3-pre.0";\r
385\r
386 let parsed = version::parse(version).unwrap();\r
387\r
388 let expected_pre = vec![\r
389 Identifier::AlphaNumeric(String::from("pre")),\r
390 Identifier::Numeric(0),\r
391 ];\r
392 assert_eq!(expected_pre, parsed.pre);\r
393 }\r
394\r
395 #[test]\r
396 fn parse_basic_build() {\r
397 let version = "1.2.3+build";\r
398\r
399 let parsed = version::parse(version).unwrap();\r
400\r
401 let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))];\r
402 assert_eq!(expected_build, parsed.build);\r
403 }\r
404\r
405 #[test]\r
406 fn parse_build_alphanumeric() {\r
407 let version = "1.2.3+build5";\r
408\r
409 let parsed = version::parse(version).unwrap();\r
410\r
411 let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];\r
412 assert_eq!(expected_build, parsed.build);\r
413 }\r
414\r
415 #[test]\r
416 fn parse_pre_and_build() {\r
417 let version = "1.2.3-alpha1+build5";\r
418\r
419 let parsed = version::parse(version).unwrap();\r
420\r
421 let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];\r
422 assert_eq!(expected_pre, parsed.pre);\r
423\r
424 let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];\r
425 assert_eq!(expected_build, parsed.build);\r
426 }\r
427\r
428 #[test]\r
429 fn parse_complex_metadata_01() {\r
430 let version = "1.2.3-1.alpha1.9+build5.7.3aedf ";\r
431\r
432 let parsed = version::parse(version).unwrap();\r
433\r
434 let expected_pre = vec![\r
435 Identifier::Numeric(1),\r
436 Identifier::AlphaNumeric(String::from("alpha1")),\r
437 Identifier::Numeric(9),\r
438 ];\r
439 assert_eq!(expected_pre, parsed.pre);\r
440\r
441 let expected_build = vec![\r
442 Identifier::AlphaNumeric(String::from("build5")),\r
443 Identifier::Numeric(7),\r
444 Identifier::AlphaNumeric(String::from("3aedf")),\r
445 ];\r
446 assert_eq!(expected_build, parsed.build);\r
447 }\r
448\r
449 #[test]\r
450 fn parse_complex_metadata_02() {\r
451 let version = "0.4.0-beta.1+0851523";\r
452\r
453 let parsed = version::parse(version).unwrap();\r
454\r
455 let expected_pre = vec![\r
456 Identifier::AlphaNumeric(String::from("beta")),\r
457 Identifier::Numeric(1),\r
458 ];\r
459 assert_eq!(expected_pre, parsed.pre);\r
460\r
461 let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))];\r
462 assert_eq!(expected_build, parsed.build);\r
463 }\r
464\r
465 #[test]\r
466 fn parse_metadata_overflow() {\r
467 let version = "0.4.0-beta.1+98765432109876543210";\r
468\r
469 let parsed = version::parse(version).unwrap();\r
470\r
471 let expected_pre = vec![\r
472 Identifier::AlphaNumeric(String::from("beta")),\r
473 Identifier::Numeric(1),\r
474 ];\r
475 assert_eq!(expected_pre, parsed.pre);\r
476\r
477 let expected_build = vec![Identifier::AlphaNumeric(String::from(\r
478 "98765432109876543210",\r
479 ))];\r
480 assert_eq!(expected_build, parsed.build);\r
481 }\r
482\r
483 #[test]\r
484 fn parse_regression_01() {\r
485 let version = "0.0.0-WIP";\r
486\r
487 let parsed = version::parse(version).unwrap();\r
488\r
489 assert_eq!(0, parsed.major);\r
490 assert_eq!(0, parsed.minor);\r
491 assert_eq!(0, parsed.patch);\r
492\r
493 let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))];\r
494 assert_eq!(expected_pre, parsed.pre);\r
495 }\r
496\r
497 #[test]\r
498 fn parse_regression_02() {\r
499 // this is used by really old versions of npm, and is valid according to semver.org\r
500 let version = "1.2.3-beta-1";\r
501\r
502 let parsed = version::parse(version).unwrap();\r
503\r
504 assert_eq!(1, parsed.major);\r
505 assert_eq!(2, parsed.minor);\r
506 assert_eq!(3, parsed.patch);\r
507\r
508 let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta-1"))];\r
509 assert_eq!(expected_pre, parsed.pre);\r
510 }\r
511}\r