Skip to content

Commit fc4c3bc

Browse files
committed
Add constructors to RustTarget
1 parent 9665f63 commit fc4c3bc

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

bindgen/features.rs

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@
44
#![deny(clippy::missing_docs_in_private_items)]
55
#![allow(deprecated)]
66

7-
use std::io;
87
use std::str::FromStr;
8+
use std::{fmt, io};
99

1010
/// Represents the version of the Rust language to target.
1111
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
1212
#[repr(transparent)]
1313
pub struct RustTarget(Version);
1414

1515
impl RustTarget {
16+
/// Create a new [`RustTarget`] for a stable release of Rust.
17+
pub fn stable(minor: u64, patch: u64) -> Result<Self, InvalidRustTarget> {
18+
let target = Self(Version::Stable(minor, patch));
19+
20+
if target < EARLIEST_STABLE_RUST {
21+
return Err(InvalidRustTarget::TooEarly);
22+
}
23+
24+
Ok(target)
25+
}
26+
1627
const fn minor(&self) -> Option<u64> {
1728
match self.0 {
1829
Version::Nightly => None,
@@ -39,8 +50,8 @@ impl Default for RustTarget {
3950
}
4051
}
4152

42-
impl std::fmt::Display for RustTarget {
43-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53+
impl fmt::Display for RustTarget {
54+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4455
match self.0 {
4556
Version::Stable(minor, patch) => write!(f, "1.{minor}.{patch}"),
4657
Version::Nightly => "nightly".fmt(f),
@@ -54,6 +65,18 @@ enum Version {
5465
Nightly,
5566
}
5667

68+
pub enum InvalidRustTarget {
69+
TooEarly,
70+
}
71+
72+
impl fmt::Display for InvalidRustTarget {
73+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74+
match self {
75+
Self::TooEarly => write!(f, "the earliest Rust version supported by bindgen is {EARLIEST_STABLE_RUST}"),
76+
}
77+
}
78+
}
79+
5780
/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
5881
macro_rules! define_rust_targets {
5982
(
@@ -71,7 +94,16 @@ macro_rules! define_rust_targets {
7194
"- [`", stringify!($nightly_feature), "`]",
7295
"(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
7396
)])*
74-
pub const Nightly: Self = Self(Version::Nightly);
97+
pub const Nightly: Self = Self::nightly();
98+
99+
/// The nightly version of Rust, which introduces the following features:"
100+
$(#[doc = concat!(
101+
"- [`", stringify!($nightly_feature), "`]",
102+
"(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
103+
)])*
104+
pub const fn nightly() -> Self {
105+
Self(Version::Nightly)
106+
}
75107

76108
$(
77109
#[doc = concat!("Version 1.", stringify!($minor), " of Rust, which introduced the following features:")]
@@ -238,11 +270,11 @@ pub const EARLIEST_STABLE_RUST: RustTarget = {
238270
}
239271
};
240272

241-
fn invalid_input<T>(input: &str, msg: impl std::fmt::Display) -> io::Result<T> {
242-
Err(io::Error::new(
273+
fn invalid_input(input: &str, msg: impl fmt::Display) -> io::Error {
274+
io::Error::new(
243275
io::ErrorKind::InvalidInput,
244276
format!("\"{input}\" is not a valid Rust target, {msg}"),
245-
))
277+
)
246278
}
247279

248280
impl FromStr for RustTarget {
@@ -254,35 +286,35 @@ impl FromStr for RustTarget {
254286
}
255287

256288
let Some((major_str, tail)) = input.split_once('.') else {
257-
return invalid_input(input, "accepted values are of the form \"1.71\", \"1.71.1\" or \"nightly\"." );
289+
return Err(invalid_input(input, "accepted values are of the form \"1.71\", \"1.71.1\" or \"nightly\"." ) );
258290
};
259291

260292
if major_str != "1" {
261-
return invalid_input(
293+
return Err(invalid_input(
262294
input,
263295
"The largest major version of Rust released is \"1\"",
264-
);
296+
));
265297
}
266298

267299
let (minor, patch) = match tail.split_once('.') {
268300
Some((minor_str, patch_str)) => {
269301
let Ok(minor) = minor_str.parse::<u64>() else {
270-
return invalid_input(input, "the minor version number must be an unsigned 64-bit integer");
302+
return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer"));
271303
};
272304
let Ok(patch) = patch_str.parse::<u64>() else {
273-
return invalid_input(input, "the patch version number must be an unsigned 64-bit integer");
305+
return Err(invalid_input(input, "the patch version number must be an unsigned 64-bit integer"));
274306
};
275307
(minor, patch)
276308
}
277309
None => {
278310
let Ok(minor) = tail.parse::<u64>() else {
279-
return invalid_input(input, "the minor version number must be an unsigned 64-bit integer");
311+
return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer"));
280312
};
281313
(minor, 0)
282314
}
283315
};
284316

285-
Ok(Self(Version::Stable(minor, patch)))
317+
Self::stable(minor, patch).map_err(|err| invalid_input(input, err))
286318
}
287319
}
288320

@@ -380,5 +412,7 @@ mod test {
380412
test_invalid_target("1.-1.0");
381413
test_invalid_target("1.0.-1");
382414
test_invalid_target("beta");
415+
test_invalid_target("1.0.0");
416+
test_invalid_target("1.32.0");
383417
}
384418
}

0 commit comments

Comments
 (0)