• 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.1
91             => Stable_1_1 => 1.1;
92             /// Rust stable 1.19
93             ///  * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
94             => Stable_1_19 => 1.19;
95             /// Rust stable 1.20
96             ///  * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
97             => Stable_1_20 => 1.20;
98             /// Rust stable 1.21
99             ///  * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
100             => Stable_1_21 => 1.21;
101             /// Rust stable 1.25
102             ///  * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006))
103             => Stable_1_25 => 1.25;
104             /// Rust stable 1.26
105             ///  * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
106             => Stable_1_26 => 1.26;
107             /// Rust stable 1.27
108             ///  * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
109             => Stable_1_27 => 1.27;
110             /// Rust stable 1.28
111             ///  * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562))
112             => Stable_1_28 => 1.28;
113             /// Rust stable 1.30
114             ///  * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/)
115             /// *  [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html)
116             => Stable_1_30 => 1.30;
117             /// Rust stable 1.33
118             ///  * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049))
119             => Stable_1_33 => 1.33;
120             /// Rust stable 1.36
121             ///  * `MaybeUninit` instead of `mem::uninitialized()` ([PR](https://github.com/rust-lang/rust/pull/60445))
122             => Stable_1_36 => 1.36;
123             /// Rust stable 1.40
124             /// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109))
125             => Stable_1_40 => 1.40;
126             /// Nightly rust
127             ///  * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
128             => Nightly => nightly;
129         );
130     }
131 }
132 
133 rust_target_base!(rust_target_def);
134 rust_target_base!(rust_target_values_def);
135 
136 /// Latest stable release of Rust
137 pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_40;
138 
139 /// Create RustFeatures struct definition, new(), and a getter for each field
140 macro_rules! rust_feature_def {
141     (
142         $( $rust_target:ident {
143             $( $( #[$attr:meta] )* => $feature:ident; )*
144         } )*
145     ) => {
146         /// Features supported by a rust target
147         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
148         #[allow(missing_docs)] // Documentation should go into the relevant variants.
149         pub(crate) struct RustFeatures {
150             $( $(
151                 $(
152                     #[$attr]
153                 )*
154                 pub $feature: bool,
155             )* )*
156         }
157 
158         impl RustFeatures {
159             /// Gives a RustFeatures struct with all features disabled
160             fn new() -> Self {
161                 RustFeatures {
162                     $( $(
163                         $feature: false,
164                     )* )*
165                 }
166             }
167         }
168 
169         impl From<RustTarget> for RustFeatures {
170             fn from(rust_target: RustTarget) -> Self {
171                 let mut features = RustFeatures::new();
172 
173                 $(
174                 if rust_target >= RustTarget::$rust_target {
175                     $(
176                     features.$feature = true;
177                     )*
178                 }
179                 )*
180 
181                 features
182             }
183         }
184     }
185 }
186 
187 // NOTE(emilio): When adding or removing features here, make sure to update the
188 // documentation for the relevant variant in the rust_target_base macro
189 // definition.
190 rust_feature_def!(
191     Stable_1_19 {
192         => untagged_union;
193     }
194     Stable_1_20 {
195         => associated_const;
196     }
197     Stable_1_21 {
198         => builtin_clone_impls;
199     }
200     Stable_1_25 {
201         => repr_align;
202     }
203     Stable_1_26 {
204         => i128_and_u128;
205     }
206     Stable_1_27 {
207         => must_use_function;
208     }
209     Stable_1_28 {
210         => repr_transparent;
211     }
212     Stable_1_30 {
213         => min_const_fn;
214         => core_ffi_c_void;
215     }
216     Stable_1_33 {
217         => repr_packed_n;
218     }
219     Stable_1_36 {
220         => maybe_uninit;
221     }
222     Stable_1_40 {
223         => non_exhaustive;
224     }
225     Nightly {
226         => thiscall_abi;
227     }
228 );
229 
230 impl Default for RustFeatures {
default() -> Self231     fn default() -> Self {
232         let default_rust_target: RustTarget = Default::default();
233         Self::from(default_rust_target)
234     }
235 }
236 
237 #[cfg(test)]
238 mod test {
239     #![allow(unused_imports)]
240     use super::*;
241 
242     #[test]
target_features()243     fn target_features() {
244         let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
245         assert!(
246             !f_1_0.core_ffi_c_void &&
247                 !f_1_0.untagged_union &&
248                 !f_1_0.associated_const &&
249                 !f_1_0.builtin_clone_impls &&
250                 !f_1_0.repr_align &&
251                 !f_1_0.thiscall_abi
252         );
253         let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
254         assert!(
255             !f_1_21.core_ffi_c_void &&
256                 f_1_21.untagged_union &&
257                 f_1_21.associated_const &&
258                 f_1_21.builtin_clone_impls &&
259                 !f_1_21.repr_align &&
260                 !f_1_21.thiscall_abi
261         );
262         let f_nightly = RustFeatures::from(RustTarget::Nightly);
263         assert!(
264             f_nightly.core_ffi_c_void &&
265                 f_nightly.untagged_union &&
266                 f_nightly.associated_const &&
267                 f_nightly.builtin_clone_impls &&
268                 f_nightly.maybe_uninit &&
269                 f_nightly.repr_align &&
270                 f_nightly.thiscall_abi
271         );
272     }
273 
test_target(target_str: &str, target: RustTarget)274     fn test_target(target_str: &str, target: RustTarget) {
275         let target_string: String = target.into();
276         assert_eq!(target_str, target_string);
277         assert_eq!(target, RustTarget::from_str(target_str).unwrap());
278     }
279 
280     #[test]
str_to_target()281     fn str_to_target() {
282         test_target("1.0", RustTarget::Stable_1_0);
283         test_target("1.19", RustTarget::Stable_1_19);
284         test_target("1.21", RustTarget::Stable_1_21);
285         test_target("1.25", RustTarget::Stable_1_25);
286         test_target("nightly", RustTarget::Nightly);
287     }
288 }
289