2017-08-13 13:12:21 -07:00
|
|
|
//! Contains code for selecting features
|
|
|
|
|
|
|
|
#![deny(missing_docs)]
|
|
|
|
#![deny(warnings)]
|
|
|
|
#![deny(unused_extern_crates)]
|
|
|
|
|
|
|
|
use std::io;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
/// Define RustTarget struct definition, Default impl, and conversions
|
|
|
|
/// between RustTarget and String.
|
|
|
|
macro_rules! rust_target_def {
|
|
|
|
( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
|
|
|
|
/// Represents the version of the Rust language to target.
|
|
|
|
///
|
|
|
|
/// To support a beta release, use the corresponding stable release.
|
|
|
|
///
|
|
|
|
/// This enum will have more variants added as necessary.
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash)]
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
pub enum RustTarget {
|
|
|
|
$(
|
|
|
|
$(
|
|
|
|
#[$attr]
|
|
|
|
)*
|
|
|
|
$release,
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for RustTarget {
|
|
|
|
/// Gives the latest stable Rust version
|
|
|
|
fn default() -> RustTarget {
|
|
|
|
LATEST_STABLE_RUST
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for RustTarget {
|
|
|
|
type Err = io::Error;
|
|
|
|
|
|
|
|
/// Create a `RustTarget` from a string.
|
|
|
|
///
|
|
|
|
/// * The stable/beta versions of Rust are of the form "1.0",
|
|
|
|
/// "1.19", etc.
|
|
|
|
/// * The nightly version should be specified with "nightly".
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
match s.as_ref() {
|
|
|
|
$(
|
|
|
|
stringify!($value) => Ok(RustTarget::$release),
|
|
|
|
)*
|
|
|
|
_ => Err(
|
|
|
|
io::Error::new(
|
|
|
|
io::ErrorKind::InvalidInput,
|
|
|
|
concat!(
|
|
|
|
"Got an invalid rust target. Accepted values ",
|
|
|
|
"are of the form ",
|
|
|
|
"\"1.0\" or \"nightly\"."))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<RustTarget> for String {
|
|
|
|
fn from(target: RustTarget) -> Self {
|
|
|
|
match target {
|
|
|
|
$(
|
|
|
|
RustTarget::$release => stringify!($value),
|
|
|
|
)*
|
|
|
|
}.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines an array slice with all RustTarget values
|
|
|
|
macro_rules! rust_target_values_def {
|
|
|
|
( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
|
|
|
|
/// Strings of allowed `RustTarget` values
|
|
|
|
pub static RUST_TARGET_STRINGS: &'static [&str] = &[
|
|
|
|
$(
|
|
|
|
stringify!($value),
|
|
|
|
)*
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines macro which takes a macro
|
|
|
|
macro_rules! rust_target_base {
|
|
|
|
( $x_macro:ident ) => {
|
|
|
|
$x_macro!(
|
|
|
|
/// Rust stable 1.0
|
|
|
|
=> Stable_1_0 => 1.0;
|
|
|
|
/// Rust stable 1.19
|
|
|
|
=> Stable_1_19 => 1.19;
|
2018-04-01 17:46:42 -08:00
|
|
|
/// Rust stable 1.20
|
|
|
|
=> Stable_1_20 => 1.20;
|
2017-10-14 17:18:38 +03:00
|
|
|
/// Rust stable 1.21
|
|
|
|
=> Stable_1_21 => 1.21;
|
2018-03-13 12:22:11 +01:00
|
|
|
/// Rust stable 1.25
|
|
|
|
=> Stable_1_25 => 1.25;
|
2018-09-19 02:36:48 +02:00
|
|
|
/// Rust stable 1.26
|
|
|
|
=> Stable_1_26 => 1.26;
|
2017-08-13 13:12:21 -07:00
|
|
|
/// Nightly rust
|
|
|
|
=> Nightly => nightly;
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rust_target_base!(rust_target_def);
|
|
|
|
rust_target_base!(rust_target_values_def);
|
|
|
|
|
|
|
|
/// Latest stable release of Rust
|
2017-10-14 17:18:38 +03:00
|
|
|
pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_21;
|
2017-08-13 13:12:21 -07:00
|
|
|
|
|
|
|
/// Create RustFeatures struct definition, new(), and a getter for each field
|
|
|
|
macro_rules! rust_feature_def {
|
2018-07-06 20:39:30 -04:00
|
|
|
(
|
|
|
|
$( $rust_target:ident {
|
|
|
|
$( $( #[$attr:meta] )* => $feature:ident; )*
|
|
|
|
} )*
|
|
|
|
) => {
|
2017-08-13 13:12:21 -07:00
|
|
|
/// Features supported by a rust target
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
|
|
pub struct RustFeatures {
|
2018-07-06 20:39:30 -04:00
|
|
|
$( $(
|
2018-03-10 07:15:10 +01:00
|
|
|
$(
|
|
|
|
#[$attr]
|
|
|
|
)*
|
|
|
|
pub $feature: bool,
|
2018-07-06 20:39:30 -04:00
|
|
|
)* )*
|
2017-08-13 13:12:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RustFeatures {
|
|
|
|
/// Gives a RustFeatures struct with all features disabled
|
|
|
|
fn new() -> Self {
|
|
|
|
RustFeatures {
|
2018-07-06 20:39:30 -04:00
|
|
|
$( $(
|
2017-08-13 13:12:21 -07:00
|
|
|
$feature: false,
|
2018-07-06 20:39:30 -04:00
|
|
|
)* )*
|
2017-08-13 13:12:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 20:39:30 -04:00
|
|
|
impl From<RustTarget> for RustFeatures {
|
|
|
|
fn from(rust_target: RustTarget) -> Self {
|
|
|
|
let mut features = RustFeatures::new();
|
2017-08-13 13:12:21 -07:00
|
|
|
|
2018-07-06 20:39:30 -04:00
|
|
|
$(
|
|
|
|
if rust_target >= RustTarget::$rust_target {
|
|
|
|
$(
|
|
|
|
features.$feature = true;
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
)*
|
2018-03-10 07:06:36 +01:00
|
|
|
|
2018-07-06 20:39:30 -04:00
|
|
|
features
|
|
|
|
}
|
2017-08-13 13:12:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 20:39:30 -04:00
|
|
|
rust_feature_def!(
|
|
|
|
Stable_1_19 {
|
|
|
|
/// Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
|
|
|
|
=> untagged_union;
|
|
|
|
}
|
|
|
|
Stable_1_20 {
|
|
|
|
/// associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
|
|
|
|
=> associated_const;
|
|
|
|
}
|
|
|
|
Stable_1_21 {
|
|
|
|
/// builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
|
|
|
|
=> builtin_clone_impls;
|
|
|
|
}
|
|
|
|
Stable_1_25 {
|
|
|
|
/// repr(align) ([PR](https://github.com/rust-lang/rust/pull/47006))
|
|
|
|
=> repr_align;
|
|
|
|
}
|
2018-09-19 02:36:48 +02:00
|
|
|
Stable_1_26 {
|
|
|
|
/// [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
|
|
|
|
=> i128_and_u128;
|
|
|
|
}
|
2018-07-06 20:39:30 -04:00
|
|
|
Nightly {
|
|
|
|
/// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
|
|
|
|
=> thiscall_abi;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2017-08-13 13:12:21 -07:00
|
|
|
impl Default for RustFeatures {
|
|
|
|
fn default() -> Self {
|
|
|
|
let default_rust_target: RustTarget = Default::default();
|
|
|
|
Self::from(default_rust_target)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2018-07-06 20:39:30 -04:00
|
|
|
#![allow(unused_imports)]
|
2017-08-13 13:12:21 -07:00
|
|
|
use super::*;
|
|
|
|
|
2018-07-06 20:39:30 -04:00
|
|
|
#[test]
|
|
|
|
fn target_features() {
|
|
|
|
let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
|
|
|
|
assert!(
|
|
|
|
!f_1_0.untagged_union
|
|
|
|
&& !f_1_0.associated_const
|
|
|
|
&& !f_1_0.builtin_clone_impls
|
|
|
|
&& !f_1_0.repr_align
|
|
|
|
&& !f_1_0.thiscall_abi
|
|
|
|
);
|
|
|
|
let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
|
|
|
|
assert!(
|
|
|
|
f_1_21.untagged_union
|
|
|
|
&& f_1_21.associated_const
|
|
|
|
&& f_1_21.builtin_clone_impls
|
|
|
|
&& !f_1_21.repr_align
|
|
|
|
&& !f_1_21.thiscall_abi
|
|
|
|
);
|
|
|
|
let f_nightly = RustFeatures::from(RustTarget::Nightly);
|
|
|
|
assert!(
|
|
|
|
f_nightly.untagged_union
|
|
|
|
&& f_nightly.associated_const
|
|
|
|
&& f_nightly.builtin_clone_impls
|
|
|
|
&& f_nightly.repr_align
|
|
|
|
&& f_nightly.thiscall_abi
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-08-13 13:12:21 -07:00
|
|
|
fn test_target(target_str: &str, target: RustTarget) {
|
|
|
|
let target_string: String = target.into();
|
|
|
|
assert_eq!(target_str, target_string);
|
|
|
|
assert_eq!(target, RustTarget::from_str(target_str).unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn str_to_target() {
|
|
|
|
test_target("1.0", RustTarget::Stable_1_0);
|
|
|
|
test_target("1.19", RustTarget::Stable_1_19);
|
2017-10-14 17:18:38 +03:00
|
|
|
test_target("1.21", RustTarget::Stable_1_21);
|
2018-03-13 12:22:11 +01:00
|
|
|
test_target("1.25", RustTarget::Stable_1_25);
|
2017-08-13 13:12:21 -07:00
|
|
|
test_target("nightly", RustTarget::Nightly);
|
|
|
|
}
|
|
|
|
}
|