pub unsafe trait Isa: Copy + 'static {
fn is_enabled() -> bool;
unsafe fn new_unchecked() -> Self;
}
#[inline]
pub fn detect<S: Isa>() -> Option<S> {
S::is_enabled().then(|| unsafe { S::new_unchecked() })
}
macro_rules! isa_token {
($(#[$doc:meta])* $name:ident => $enabled:expr) => {
$(#[$doc])*
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct $name(());
// SAFETY: the private unit field makes `detect` (via `new_unchecked`)
unsafe impl Isa for $name {
#[inline]
fn is_enabled() -> bool {
$enabled
}
#[inline]
unsafe fn new_unchecked() -> Self {
Self(())
}
}
};
}
isa_token!(
Scalar => true
);
isa_token!(
Avx2 => crate::algorithms::simd_search::has_avx2()
);
isa_token!(
Ssse3 => {
#[cfg(all(target_arch = "x86_64", not(miri)))]
{
std::arch::is_x86_feature_detected!("ssse3")
}
#[cfg(any(not(target_arch = "x86_64"), miri))]
{
false
}
}
);
isa_token!(
Neon => cfg!(all(target_arch = "aarch64", not(miri)))
);
isa_token!(
FastBmi2 => crate::algorithms::bit_ops::has_fast_bmi2()
);
#[cfg(feature = "avx512")]
isa_token!(
Avx512F => crate::algorithms::simd_search::has_avx512f()
);
#[cfg(feature = "avx512")]
isa_token!(
Avx512Vpopcntdq => {
#[cfg(all(target_arch = "x86_64", not(miri)))]
{
std::arch::is_x86_feature_detected!("avx512f")
&& std::arch::is_x86_feature_detected!("avx512vpopcntdq")
}
#[cfg(any(not(target_arch = "x86_64"), miri))]
{
false
}
}
);
#[cfg(feature = "avx512")]
isa_token!(
Avx512Bw => {
#[cfg(all(target_arch = "x86_64", not(miri)))]
{
std::arch::is_x86_feature_detected!("avx512f")
&& std::arch::is_x86_feature_detected!("avx512bw")
}
#[cfg(any(not(target_arch = "x86_64"), miri))]
{
false
}
}
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scalar_token_always_available() {
assert!(detect::<Scalar>().is_some());
}
#[test]
fn test_tokens_agree_with_cached_helpers() {
assert_eq!(
detect::<Avx2>().is_some(),
crate::algorithms::simd_search::has_avx2()
);
assert_eq!(
detect::<FastBmi2>().is_some(),
crate::algorithms::bit_ops::has_fast_bmi2()
);
}
#[test]
#[cfg(feature = "avx512")]
fn test_avx512_subset_implications() {
if detect::<Avx512Vpopcntdq>().is_some() {
assert!(detect::<Avx512F>().is_some());
}
if detect::<Avx512Bw>().is_some() {
assert!(detect::<Avx512F>().is_some());
}
}
#[test]
fn test_token_as_kernel_parameter() {
fn kernel(_proof: Scalar, x: u32) -> u32 {
x + 1
}
let tok = detect::<Scalar>().unwrap();
assert_eq!(kernel(tok, 41), 42);
}
}