use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use std::sync::{LazyLock, OnceLock};
#[macro_export]
macro_rules! multiversion {
(
use {$($($path:ident::)+*),*};
#[dyn_dispatch = $dispatch:path]
$(#[$m:meta])* $v:vis fn $name:ident($($arg_name:ident: $arg_type:ty),*$(,)?) $(-> $ret:ty)? $body:block
$($tail:tt)*
) => {
mod $name {
#[allow(clippy::allow_attributes, unused_imports)]
use {super::*, $crate::multiversion}; $crate::multiversion!{
use {$($($path::)+*),*};
$(#[$m])* pub fn $name($($arg_name: $arg_type),*) $(-> $ret)? $body
$($tail)*
}
}
#[inline]
$v fn $name($($arg_name: $arg_type),*) $(-> $ret)? {
use $crate::multiversion::Version::*;
match *$dispatch {
Scalar => $name::scalar::$name($($arg_name),*),
Array128 => $name::array128::$name($($arg_name),*),
Array256 => $name::array256::$name($($arg_name),*),
#[cfg(not(target_family = "wasm"))]
Array4096 => $name::array4096::$name($($arg_name),*),
#[cfg(all(feature="unsafe", any(target_arch = "x86", target_arch = "x86_64")))]
AVX2 => unsafe { $name::avx2::$name($($arg_name),*) },
}
}
};
(
use {$($($path:ident::)+*),*};
$($tail:tt)+
) => {
pub mod scalar {
#![allow(
clippy::reversed_empty_ranges,
clippy::range_plus_one,
clippy::modulo_one,
clippy::trivially_copy_pass_by_ref
)]
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {super::*, $($($path::)+scalar::*),*};
$($tail)*
}
pub mod array128 {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {super::*, $($($path::)+array128::*),*};
$($tail)*
}
pub mod array256 {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {super::*, $($($path::)+array256::*),*};
$($tail)*
}
#[cfg(not(target_family = "wasm"))]
pub mod array4096 {
#![allow(clippy::large_types_passed_by_value)]
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {super::*, $($($path::)+array4096::*),*};
$($tail)*
}
#[cfg(all(feature="unsafe", any(target_arch = "x86", target_arch = "x86_64")))]
pub mod avx2 {
#![allow(clippy::missing_safety_doc)]
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {super::*, $($($path::)+avx2::*),*};
$crate::multiversion!{@helper target_feature(enable = "avx2") $($tail)*}
}
};
(fastest($name:ident())) => {
::std::sync::LazyLock::new(#[cfg_attr(target_family = "wasm", expect(unreachable_code))] || {
use $crate::multiversion::Version::*;
#[cfg(all(target_family = "wasm", target_feature = "simd128"))]
return Array256;
#[cfg(all(target_family = "wasm"))]
return Array128;
if let Some(version) = $crate::multiversion::Version::get_override() {
return version;
}
$crate::multiversion::VERSIONS
.iter()
.map(|&x| {
let start = ::std::time::Instant::now();
::std::hint::black_box(match x {
Scalar => scalar::$name(),
Array128 => array128::$name(),
Array256 => array256::$name(),
#[cfg(not(target_family = "wasm"))]
Array4096 => array4096::$name(),
#[cfg(all(feature="unsafe", any(target_arch = "x86", target_arch = "x86_64")))]
AVX2 => unsafe { avx2::$name() },
});
(start.elapsed(), x)
})
.min_by_key(|x| x.0)
.unwrap()
.1
})
};
(@helper $t:meta) => {};
(@helper $t:meta #[inline(always)] $($tail:tt)*) => {$crate::multiversion!{@helper $t #[inline] $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis const $n:ident: $ty:ty = $e:expr; $($tail:tt)*) => {$(#[$m])* $v const $n: $ty = $e; $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $t29:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $t29 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $t29:tt $t30:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $t29 $t30 $b $crate::multiversion!{@helper $t $($tail)*}};
(@helper $t:meta $(#[$m:meta])* $v:vis fn $n:ident $t0:tt $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $t19:tt $t20:tt $t21:tt $t22:tt $t23:tt $t24:tt $t25:tt $t26:tt $t27:tt $t28:tt $t29:tt $t30:tt $t31:tt $b:block $($tail:tt)*) => {$(#[$m])* #[$t] $v unsafe fn $n $t0 $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18 $t19 $t20 $t21 $t22 $t23 $t24 $t25 $t26 $t27 $t28 $t29 $t30 $t31 $b $crate::multiversion!{@helper $t $($tail)*}};
}
#[cfg(test)]
#[macro_export]
macro_rules! multiversion_test {
(
use {$($($path:ident::)+*),*};
#[test]
$(#[$m:meta])* $v:vis fn multiversion() $body:block
) => {
#[test]
$(#[$m])*
fn scalar() {
#![allow(
clippy::reversed_empty_ranges,
clippy::range_plus_one,
clippy::modulo_one,
clippy::trivially_copy_pass_by_ref
)]
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {$($($path::)+scalar::*),*};
$body
}
#[test]
$(#[$m])*
fn array128() {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {$($($path::)+array128::*),*};
$body
}
#[test]
$(#[$m])*
fn array256() {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {$($($path::)+array256::*),*};
$body
}
#[test]
$(#[$m])*
fn array4096() {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {$($($path::)+array4096::*),*};
$body
}
#[test]
#[cfg(all(feature="unsafe", any(target_arch = "x86", target_arch = "x86_64")))]
$(#[$m])*
fn avx2() {
#[allow(clippy::allow_attributes, unused_imports, clippy::wildcard_imports)]
use {$($($path::)+avx2::*),*};
if !std::arch::is_x86_feature_detected!("avx2") {
use std::io::{stdout, Write};
let _ = writeln!(&mut stdout(), "warning: skipping test in {}::avx2 due to missing avx2 support", module_path!());
return;
}
unsafe { $body }
}
};
}
macro_rules! versions_impl {
($($
(#[$m:meta])*
$name:ident $(if $supported:expr)?,
)+) => {
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub enum Version {
#[default] $(
$(#[$m])*
$(#[doc = concat!("Requires `", stringify!($supported), "`.")])?
$name,
)+
}
impl Version {
#[must_use]
pub fn supported(self) -> bool {
match self {
$($(#[$m])* Version::$name => true $(&& $supported)?,)+
}
}
}
impl FromStr for Version {
type Err = UnknownVersion;
fn from_str(x: &str) -> Result<Self, Self::Err> {
$(
$(#[$m])*
if stringify!($name).eq_ignore_ascii_case(x) { return Ok(Version::$name); }
)+
Err(UnknownVersion(x.to_string()))
}
}
pub static VERSIONS: LazyLock<Vec<Version>> = LazyLock::new(|| {
let mut vec = vec![$($(#[$m])* Version::$name,)+];
vec.retain(|i| i.supported());
vec
});
};
}
versions_impl! {
Scalar,
Array128,
Array256,
#[cfg(not(target_family = "wasm"))]
Array4096,
#[cfg(all(feature = "unsafe", any(target_arch = "x86", target_arch = "x86_64")))]
AVX2 if std::arch::is_x86_feature_detected!("avx2"),
}
static OVERRIDE: OnceLock<Option<Version>> = OnceLock::new();
impl Version {
pub fn get_override() -> Option<Version> {
*OVERRIDE.get_or_init(|| None)
}
pub fn set_override(version: Version) {
assert!(version.supported(), "{version:?} is not supported!");
if OVERRIDE.set(Some(version)).is_err() {
if Self::get_override().is_none() {
panic!("Version::set_override must be called before get_override");
} else {
panic!("Version::set_override called more than once");
}
}
}
}
#[derive(Debug)]
pub struct UnknownVersion(String);
impl Display for UnknownVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "unknown function version: {:#}", self.0)
}
}
impl Error for UnknownVersion {}