Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / third_party / rust / bindgen / features.rs
blobe5e20680533523d553356fdfefbd5fa8d2eb5f0b
1 //! Contains code for selecting features
3 #![deny(unused_extern_crates)]
4 #![deny(clippy::missing_docs_in_private_items)]
5 #![allow(deprecated)]
7 use std::cmp::Ordering;
8 use std::io;
9 use std::str::FromStr;
11 /// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
12 macro_rules! define_rust_targets {
13     (
14         Nightly => {$($nightly_feature:ident $(: #$issue:literal)?),* $(,)?} $(,)?
15         $(
16             $(#[$attrs:meta])*
17             $variant:ident($minor:literal) => {$($feature:ident $(: #$pull:literal)?),* $(,)?},
18         )*
19         $(,)?
20     ) => {
21         /// Represents the version of the Rust language to target.
22         ///
23         /// To support a beta release, use the corresponding stable release.
24         ///
25         /// This enum will have more variants added as necessary.
26         #[allow(non_camel_case_types)]
27         #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28         pub enum RustTarget {
29             /// Rust Nightly
30             $(#[doc = concat!(
31                 "- [`", stringify!($nightly_feature), "`]",
32                 "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
33             )])*
34             Nightly,
35             $(
36                 #[doc = concat!("Rust 1.", stringify!($minor))]
37                 $(#[doc = concat!(
38                     "- [`", stringify!($feature), "`]",
39                     "(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")",
40                 )])*
41                 $(#[$attrs])*
42                 $variant,
43             )*
44         }
46         impl RustTarget {
47             fn minor(self) -> Option<u64> {
48                 match self {
49                     $( Self::$variant => Some($minor),)*
50                     Self::Nightly => None
51                 }
52             }
54             const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] {
55                 [$((Self::$variant, $minor),)*]
56             }
57         }
59         #[cfg(feature = "__cli")]
60         /// Strings of allowed `RustTarget` values
61         pub const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*];
63         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
64         pub(crate) struct RustFeatures {
65             $($(pub(crate) $feature: bool,)*)*
66             $(pub(crate) $nightly_feature: bool,)*
67         }
69         impl From<RustTarget> for RustFeatures {
70             fn from(target: RustTarget) -> Self {
71                 if target == RustTarget::Nightly {
72                     return Self {
73                         $($($feature: true,)*)*
74                         $($nightly_feature: true,)*
75                     };
76                 }
78                 let mut features = Self {
79                     $($($feature: false,)*)*
80                     $($nightly_feature: false,)*
81                 };
83                 $(if target >= RustTarget::$variant {
84                     $(features.$feature = true;)*
85                 })*
87                 features
88             }
89         }
90     };
93 // NOTE: When adding or removing features here, make sure to add the stabilization PR
94 // number for the feature if it has been stabilized or the tracking issue number if the feature is
95 // not stable.
96 define_rust_targets! {
97     Nightly => {
98         vectorcall_abi,
99     },
100     Stable_1_73(73) => { thiscall_abi: #42202 },
101     Stable_1_71(71) => { c_unwind_abi: #106075 },
102     Stable_1_68(68) => { abi_efiapi: #105795 },
103     Stable_1_64(64) => { core_ffi_c: #94503 },
104     Stable_1_59(59) => { const_cstr: #54745 },
105     Stable_1_47(47) => { larger_arrays: #74060 },
106     Stable_1_40(40) => { non_exhaustive: #44109 },
107     Stable_1_36(36) => { maybe_uninit: #60445 },
108     Stable_1_33(33) => { repr_packed_n: #57049 },
109     #[deprecated]
110     Stable_1_30(30) => {
111         core_ffi_c_void: #53910,
112         min_const_fn: #54835,
113     },
114     #[deprecated]
115     Stable_1_28(28) => { repr_transparent: #51562 },
116     #[deprecated]
117     Stable_1_27(27) => { must_use_function: #48925 },
118     #[deprecated]
119     Stable_1_26(26) => { i128_and_u128: #49101 },
120     #[deprecated]
121     Stable_1_25(25) => { repr_align: #47006 },
122     #[deprecated]
123     Stable_1_21(21) => { builtin_clone_impls: #43690 },
124     #[deprecated]
125     Stable_1_20(20) => { associated_const: #42809 },
126     #[deprecated]
127     Stable_1_19(19) => { untagged_union: #42068 },
128     #[deprecated]
129     Stable_1_17(17) => { static_lifetime_elision: #39265 },
130     #[deprecated]
131     Stable_1_0(0) => {},
134 /// Latest stable release of Rust
135 pub const LATEST_STABLE_RUST: RustTarget = {
136     // FIXME: replace all this code by
137     // ```
138     // RustTarget::stable_releases()
139     //     .into_iter()
140     //     .max_by_key(|(_, m)| m)
141     //     .map(|(t, _)| t)
142     //     .unwrap_or(RustTarget::Nightly)
143     // ```
144     // once those operations can be used in constants.
145     let targets = RustTarget::stable_releases();
147     let mut i = 0;
148     let mut latest_target = None;
149     let mut latest_minor = 0;
151     while i < targets.len() {
152         let (target, minor) = targets[i];
154         if latest_minor < minor {
155             latest_minor = minor;
156             latest_target = Some(target);
157         }
159         i += 1;
160     }
162     match latest_target {
163         Some(target) => target,
164         None => unreachable!(),
165     }
168 impl Default for RustTarget {
169     fn default() -> Self {
170         LATEST_STABLE_RUST
171     }
174 impl PartialOrd for RustTarget {
175     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
176         Some(self.cmp(other))
177     }
180 impl Ord for RustTarget {
181     fn cmp(&self, other: &Self) -> Ordering {
182         match (self.minor(), other.minor()) {
183             (Some(a), Some(b)) => a.cmp(&b),
184             (Some(_), None) => Ordering::Less,
185             (None, Some(_)) => Ordering::Greater,
186             (None, None) => Ordering::Equal,
187         }
188     }
191 impl FromStr for RustTarget {
192     type Err = io::Error;
194     fn from_str(s: &str) -> Result<Self, Self::Err> {
195         if s == "nightly" {
196             return Ok(Self::Nightly);
197         }
199         if let Some(("1", str_minor)) = s.split_once('.') {
200             if let Ok(minor) = str_minor.parse::<u64>() {
201                 for (target, target_minor) in Self::stable_releases() {
202                     if minor == target_minor {
203                         return Ok(target);
204                     }
205                 }
206             }
207         }
209         Err(io::Error::new(
210             io::ErrorKind::InvalidInput,
211             "Got an invalid Rust target. Accepted values are of the form \"1.71\" or \"nightly\"."
212         ))
213     }
216 impl std::fmt::Display for RustTarget {
217     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218         match self.minor() {
219             Some(minor) => write!(f, "1.{}", minor),
220             None => "nightly".fmt(f),
221         }
222     }
225 impl Default for RustFeatures {
226     fn default() -> Self {
227         RustTarget::default().into()
228     }
231 #[cfg(test)]
232 mod test {
233     #![allow(unused_imports)]
234     use super::*;
236     #[test]
237     fn target_features() {
238         let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
239         assert!(
240             !f_1_0.static_lifetime_elision &&
241                 !f_1_0.core_ffi_c_void &&
242                 !f_1_0.untagged_union &&
243                 !f_1_0.associated_const &&
244                 !f_1_0.builtin_clone_impls &&
245                 !f_1_0.repr_align &&
246                 !f_1_0.thiscall_abi &&
247                 !f_1_0.vectorcall_abi
248         );
249         let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
250         assert!(
251             f_1_21.static_lifetime_elision &&
252                 !f_1_21.core_ffi_c_void &&
253                 f_1_21.untagged_union &&
254                 f_1_21.associated_const &&
255                 f_1_21.builtin_clone_impls &&
256                 !f_1_21.repr_align &&
257                 !f_1_21.thiscall_abi &&
258                 !f_1_21.vectorcall_abi
259         );
260         let features = RustFeatures::from(RustTarget::Stable_1_71);
261         assert!(
262             features.c_unwind_abi &&
263                 features.abi_efiapi &&
264                 !features.thiscall_abi
265         );
266         let f_nightly = RustFeatures::from(RustTarget::Nightly);
267         assert!(
268             f_nightly.static_lifetime_elision &&
269                 f_nightly.core_ffi_c_void &&
270                 f_nightly.untagged_union &&
271                 f_nightly.associated_const &&
272                 f_nightly.builtin_clone_impls &&
273                 f_nightly.maybe_uninit &&
274                 f_nightly.repr_align &&
275                 f_nightly.thiscall_abi &&
276                 f_nightly.vectorcall_abi
277         );
278     }
280     fn test_target(target_str: &str, target: RustTarget) {
281         let target_string = target.to_string();
282         assert_eq!(target_str, target_string);
283         assert_eq!(target, RustTarget::from_str(target_str).unwrap());
284     }
286     #[test]
287     fn str_to_target() {
288         test_target("1.0", RustTarget::Stable_1_0);
289         test_target("1.17", RustTarget::Stable_1_17);
290         test_target("1.19", RustTarget::Stable_1_19);
291         test_target("1.21", RustTarget::Stable_1_21);
292         test_target("1.25", RustTarget::Stable_1_25);
293         test_target("1.71", RustTarget::Stable_1_71);
294         test_target("nightly", RustTarget::Nightly);
295     }