1 | #![no_std ] |
2 | |
3 | use core::{cmp::Ordering, fmt::Display, num::ParseIntError}; |
4 | |
5 | /// `Error` represents an Error during parsing of a [`RustcVersion`]. |
6 | #[derive (Debug, Eq, PartialEq, Copy, Clone)] |
7 | pub enum Error { |
8 | /// A version was passed that has too many elements seperated by `'.'`. |
9 | TooManyElements, |
10 | /// A version was passed that neither is a [`SpecialVersion`], nor a |
11 | /// normal [`RustcVersion`]. |
12 | NotASpecialVersion, |
13 | /// A version was passed, that was either an empty string or a part of the |
14 | /// version was left out, e.g. `1. .3` |
15 | EmptyVersionPart, |
16 | /// A version was passed that has unallowed chracters. |
17 | ParseIntError, |
18 | } |
19 | |
20 | impl From<ParseIntError> for Error { |
21 | fn from(_: ParseIntError) -> Self { |
22 | Self::ParseIntError |
23 | } |
24 | } |
25 | |
26 | /// Result type for this crate |
27 | pub type Result<T> = core::result::Result<T, Error>; |
28 | |
29 | /// `RustcVersion` represents a version of the Rust Compiler. |
30 | /// |
31 | /// This struct only supports the [`NormalVersion`] format |
32 | /// ```text |
33 | /// major.minor.patch |
34 | /// ``` |
35 | /// and 3 special formats represented by the [`SpecialVersion`] enum. |
36 | /// |
37 | /// A version can be created with one of the functions [`RustcVersion::new`] or |
38 | /// [`RustcVersion::parse`]. The [`RustcVersion::new`] method only supports the |
39 | /// normal version format. |
40 | /// |
41 | /// You can compare two versions, just as you would expect: |
42 | /// |
43 | /// ```rust |
44 | /// use rustc_semver::RustcVersion; |
45 | /// |
46 | /// assert!(RustcVersion::new(1, 34, 0) > RustcVersion::parse("1.10" ).unwrap()); |
47 | /// assert!(RustcVersion::new(1, 34, 0) > RustcVersion::parse("0.9" ).unwrap()); |
48 | /// ``` |
49 | /// |
50 | /// This comparison is semver conform according to the [semver definition of |
51 | /// precedence]. However, if you want to check whether one version meets |
52 | /// another version according to the [Caret Requirements], you should use |
53 | /// [`RustcVersion::meets`]. |
54 | /// |
55 | /// [Caret Requirements]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements |
56 | /// [semver definition of precedence]: https://semver.org/#spec-item-11 |
57 | #[derive (Debug, Eq, PartialEq, Copy, Clone)] |
58 | pub enum RustcVersion { |
59 | Normal(NormalVersion), |
60 | Special(SpecialVersion), |
61 | } |
62 | |
63 | /// `NormalVersion` represents a normal version used for all releases since |
64 | /// Rust 1.0.0. |
65 | /// |
66 | /// This struct supports versions in the format |
67 | /// ```test |
68 | /// major.minor.patch |
69 | /// ``` |
70 | #[derive (Debug, Copy, Clone)] |
71 | pub struct NormalVersion { |
72 | major: u32, |
73 | minor: u32, |
74 | patch: u32, |
75 | omitted: OmittedParts, |
76 | } |
77 | |
78 | #[derive (Debug, Copy, Clone)] |
79 | enum OmittedParts { |
80 | None, |
81 | Minor, |
82 | Patch, |
83 | } |
84 | |
85 | impl From<usize> for OmittedParts { |
86 | fn from(parts: usize) -> Self { |
87 | match parts { |
88 | 1 => Self::Minor, |
89 | 2 => Self::Patch, |
90 | 3 => Self::None, |
91 | _ => unreachable!( |
92 | "This function should never be called with `parts == 0` or `parts > 3`" |
93 | ), |
94 | } |
95 | } |
96 | } |
97 | |
98 | /// `SpecialVersion` represents a special version from the first releases. |
99 | /// |
100 | /// Before Rust 1.0.0, there were two alpha and one beta release, namely |
101 | /// |
102 | /// - `1.0.0-alpha` |
103 | /// - `1.0.0-alpha.2` |
104 | /// - `1.0.0-beta` |
105 | /// |
106 | /// This enum represents those releases. |
107 | #[derive (Debug, Eq, PartialEq, Copy, Clone)] |
108 | pub enum SpecialVersion { |
109 | Alpha, |
110 | Alpha2, |
111 | Beta, |
112 | } |
113 | |
114 | impl PartialOrd for RustcVersion { |
115 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
116 | Some(self.cmp(other)) |
117 | } |
118 | } |
119 | |
120 | impl Ord for RustcVersion { |
121 | fn cmp(&self, other: &Self) -> Ordering { |
122 | match (self, other) { |
123 | (Self::Normal(ver: &NormalVersion), Self::Normal(o_ver: &NormalVersion)) => ver.cmp(o_ver), |
124 | (Self::Normal(NormalVersion { major: &u32, .. }), Self::Special(_)) => { |
125 | if *major >= 1 { |
126 | Ordering::Greater |
127 | } else { |
128 | Ordering::Less |
129 | } |
130 | } |
131 | (Self::Special(_), Self::Normal(NormalVersion { major: &u32, .. })) => { |
132 | if *major >= 1 { |
133 | Ordering::Less |
134 | } else { |
135 | Ordering::Greater |
136 | } |
137 | } |
138 | (Self::Special(s_ver: &SpecialVersion), Self::Special(o_s_ver: &SpecialVersion)) => s_ver.cmp(o_s_ver), |
139 | } |
140 | } |
141 | } |
142 | |
143 | impl PartialOrd for NormalVersion { |
144 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
145 | Some(self.cmp(other)) |
146 | } |
147 | } |
148 | |
149 | impl Ord for NormalVersion { |
150 | fn cmp(&self, other: &Self) -> Ordering { |
151 | match self.major.cmp(&other.major) { |
152 | Ordering::Equal => match self.minor.cmp(&other.minor) { |
153 | Ordering::Equal => self.patch.cmp(&other.patch), |
154 | ord: Ordering => ord, |
155 | }, |
156 | ord: Ordering => ord, |
157 | } |
158 | } |
159 | } |
160 | |
161 | impl PartialEq for NormalVersion { |
162 | fn eq(&self, other: &Self) -> bool { |
163 | self.major == other.major && self.minor == other.minor && self.patch == other.patch |
164 | } |
165 | } |
166 | |
167 | impl Eq for NormalVersion {} |
168 | |
169 | impl PartialOrd for SpecialVersion { |
170 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
171 | Some(self.cmp(other)) |
172 | } |
173 | } |
174 | |
175 | impl Ord for SpecialVersion { |
176 | fn cmp(&self, other: &Self) -> Ordering { |
177 | match (self, other) { |
178 | (Self::Alpha, Self::Alpha) |
179 | | (Self::Alpha2, Self::Alpha2) |
180 | | (Self::Beta, Self::Beta) => Ordering::Equal, |
181 | (Self::Alpha, _) | (Self::Alpha2, Self::Beta) => Ordering::Less, |
182 | (Self::Beta, _) | (Self::Alpha2, Self::Alpha) => Ordering::Greater, |
183 | } |
184 | } |
185 | } |
186 | |
187 | impl Display for RustcVersion { |
188 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
189 | match self { |
190 | Self::Normal(NormalVersion { |
191 | major: &u32, |
192 | minor: &u32, |
193 | patch: &u32, |
194 | .. |
195 | }) => write!(f, " {}. {}. {}" , major, minor, patch), |
196 | Self::Special(special: &SpecialVersion) => write!(f, " {}" , special), |
197 | } |
198 | } |
199 | } |
200 | |
201 | impl Display for SpecialVersion { |
202 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
203 | match self { |
204 | Self::Alpha => write!(f, "1.0.0-alpha" ), |
205 | Self::Alpha2 => write!(f, "1.0.0-alpha.2" ), |
206 | Self::Beta => write!(f, "1.0.0-beta" ), |
207 | } |
208 | } |
209 | } |
210 | |
211 | impl From<[u32; 3]> for NormalVersion { |
212 | fn from(arr: [u32; 3]) -> Self { |
213 | NormalVersion { |
214 | major: arr[0], |
215 | minor: arr[1], |
216 | patch: arr[2], |
217 | omitted: OmittedParts::None, |
218 | } |
219 | } |
220 | } |
221 | |
222 | const ACCEPTED_SPECIAL_VERSIONS: [(&str, SpecialVersion); 3] = [ |
223 | ("1.0.0-alpha" , SpecialVersion::Alpha), |
224 | ("1.0.0-alpha.2" , SpecialVersion::Alpha2), |
225 | ("1.0.0-beta" , SpecialVersion::Beta), |
226 | ]; |
227 | |
228 | impl RustcVersion { |
229 | /// `RustcVersion::new` is a `const` constructor for a `RustcVersion`. |
230 | /// |
231 | /// This function is primarily used to construct constants, for everything |
232 | /// else use [`RustcVersion::parse`]. |
233 | /// |
234 | /// This function only allows to construct normal versions. For special |
235 | /// versions, construct them directly with the [`SpecialVersion`] enum. |
236 | /// |
237 | /// # Examples |
238 | /// |
239 | /// ```rust |
240 | /// use rustc_semver::RustcVersion; |
241 | /// |
242 | /// const MY_FAVORITE_RUST: RustcVersion = RustcVersion::new(1, 48, 0); |
243 | /// |
244 | /// assert!(MY_FAVORITE_RUST > RustcVersion::new(1, 0, 0)) |
245 | /// ``` |
246 | pub const fn new(major: u32, minor: u32, patch: u32) -> Self { |
247 | Self::Normal(NormalVersion { |
248 | major, |
249 | minor, |
250 | patch, |
251 | omitted: OmittedParts::None, |
252 | }) |
253 | } |
254 | |
255 | /// `RustcVersion::parse` parses a [`RustcVersion`]. |
256 | /// |
257 | /// This function can parse all normal and special versions. It is possbile |
258 | /// to omit parts of the version, like the patch or minor version part. So |
259 | /// `1`, `1.0`, and `1.0.0` are all valid inputs and will result in the |
260 | /// same version. |
261 | /// |
262 | /// # Errors |
263 | /// |
264 | /// This function returns an [`Error`], if the passed string is not a valid |
265 | /// [`RustcVersion`] |
266 | /// |
267 | /// # Examples |
268 | /// |
269 | /// ```rust |
270 | /// use rustc_semver::{SpecialVersion, RustcVersion}; |
271 | /// |
272 | /// let ver = RustcVersion::new(1, 0, 0); |
273 | /// |
274 | /// assert_eq!(RustcVersion::parse("1" ).unwrap(), ver); |
275 | /// assert_eq!(RustcVersion::parse("1.0" ).unwrap(), ver); |
276 | /// assert_eq!(RustcVersion::parse("1.0.0" ).unwrap(), ver); |
277 | /// assert_eq!( |
278 | /// RustcVersion::parse("1.0.0-alpha" ).unwrap(), |
279 | /// RustcVersion::Special(SpecialVersion::Alpha) |
280 | /// ); |
281 | /// ``` |
282 | pub fn parse(version: &str) -> Result<Self> { |
283 | let special_version = ACCEPTED_SPECIAL_VERSIONS.iter().find_map(|sv| { |
284 | if version == sv.0 { |
285 | Some(sv.1) |
286 | } else { |
287 | None |
288 | } |
289 | }); |
290 | if let Some(special_version) = special_version { |
291 | return Ok(RustcVersion::Special(special_version)); |
292 | } |
293 | |
294 | let mut rustc_version = [0_u32; 3]; |
295 | let mut parts = 0; |
296 | for (i, part) in version.split('.' ).enumerate() { |
297 | let part = part.trim(); |
298 | if part.is_empty() { |
299 | return Err(Error::EmptyVersionPart); |
300 | } |
301 | if i == 3 { |
302 | return Err(Error::TooManyElements); |
303 | } |
304 | match str::parse(part) { |
305 | Ok(part) => rustc_version[i] = part, |
306 | Err(e) => { |
307 | if i == 2 { |
308 | return Err(Error::NotASpecialVersion); |
309 | } else { |
310 | return Err(e.into()); |
311 | } |
312 | } |
313 | } |
314 | |
315 | parts = i + 1; |
316 | } |
317 | |
318 | let mut ver = NormalVersion::from(rustc_version); |
319 | ver.omitted = OmittedParts::from(parts); |
320 | Ok(RustcVersion::Normal(ver)) |
321 | } |
322 | |
323 | /// `RustcVersion::meets` implements a semver conform version check |
324 | /// according to the [Caret Requirements]. |
325 | /// |
326 | /// Note that [`SpecialVersion`]s only meet themself and no other version |
327 | /// meets a [`SpecialVersion`]. This is because [according to semver], |
328 | /// special versions are considered unstable and "might not satisfy the |
329 | /// intended compatibility requirements as denoted by \[their\] associated |
330 | /// normal version". |
331 | /// |
332 | /// # Examples |
333 | /// |
334 | /// ```rust |
335 | /// use rustc_semver::RustcVersion; |
336 | /// |
337 | /// assert!(RustcVersion::new(1, 30, 0).meets(RustcVersion::parse("1.29" ).unwrap())); |
338 | /// assert!(!RustcVersion::new(1, 30, 0).meets(RustcVersion::parse("1.31" ).unwrap())); |
339 | /// |
340 | /// assert!(RustcVersion::new(0, 2, 1).meets(RustcVersion::parse("0.2" ).unwrap())); |
341 | /// assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::parse("0.2" ).unwrap())); |
342 | /// ``` |
343 | /// |
344 | /// [Caret Requirements]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements |
345 | /// [according to semver]: https://semver.org/#spec-item-9 |
346 | pub fn meets(self, other: Self) -> bool { |
347 | match (self, other) { |
348 | (RustcVersion::Special(_), _) | (_, RustcVersion::Special(_)) => self == other, |
349 | (RustcVersion::Normal(ver), RustcVersion::Normal(o_ver)) => { |
350 | // In any case must `self` be bigger than `other`, with the major part matching |
351 | // the other version. |
352 | let mut meets = ver >= o_ver && ver.major == o_ver.major; |
353 | |
354 | // In addition, the left-most non-zero digit must not be modified. |
355 | match o_ver.omitted { |
356 | OmittedParts::None => { |
357 | // Nothing was omitted, this means that everything must match in case of |
358 | // leading zeros. |
359 | if o_ver.major == 0 { |
360 | // Leading 0 in major position, check for |
361 | // `self.minor == other.minor` |
362 | meets &= ver.minor == o_ver.minor; |
363 | |
364 | if o_ver.minor == 0 { |
365 | // Leading 0 in minor position, check for |
366 | // `self.patch == other.patch`. |
367 | meets &= ver.patch == o_ver.patch; |
368 | } |
369 | } |
370 | } |
371 | OmittedParts::Patch => { |
372 | // The patch version was omitted, this means the patch version of `self` |
373 | // does not have to match the patch version of `other`. |
374 | if o_ver.major == 0 { |
375 | meets &= ver.minor == o_ver.minor; |
376 | } |
377 | } |
378 | OmittedParts::Minor => { |
379 | // The minor (and patch) version was omitted, this means |
380 | // the minor and patch version of `self` do not have to |
381 | // match the minor and patch version of `other` |
382 | } |
383 | } |
384 | |
385 | meets |
386 | } |
387 | } |
388 | } |
389 | } |
390 | |
391 | #[cfg (test)] |
392 | mod test { |
393 | use super::*; |
394 | |
395 | #[test ] |
396 | fn omitted_parts() { |
397 | assert_eq!( |
398 | RustcVersion::parse("1.0.0" ).unwrap(), |
399 | RustcVersion::new(1, 0, 0) |
400 | ); |
401 | assert_eq!( |
402 | RustcVersion::parse("1.0" ).unwrap(), |
403 | RustcVersion::new(1, 0, 0) |
404 | ); |
405 | assert_eq!( |
406 | RustcVersion::parse("1" ).unwrap(), |
407 | RustcVersion::new(1, 0, 0) |
408 | ); |
409 | } |
410 | |
411 | #[test ] |
412 | fn special_versions() { |
413 | assert_eq!( |
414 | RustcVersion::parse("1.0.0-alpha" ).unwrap(), |
415 | RustcVersion::Special(SpecialVersion::Alpha) |
416 | ); |
417 | assert_eq!( |
418 | RustcVersion::parse("1.0.0-alpha.2" ).unwrap(), |
419 | RustcVersion::Special(SpecialVersion::Alpha2) |
420 | ); |
421 | assert_eq!( |
422 | RustcVersion::parse("1.0.0-beta" ).unwrap(), |
423 | RustcVersion::Special(SpecialVersion::Beta) |
424 | ); |
425 | assert_eq!( |
426 | RustcVersion::parse("1.0.0-sigma" ), |
427 | Err(Error::NotASpecialVersion) |
428 | ); |
429 | assert_eq!( |
430 | RustcVersion::parse("1.0.0beta" ), |
431 | Err(Error::NotASpecialVersion) |
432 | ); |
433 | assert_eq!( |
434 | RustcVersion::parse("1.1.0-beta" ), |
435 | Err(Error::NotASpecialVersion) |
436 | ); |
437 | } |
438 | |
439 | #[test ] |
440 | fn less_than() { |
441 | let bigger = RustcVersion::new(1, 30, 1); |
442 | assert!(RustcVersion::parse("1.0.0" ).unwrap() < bigger); |
443 | assert!(RustcVersion::parse("1.0" ).unwrap() < bigger); |
444 | assert!(RustcVersion::parse("1" ).unwrap() < bigger); |
445 | assert!(RustcVersion::parse("1.30" ).unwrap() < bigger); |
446 | assert!(RustcVersion::parse("1.0.0-beta" ).unwrap() < bigger); |
447 | assert!(RustcVersion::parse("0.9" ).unwrap() < RustcVersion::Special(SpecialVersion::Alpha)); |
448 | assert!( |
449 | RustcVersion::parse("1.0.0-alpha" ).unwrap() |
450 | < RustcVersion::Special(SpecialVersion::Alpha2) |
451 | ); |
452 | assert!( |
453 | RustcVersion::parse("1.0.0-alpha" ).unwrap() |
454 | < RustcVersion::Special(SpecialVersion::Beta) |
455 | ); |
456 | assert!( |
457 | RustcVersion::parse("1.0.0-alpha.2" ).unwrap() |
458 | < RustcVersion::Special(SpecialVersion::Beta) |
459 | ); |
460 | } |
461 | |
462 | #[test ] |
463 | fn equal() { |
464 | assert_eq!( |
465 | RustcVersion::parse("1.22.0" ).unwrap(), |
466 | RustcVersion::new(1, 22, 0) |
467 | ); |
468 | assert_eq!( |
469 | RustcVersion::parse("1.22" ).unwrap(), |
470 | RustcVersion::new(1, 22, 0) |
471 | ); |
472 | assert_eq!( |
473 | RustcVersion::parse("1.48.1" ).unwrap(), |
474 | RustcVersion::new(1, 48, 1) |
475 | ); |
476 | assert_eq!( |
477 | RustcVersion::parse("1.0.0-alpha" ) |
478 | .unwrap() |
479 | .cmp(&RustcVersion::Special(SpecialVersion::Alpha)), |
480 | Ordering::Equal |
481 | ); |
482 | assert_eq!( |
483 | RustcVersion::parse("1.0.0-alpha.2" ) |
484 | .unwrap() |
485 | .cmp(&RustcVersion::Special(SpecialVersion::Alpha2)), |
486 | Ordering::Equal |
487 | ); |
488 | assert_eq!( |
489 | RustcVersion::parse("1.0.0-beta" ) |
490 | .unwrap() |
491 | .cmp(&RustcVersion::Special(SpecialVersion::Beta)), |
492 | Ordering::Equal |
493 | ); |
494 | } |
495 | |
496 | #[test ] |
497 | fn greater_than() { |
498 | let less = RustcVersion::new(1, 15, 1); |
499 | assert!(RustcVersion::parse("1.16.0" ).unwrap() > less); |
500 | assert!(RustcVersion::parse("1.16" ).unwrap() > less); |
501 | assert!(RustcVersion::parse("2" ).unwrap() > less); |
502 | assert!(RustcVersion::parse("1.15.2" ).unwrap() > less); |
503 | assert!( |
504 | RustcVersion::parse("1.0.0-beta" ).unwrap() |
505 | > RustcVersion::Special(SpecialVersion::Alpha2) |
506 | ); |
507 | assert!( |
508 | RustcVersion::parse("1.0.0-beta" ).unwrap() |
509 | > RustcVersion::Special(SpecialVersion::Alpha) |
510 | ); |
511 | assert!( |
512 | RustcVersion::parse("1.0.0-alpha.2" ).unwrap() |
513 | > RustcVersion::Special(SpecialVersion::Alpha) |
514 | ); |
515 | assert!(RustcVersion::parse("1.0.0-alpha.2" ).unwrap() > RustcVersion::new(0, 8, 0)); |
516 | assert!( |
517 | RustcVersion::parse("1.45.2" ).unwrap() > RustcVersion::Special(SpecialVersion::Alpha2) |
518 | ); |
519 | } |
520 | |
521 | #[test ] |
522 | fn edge_cases() { |
523 | assert_eq!(RustcVersion::parse("" ), Err(Error::EmptyVersionPart)); |
524 | assert_eq!(RustcVersion::parse(" " ), Err(Error::EmptyVersionPart)); |
525 | assert_eq!(RustcVersion::parse(" \t" ), Err(Error::EmptyVersionPart)); |
526 | assert_eq!(RustcVersion::parse("1." ), Err(Error::EmptyVersionPart)); |
527 | assert_eq!(RustcVersion::parse("1. " ), Err(Error::EmptyVersionPart)); |
528 | assert_eq!(RustcVersion::parse("1. \t" ), Err(Error::EmptyVersionPart)); |
529 | assert_eq!(RustcVersion::parse("1. \t.3" ), Err(Error::EmptyVersionPart)); |
530 | assert_eq!( |
531 | RustcVersion::parse(" 1 . \t 3. \r 5" ).unwrap(), |
532 | RustcVersion::new(1, 3, 5) |
533 | ); |
534 | } |
535 | |
536 | #[test ] |
537 | fn formatting() { |
538 | extern crate alloc; |
539 | use alloc::string::{String, ToString}; |
540 | assert_eq!( |
541 | RustcVersion::new(1, 42, 28).to_string(), |
542 | String::from("1.42.28" ) |
543 | ); |
544 | assert_eq!( |
545 | RustcVersion::Special(SpecialVersion::Alpha).to_string(), |
546 | String::from("1.0.0-alpha" ) |
547 | ); |
548 | assert_eq!( |
549 | RustcVersion::Special(SpecialVersion::Alpha2).to_string(), |
550 | String::from("1.0.0-alpha.2" ) |
551 | ); |
552 | assert_eq!( |
553 | RustcVersion::Special(SpecialVersion::Beta).to_string(), |
554 | String::from("1.0.0-beta" ) |
555 | ); |
556 | } |
557 | |
558 | #[test ] |
559 | fn too_many_elements() { |
560 | assert_eq!( |
561 | RustcVersion::parse("1.0.0.100" ), |
562 | Err(Error::TooManyElements) |
563 | ); |
564 | } |
565 | |
566 | #[test ] |
567 | fn alpha_numeric_version() { |
568 | assert_eq!(RustcVersion::parse("a.0.1" ), Err(Error::ParseIntError)); |
569 | assert_eq!(RustcVersion::parse("2.x.1" ), Err(Error::ParseIntError)); |
570 | assert_eq!(RustcVersion::parse("0.2.s" ), Err(Error::NotASpecialVersion)); |
571 | } |
572 | |
573 | #[test ] |
574 | fn meets_full() { |
575 | // Nothing was omitted |
576 | assert!(RustcVersion::new(1, 2, 3).meets(RustcVersion::new(1, 2, 3))); |
577 | assert!(RustcVersion::new(1, 2, 5).meets(RustcVersion::new(1, 2, 3))); |
578 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::new(1, 2, 3))); |
579 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::new(1, 2, 3))); |
580 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::new(1, 0, 0))); |
581 | |
582 | assert!(RustcVersion::new(0, 2, 3).meets(RustcVersion::new(0, 2, 3))); |
583 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::new(0, 2, 3))); |
584 | assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::new(0, 2, 3))); |
585 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::new(0, 2, 3))); |
586 | |
587 | assert!(RustcVersion::new(0, 0, 3).meets(RustcVersion::new(0, 0, 3))); |
588 | assert!(!RustcVersion::new(0, 0, 5).meets(RustcVersion::new(0, 0, 3))); |
589 | assert!(!RustcVersion::new(0, 1, 0).meets(RustcVersion::new(0, 0, 3))); |
590 | |
591 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::new(0, 0, 0))); |
592 | assert!(!RustcVersion::new(0, 0, 1).meets(RustcVersion::new(0, 0, 0))); |
593 | } |
594 | |
595 | #[test ] |
596 | fn meets_no_patch() { |
597 | // Patch was omitted |
598 | assert!(RustcVersion::new(1, 2, 0).meets(RustcVersion::parse("1.2" ).unwrap())); |
599 | assert!(RustcVersion::new(1, 2, 5).meets(RustcVersion::parse("1.2" ).unwrap())); |
600 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::parse("1.2" ).unwrap())); |
601 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::parse("1.2" ).unwrap())); |
602 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::parse("1.0" ).unwrap())); |
603 | |
604 | assert!(RustcVersion::new(0, 2, 0).meets(RustcVersion::parse("0.2" ).unwrap())); |
605 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::parse("0.2" ).unwrap())); |
606 | assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::parse("0.2" ).unwrap())); |
607 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("0.2" ).unwrap())); |
608 | |
609 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::parse("0.0" ).unwrap())); |
610 | assert!(RustcVersion::new(0, 0, 5).meets(RustcVersion::parse("0.0" ).unwrap())); |
611 | assert!(!RustcVersion::new(0, 1, 0).meets(RustcVersion::parse("0.0" ).unwrap())); |
612 | } |
613 | |
614 | #[test ] |
615 | fn meets_no_minor() { |
616 | // Minor was omitted |
617 | assert!(RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("1" ).unwrap())); |
618 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::parse("1" ).unwrap())); |
619 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::parse("1" ).unwrap())); |
620 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::parse("1" ).unwrap())); |
621 | |
622 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::parse("0" ).unwrap())); |
623 | assert!(RustcVersion::new(0, 0, 1).meets(RustcVersion::parse("0" ).unwrap())); |
624 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::parse("0" ).unwrap())); |
625 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("0" ).unwrap())); |
626 | } |
627 | |
628 | #[test ] |
629 | fn meets_special() { |
630 | assert!(RustcVersion::Special(SpecialVersion::Alpha) |
631 | .meets(RustcVersion::Special(SpecialVersion::Alpha))); |
632 | assert!(RustcVersion::Special(SpecialVersion::Alpha2) |
633 | .meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
634 | assert!(RustcVersion::Special(SpecialVersion::Beta) |
635 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
636 | assert!(!RustcVersion::Special(SpecialVersion::Alpha) |
637 | .meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
638 | assert!(!RustcVersion::Special(SpecialVersion::Alpha) |
639 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
640 | assert!(!RustcVersion::Special(SpecialVersion::Alpha2) |
641 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
642 | assert!(!RustcVersion::Special(SpecialVersion::Alpha).meets(RustcVersion::new(1, 0, 0))); |
643 | assert!(!RustcVersion::Special(SpecialVersion::Alpha2).meets(RustcVersion::new(1, 0, 0))); |
644 | assert!(!RustcVersion::Special(SpecialVersion::Beta).meets(RustcVersion::new(1, 0, 0))); |
645 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Alpha))); |
646 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
647 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Beta))); |
648 | } |
649 | |
650 | #[test ] |
651 | #[should_panic ( |
652 | expected = "This function should never be called with `parts == 0` or `parts > 3`" |
653 | )] |
654 | fn omitted_parts_with_zero() { |
655 | OmittedParts::from(0); |
656 | } |
657 | |
658 | #[test ] |
659 | #[should_panic ( |
660 | expected = "This function should never be called with `parts == 0` or `parts > 3`" |
661 | )] |
662 | fn omitted_parts_with_four() { |
663 | OmittedParts::from(4); |
664 | } |
665 | } |
666 | |