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 { default() -> Self252 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] target_features()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 test_target(target_str: &str, target: RustTarget)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] str_to_target()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