1//! Contains code for selecting features
2
3#![deny(missing_docs)]
4#![deny(unused_extern_crates)]
5#![allow(deprecated)]
6
7use std::io;
8use std::str::FromStr;
9
10/// Define RustTarget struct definition, Default impl, and conversions
11/// between RustTarget and String.
12macro_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
74macro_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
86macro_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
143rust_target_base!(rust_target_def);
144rust_target_base!(rust_target_values_def);
145
146/// Latest stable release of Rust
147pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_64;
148
149/// Create RustFeatures struct definition, new(), and a getter for each field
150macro_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.
200rust_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
251impl Default for RustFeatures {
252 fn default() -> Self {
253 let default_rust_target: RustTarget = Default::default();
254 Self::from(default_rust_target)
255 }
256}
257
258#[cfg(test)]
259mod test {
260 #![allow(unused_imports)]
261 use super::*;
262
263 #[test]
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
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]
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