use lazy_static::lazy_static;
lazy_static! {
pub static ref TARGET_CONFIG: TargetConfiguration = TargetConfiguration::default();
}
#[derive(Clone, Debug)]
pub struct TargetConfiguration {
pub arch: String,
pub feature: String,
pub os: String,
pub family: String,
pub env: String,
pub endian: String,
pub pointer_width: String,
pub vendor: String,
}
impl Default for TargetConfiguration {
fn default() -> Self {
fn getenv(var: &'static str) -> String {
std::env::var(var)
.unwrap_or_else(|_| String::new())
.to_uppercase()
}
TargetConfiguration {
arch: getenv("CARGO_CFG_TARGET_ARCH"),
feature: getenv("CARGO_CFG_TARGET_FEATURE"),
os: getenv("CARGO_CFG_TARGET_OS"),
family: getenv("CARGO_CFG_TARGET_FAMILY"),
env: getenv("CARGO_CFG_TARGET_ENV"),
endian: getenv("CARGO_CFG_TARGET_ENDIAN"),
pointer_width: getenv("CARGO_CFG_TARGET_POINTER_WIDTH"),
vendor: getenv("CARGO_CFG_TARGET_VENDOR"),
}
}
}
impl TargetConfiguration {
pub fn target_arch(&self, arch: &str) -> bool {
self.arch == arch.to_uppercase()
}
pub fn target_os(&self, os: &str) -> bool {
self.os == os.to_uppercase()
}
pub fn target_family(&self, family: &str) -> bool {
self.family == family.to_uppercase()
}
pub fn target_env(&self, env: &str) -> bool {
self.env == env.to_uppercase()
}
pub fn target_endian(&self, endian: &str) -> bool {
self.endian == endian.to_uppercase()
}
pub fn target_pointer_width(&self, pointer_width: &str) -> bool {
self.pointer_width == pointer_width.to_uppercase()
}
pub fn target_vendor(&self, vendor: &str) -> bool {
self.vendor == vendor.to_uppercase()
}
}
#[macro_export]
macro_rules! target_cfg {
(
@emit
all
$({$($grouped:tt)+})+
) => {
($(
target_cfg!($($grouped)+)
)&&+)
};
(
@emit
any
$({$($grouped:tt)+})+
) => {
($(
target_cfg!($($grouped)+)
)||+)
};
(
@clause
$op:ident
[$({$($grouped:tt)+})*]
[, $($rest:tt)*]
$($current:tt)+
) => {
target_cfg!(@clause $op [
$(
{$($grouped)+}
)*
{$($current)+}
] [
$($rest)*
])
};
(
@clause
$op:ident
[$({$($grouped:tt)+})*]
[$tok:tt $($rest:tt)*]
$($current:tt)*
) => {
target_cfg!(@clause $op [
$(
{$($grouped)+}
)*
] [
$($rest)*
] $($current)* $tok)
};
(
@clause
$op:ident
[$({$($grouped:tt)+})*]
[]
$($current:tt)+
) => {
target_cfg!(@emit $op
$(
{$($grouped)+}
)*
{$($current)+}
)
};
(
all($($tokens:tt)+)
) => {
target_cfg!(@clause all [] [$($tokens)+])
};
(
any($($tokens:tt)+)
) => {
target_cfg!(@clause any [] [$($tokens)+])
};
(
not($($tokens:tt)+)
) => {
!(target_cfg!($($tokens)+))
};
(
$e:tt = $v:expr
) => {
$crate::TARGET_CONFIG.$e($v)
};
}
#[cfg(test)]
mod tests {
fn setup_test_env() {
std::env::set_var("CARGO_CFG_TARGET_ARCH", "testarch");
std::env::set_var("CARGO_CFG_TARGET_FEATURE", "testfeat1,testfeat2");
std::env::set_var("CARGO_CFG_TARGET_OS", "testos");
std::env::set_var("CARGO_CFG_TARGET_FAMILY", "testfamily");
std::env::set_var("CARGO_CFG_TARGET_ENV", "testenv");
std::env::set_var("CARGO_CFG_TARGET_ENDIAN", "little");
std::env::set_var("CARGO_CFG_TARGET_POINTER_WIDTH", "32");
std::env::set_var("CARGO_CFG_TARGET_VENDOR", "testvendor");
}
#[test]
fn test_level0() {
setup_test_env();
assert!(target_cfg!(target_arch = "testarch"));
assert!(!target_cfg!(target_arch = "wrong"));
assert!(target_cfg!(target_os = "testos"));
assert!(target_cfg!(target_family = "testfamily"));
assert!(target_cfg!(target_env = "testenv"));
assert!(target_cfg!(target_endian = "little"));
assert!(target_cfg!(target_pointer_width = "32"));
assert!(target_cfg!(target_vendor = "testvendor"));
}
#[test]
fn test_level1() {
setup_test_env();
assert!(target_cfg!(not(target_arch = "wrong")));
assert!(!target_cfg!(not(target_arch = "testarch")));
assert!(target_cfg!(all(target_arch = "testarch")));
assert!(!target_cfg!(all(target_arch = "wrong")));
assert!(target_cfg!(all(
target_arch = "testarch",
target_os = "testos"
)));
assert!(!target_cfg!(all(
target_arch = "testarch",
target_os = "wrong"
)));
assert!(target_cfg!(any(target_arch = "testarch")));
assert!(!target_cfg!(any(target_arch = "wrong")));
assert!(target_cfg!(any(
target_arch = "testarch",
target_os = "testos"
)));
assert!(target_cfg!(any(
target_arch = "testarch",
target_os = "wrong"
)));
assert!(!target_cfg!(any(
target_arch = "wrong1",
target_os = "wrong2"
)));
}
#[test]
fn test_level2() {
setup_test_env();
assert!(target_cfg!(all(not(target_arch = "wrong"))));
assert!(!target_cfg!(all(not(target_arch = "testarch"))));
assert!(target_cfg!(all(
target_arch = "testarch",
not(target_os = "wrong")
)));
assert!(target_cfg!(all(
any(target_arch = "testarch", target_os = "wrong"),
target_env = "testenv"
)));
assert!(target_cfg!(all(
any(target_arch = "testarch", target_os = "wrong"),
not(target_vendor = "wrong")
)));
}
}