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