#![allow(unused, unused_macros, unused_imports)]
use target_features::Target;
mod unconstructible {
pub struct Unconstructible(());
impl Unconstructible {
pub unsafe fn new() -> Self {
Self(())
}
}
}
use unconstructible::Unconstructible;
unsafe trait Proof: Sized {
const TARGET: Target;
fn detect() -> Option<Self>;
unsafe fn assume() -> Self;
}
macro_rules! make_target_proof {
{ $vis:vis struct $proof:ident($($feature:tt),*); } => {
$vis struct $proof(Unconstructible);
unsafe impl Proof for $proof {
const TARGET: Target = target_features::CURRENT_TARGET$(.with_feature_str($feature))*;
fn detect() -> Option<Self> {
if true $(&& is_x86_feature_detected!($feature))* {
unsafe { Some(Self::assume()) }
} else {
None
}
}
unsafe fn assume() -> Self {
Self(Unconstructible::new())
}
}
}
}
#[cfg(target_arch = "x86_64")]
fn safe_avx_fn<P: Proof>(_: P) {
#[target_feature(enable = "avx")]
unsafe fn unsafe_avx_fn() {
println!("called an avx function")
}
assert!(
P::TARGET.supports_feature_str("avx"),
"avx feature not supported"
);
unsafe { unsafe_avx_fn() }
}
#[cfg(target_arch = "x86_64")]
fn main() {
make_target_proof! {
struct Avx("avx");
}
if let Some(proof) = Avx::detect() {
safe_avx_fn(proof);
}
make_target_proof! {
struct Avx2("avx2");
}
if let Some(proof) = Avx2::detect() {
safe_avx_fn(proof);
}
make_target_proof! {
struct Aes("aes");
}
if let Some(proof) = Aes::detect() {
safe_avx_fn(proof);
}
}
#[cfg(not(target_arch = "x86_64"))]
fn main() {}