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 { |
252 | 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 ] |
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 | |