Skip to content

Commit 9665f63

Browse files
committed
Represent Rust versions with integers
1 parent c7361b1 commit 9665f63

File tree

1 file changed

+71
-75
lines changed

1 file changed

+71
-75
lines changed

bindgen/features.rs

Lines changed: 71 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,56 @@
44
#![deny(clippy::missing_docs_in_private_items)]
55
#![allow(deprecated)]
66

7-
use std::cmp::Ordering;
87
use std::io;
98
use std::str::FromStr;
109

10+
/// Represents the version of the Rust language to target.
11+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
12+
#[repr(transparent)]
13+
pub struct RustTarget(Version);
14+
15+
impl RustTarget {
16+
const fn minor(&self) -> Option<u64> {
17+
match self.0 {
18+
Version::Nightly => None,
19+
Version::Stable(minor, _) => Some(minor),
20+
}
21+
}
22+
23+
const fn is_compatible(&self, other: &Self) -> bool {
24+
match (self.0, other.0) {
25+
(Version::Stable(minor, _), Version::Stable(other_minor, _)) => {
26+
// We ignore the patch version number as they only include backwards compatible bug
27+
// fixes.
28+
minor >= other_minor
29+
}
30+
(_, Version::Nightly) => false,
31+
(Version::Nightly, _) => true,
32+
}
33+
}
34+
}
35+
36+
impl Default for RustTarget {
37+
fn default() -> Self {
38+
LATEST_STABLE_RUST
39+
}
40+
}
41+
42+
impl std::fmt::Display for RustTarget {
43+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44+
match self.0 {
45+
Version::Stable(minor, patch) => write!(f, "1.{minor}.{patch}"),
46+
Version::Nightly => "nightly".fmt(f),
47+
}
48+
}
49+
}
50+
51+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
52+
enum Version {
53+
Stable(u64, u64),
54+
Nightly,
55+
}
56+
1157
/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
1258
macro_rules! define_rust_targets {
1359
(
@@ -18,38 +64,24 @@ macro_rules! define_rust_targets {
1864
)*
1965
$(,)?
2066
) => {
21-
/// Represents the version of the Rust language to target.
22-
///
23-
/// To support a beta release, use the corresponding stable release.
24-
///
25-
/// This enum will have more variants added as necessary.
26-
#[allow(non_camel_case_types)]
27-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28-
pub enum RustTarget {
29-
/// Rust Nightly
67+
68+
impl RustTarget {
69+
/// The nightly version of Rust, which introduces the following features:"
3070
$(#[doc = concat!(
3171
"- [`", stringify!($nightly_feature), "`]",
3272
"(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
3373
)])*
34-
Nightly,
74+
pub const Nightly: Self = Self(Version::Nightly);
75+
3576
$(
36-
#[doc = concat!("Rust 1.", stringify!($minor))]
77+
#[doc = concat!("Version 1.", stringify!($minor), " of Rust, which introduced the following features:")]
3778
$(#[doc = concat!(
3879
"- [`", stringify!($feature), "`]",
3980
"(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")",
4081
)])*
4182
$(#[$attrs])*
42-
$variant,
83+
pub const $variant: Self = Self(Version::Stable($minor, 0));
4384
)*
44-
}
45-
46-
impl RustTarget {
47-
const fn minor(self) -> Option<u64> {
48-
match self {
49-
$( Self::$variant => Some($minor),)*
50-
Self::Nightly => None
51-
}
52-
}
5385

5486
const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] {
5587
[$((Self::$variant, $minor),)*]
@@ -58,7 +90,7 @@ macro_rules! define_rust_targets {
5890

5991
#[cfg(feature = "__cli")]
6092
/// Strings of allowed `RustTarget` values
61-
pub const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*];
93+
pub(crate) const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*];
6294

6395
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
6496
pub(crate) struct RustFeatures {
@@ -80,7 +112,7 @@ macro_rules! define_rust_targets {
80112
$($nightly_feature: false,)*
81113
};
82114

83-
$(if target >= RustTarget::$variant {
115+
$(if target.is_compatible(&RustTarget::$variant) {
84116
$(features.$feature = true;)*
85117
})*
86118

@@ -206,29 +238,6 @@ pub const EARLIEST_STABLE_RUST: RustTarget = {
206238
}
207239
};
208240

209-
impl Default for RustTarget {
210-
fn default() -> Self {
211-
LATEST_STABLE_RUST
212-
}
213-
}
214-
215-
impl PartialOrd for RustTarget {
216-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
217-
Some(self.cmp(other))
218-
}
219-
}
220-
221-
impl Ord for RustTarget {
222-
fn cmp(&self, other: &Self) -> Ordering {
223-
match (self.minor(), other.minor()) {
224-
(Some(a), Some(b)) => a.cmp(&b),
225-
(Some(_), None) => Ordering::Less,
226-
(None, Some(_)) => Ordering::Greater,
227-
(None, None) => Ordering::Equal,
228-
}
229-
}
230-
}
231-
232241
fn invalid_input<T>(input: &str, msg: impl std::fmt::Display) -> io::Result<T> {
233242
Err(io::Error::new(
234243
io::ErrorKind::InvalidInput,
@@ -255,8 +264,7 @@ impl FromStr for RustTarget {
255264
);
256265
}
257266

258-
// We ignore the patch version number as they only include backwards compatible bug fixes.
259-
let (minor, _patch) = match tail.split_once('.') {
267+
let (minor, patch) = match tail.split_once('.') {
260268
Some((minor_str, patch_str)) => {
261269
let Ok(minor) = minor_str.parse::<u64>() else {
262270
return invalid_input(input, "the minor version number must be an unsigned 64-bit integer");
@@ -274,26 +282,7 @@ impl FromStr for RustTarget {
274282
}
275283
};
276284

277-
let Some(target) = Self::stable_releases()
278-
.iter()
279-
.filter(|(_, target_minor)| minor >= *target_minor)
280-
.max_by_key(|(_, target_minor)| target_minor)
281-
.map(|(target, _)| target)
282-
.cloned()
283-
else {
284-
return invalid_input(input, format!("the earliest Rust target supported by bindgen is {EARLIEST_STABLE_RUST}"));
285-
};
286-
287-
Ok(target)
288-
}
289-
}
290-
291-
impl std::fmt::Display for RustTarget {
292-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293-
match self.minor() {
294-
Some(minor) => write!(f, "1.{}", minor),
295-
None => "nightly".fmt(f),
296-
}
285+
Ok(Self(Version::Stable(minor, patch)))
297286
}
298287
}
299288

@@ -351,16 +340,23 @@ mod test {
351340
);
352341
}
353342

354-
fn test_target(target_str: &str, target: RustTarget) {
343+
fn test_target(input: &str, expected: RustTarget) {
344+
// Two targets are equivalent if they enable the same set of features
345+
let expected = RustFeatures::from(expected);
346+
let found = RustFeatures::from(input.parse::<RustTarget>().unwrap());
355347
assert_eq!(
356-
target,
357-
target_str.parse::<RustTarget>().unwrap(),
358-
"{target_str}"
348+
expected,
349+
found,
350+
"target {input} enables features:\n{found:#?}\nand should enable features:\n{expected:#?}"
359351
);
360352
}
361353

362-
fn test_invalid_target(target_str: &str) {
363-
assert!(target_str.parse::<RustTarget>().is_err(), "{}", target_str);
354+
fn test_invalid_target(input: &str) {
355+
assert!(
356+
input.parse::<RustTarget>().is_err(),
357+
"{} should be an invalid target",
358+
input
359+
);
364360
}
365361

366362
#[test]

0 commit comments

Comments
 (0)