44#![ deny( clippy:: missing_docs_in_private_items) ]
55#![ allow( deprecated) ]
66
7- use std:: io;
87use 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) ]
1313pub struct RustTarget ( Version ) ;
1414
1515impl 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.
5881macro_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
248280impl 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
0 commit comments