• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Contains code for selecting features
2 
3 #![deny(missing_docs)]
4 #![deny(unused_extern_crates)]
5 #![allow(deprecated)]
6 
7 use std::io;
8 use std::str::FromStr;
9 
10 /// Define RustTarget struct definition, Default impl, and conversions
11 /// between RustTarget and String.
12 macro_rules! rust_target_def {
13     ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
14         /// Represents the version of the Rust language to target.
15         ///
16         /// To support a beta release, use the corresponding stable release.
17         ///
18         /// This enum will have more variants added as necessary.
19         #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash)]
20         #[allow(non_camel_case_types)]
21         pub enum RustTarget {
22             $(
23                 $(
24                     #[$attr]
25                 )*
26                 $release,
27             )*
28         }
29 
30         impl Default for RustTarget {
31             /// Gives the latest stable Rust version
32             fn default() -> RustTarget {
33                 LATEST_STABLE_RUST
34             }
35         }
36 
37         impl FromStr for RustTarget {
38             type Err = io::Error;
39 
40             /// Create a `RustTarget` from a string.
41             ///
42             /// * The stable/beta versions of Rust are of the form "1.0",
43             /// "1.19", etc.
44             /// * The nightly version should be specified with "nightly".
45             fn from_str(s: &str) -> Result<Self, Self::Err> {
46                 match s.as_ref() {
47                     $(
48                         stringify!($value) => Ok(RustTarget::$release),
49                     )*
50                     _ => Err(
51                         io::Error::new(
52                             io::ErrorKind::InvalidInput,
53                             concat!(
54                                 "Got an invalid rust target. Accepted values ",
55                                 "are of the form ",
56                                 "\"1.0\" or \"nightly\"."))),
57                 }
58             }
59         }
60 
61         impl From<RustTarget> for String {
62             fn from(target: RustTarget) -> Self {
63                 match target {
64                     $(
65                         RustTarget::$release => stringify!($value),
66                     )*
67                 }.into()
68             }
69         }
70     }
71 }
72 
73 /// Defines an array slice with all RustTarget values
74 macro_rules! rust_target_values_def {
75     ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
76         /// Strings of allowed `RustTarget` values
77         pub static RUST_TARGET_STRINGS: &'static [&str] = &[
78             $(
79                 stringify!($value),
80             )*
81         ];
82     }
83 }
84 
85 /// Defines macro which takes a macro
86 macro_rules! rust_target_base {
87     ( $x_macro:ident ) => {
88         $x_macro!(
89             /// Rust stable 1.0
90             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_0 => 1.0;
91             /// Rust stable 1.17
92             ///  * Static lifetime elision ([RFC 1623](https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md))
93             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_17 => 1.17;
94             /// Rust stable 1.19
95             ///  * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
96             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_19 => 1.19;
97             /// Rust stable 1.20
98             ///  * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
99             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_20 => 1.20;
100             /// Rust stable 1.21
101             ///  * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
102             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_21 => 1.21;
103             /// Rust stable 1.25
104             ///  * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006))
105             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_25 => 1.25;
106             /// Rust stable 1.26
107             ///  * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
108             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_26 => 1.26;
109             /// Rust stable 1.27
110             ///  * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
111             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_27 => 1.27;
112             /// Rust stable 1.28
113             ///  * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562))
114             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_28 => 1.28;
115             /// Rust stable 1.30
116             ///  * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/)
117             /// *  [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html)
118             #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_30 => 1.30;
119             /// Rust stable 1.33
120             ///  * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049))
121             => Stable_1_33 => 1.33;
122             /// Rust stable 1.36
123             ///  * `MaybeUninit` instead of `mem::uninitialized()` ([PR](https://github.com/rust-lang/rust/pull/60445))
124             => Stable_1_36 => 1.36;
125             /// Rust stable 1.40
126             /// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109))
127             => Stable_1_40 => 1.40;
128             /// Rust stable 1.47
129             /// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060))
130             => Stable_1_47 => 1.47;
131             /// Rust stable 1.64
132             ///  * `core_ffi_c` ([Tracking issue](https://github.com/rust-lang/rust/issues/94501))
133             => Stable_1_64 => 1.64;
134             /// Nightly rust
135             ///  * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
136             ///  * `vectorcall` calling convention (no tracking issue)
137             ///  * `c_unwind` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/74990))
138             => Nightly => nightly;
139         );
140     }
141 }
142 
143 rust_target_base!(rust_target_def);
144 rust_target_base!(rust_target_values_def);
145 
146 /// Latest stable release of Rust
147 pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_64;
148 
149 /// Create RustFeatures struct definition, new(), and a getter for each field
150 macro_rules! rust_feature_def {
151     (
152         $( $rust_target:ident {
153             $( $( #[$attr:meta] )* => $feature:ident; )*
154         } )*
155     ) => {
156         /// Features supported by a rust target
157         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
158         #[allow(missing_docs)] // Documentation should go into the relevant variants.
159         pub(crate) struct RustFeatures {
160             $( $(
161                 $(
162                     #[$attr]
163                 )*
164                 pub $feature: bool,
165             )* )*
166         }
167 
168         impl RustFeatures {
169             /// Gives a RustFeatures struct with all features disabled
170             fn new() -> Self {
171                 RustFeatures {
172                     $( $(
173                         $feature: false,
174                     )* )*
175                 }
176             }
177         }
178 
179         impl From<RustTarget> for RustFeatures {
180             fn from(rust_target: RustTarget) -> Self {
181                 let mut features = RustFeatures::new();
182 
183                 $(
184                 if rust_target >= RustTarget::$rust_target {
185                     $(
186                     features.$feature = true;
187                     )*
188                 }
189                 )*
190 
191                 features
192             }
193         }
194     }
195 }
196 
197 // NOTE(emilio): When adding or removing features here, make sure to update the
198 // documentation for the relevant variant in the rust_target_base macro
199 // definition.
200 rust_feature_def!(
201     Stable_1_17 {
202         => static_lifetime_elision;
203     }
204     Stable_1_19 {
205         => untagged_union;
206     }
207     Stable_1_20 {
208         => associated_const;
209     }
210     Stable_1_21 {
211         => builtin_clone_impls;
212     }
213     Stable_1_25 {
214         => repr_align;
215     }
216     Stable_1_26 {
217         => i128_and_u128;
218     }
219     Stable_1_27 {
220         => must_use_function;
221     }
222     Stable_1_28 {
223         => repr_transparent;
224     }
225     Stable_1_30 {
226         => min_const_fn;
227         => core_ffi_c_void;
228     }
229     Stable_1_33 {
230         => repr_packed_n;
231     }
232     Stable_1_36 {
233         => maybe_uninit;
234     }
235     Stable_1_40 {
236         => non_exhaustive;
237     }
238     Stable_1_47 {
239         => larger_arrays;
240     }
241     Stable_1_64 {
242         => core_ffi_c;
243     }
244     Nightly {
245         => thiscall_abi;
246         => vectorcall_abi;
247         => c_unwind_abi;
248     }
249 );
250 
251 impl Default for RustFeatures {
default() -> Self252     fn default() -> Self {
253         let default_rust_target: RustTarget = Default::default();
254         Self::from(default_rust_target)
255     }
256 }
257 
258 #[cfg(test)]
259 mod test {
260     #![allow(unused_imports)]
261     use super::*;
262 
263     #[test]
target_features()264     fn target_features() {
265         let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
266         assert!(
267             !f_1_0.static_lifetime_elision &&
268                 !f_1_0.core_ffi_c_void &&
269                 !f_1_0.untagged_union &&
270                 !f_1_0.associated_const &&
271                 !f_1_0.builtin_clone_impls &&
272                 !f_1_0.repr_align &&
273                 !f_1_0.thiscall_abi &&
274                 !f_1_0.vectorcall_abi
275         );
276         let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
277         assert!(
278             f_1_21.static_lifetime_elision &&
279                 !f_1_21.core_ffi_c_void &&
280                 f_1_21.untagged_union &&
281                 f_1_21.associated_const &&
282                 f_1_21.builtin_clone_impls &&
283                 !f_1_21.repr_align &&
284                 !f_1_21.thiscall_abi &&
285                 !f_1_21.vectorcall_abi
286         );
287         let f_nightly = RustFeatures::from(RustTarget::Nightly);
288         assert!(
289             f_nightly.static_lifetime_elision &&
290                 f_nightly.core_ffi_c_void &&
291                 f_nightly.untagged_union &&
292                 f_nightly.associated_const &&
293                 f_nightly.builtin_clone_impls &&
294                 f_nightly.maybe_uninit &&
295                 f_nightly.repr_align &&
296                 f_nightly.thiscall_abi &&
297                 f_nightly.vectorcall_abi &&
298                 f_nightly.c_unwind_abi
299         );
300     }
301 
test_target(target_str: &str, target: RustTarget)302     fn test_target(target_str: &str, target: RustTarget) {
303         let target_string: String = target.into();
304         assert_eq!(target_str, target_string);
305         assert_eq!(target, RustTarget::from_str(target_str).unwrap());
306     }
307 
308     #[test]
str_to_target()309     fn str_to_target() {
310         test_target("1.0", RustTarget::Stable_1_0);
311         test_target("1.17", RustTarget::Stable_1_17);
312         test_target("1.19", RustTarget::Stable_1_19);
313         test_target("1.21", RustTarget::Stable_1_21);
314         test_target("1.25", RustTarget::Stable_1_25);
315         test_target("nightly", RustTarget::Nightly);
316     }
317 }
318