1#![no_std]
2
3use 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)]
7pub 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
20impl From<ParseIntError> for Error {
21 fn from(_: ParseIntError) -> Self {
22 Self::ParseIntError
23 }
24}
25
26/// Result type for this crate
27pub 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)]
58pub 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)]
71pub struct NormalVersion {
72 major: u32,
73 minor: u32,
74 patch: u32,
75 omitted: OmittedParts,
76}
77
78#[derive(Debug, Copy, Clone)]
79enum OmittedParts {
80 None,
81 Minor,
82 Patch,
83}
84
85impl 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)]
108pub enum SpecialVersion {
109 Alpha,
110 Alpha2,
111 Beta,
112}
113
114impl PartialOrd for RustcVersion {
115 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
116 Some(self.cmp(other))
117 }
118}
119
120impl 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
143impl PartialOrd for NormalVersion {
144 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
145 Some(self.cmp(other))
146 }
147}
148
149impl 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
161impl 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
167impl Eq for NormalVersion {}
168
169impl PartialOrd for SpecialVersion {
170 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171 Some(self.cmp(other))
172 }
173}
174
175impl 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
187impl 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
201impl 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
211impl 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
222const 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
228impl 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)]
392mod 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