1pub trait Feature {
3 fn name(&self) -> &'static str;
5
6 fn required(&self) -> bool;
8
9 fn vector_length(&self) -> usize;
11
12 fn check(&self) -> bool {
14 if self.required() {
15 return true;
16 }
17
18 self.check_volatile()
19 }
20
21 fn check_volatile(&self) -> bool;
23}
24
25#[cfg_attr(not(target_arch = "x86_64"), expect(unused))]
27pub fn iterate<F: FnMut(&dyn Feature)>(mut f: F) {
28 #[cfg(target_arch = "x86_64")]
29 {
30 f(&Sha);
31 f(&Avx2);
32 f(&Avx512F);
33 f(&Avx512VL);
34 }
35}
36
37macro_rules! define_x86_feature {
38 ($name:ident, $cpuid_name:ident, $feature:tt) => {
39 #[cfg(target_arch = "x86_64")]
40 cpufeatures::new!($cpuid_name, $feature);
41
42 #[cfg(target_arch = "x86_64")]
43 #[derive(Default)]
44 #[doc = concat!("X86 ", stringify!($feature), " feature.")]
45 pub struct $name;
46
47 #[cfg(target_arch = "x86_64")]
48 impl Feature for $name {
49 fn name(&self) -> &'static str {
50 stringify!($feature)
51 }
52
53 fn required(&self) -> bool {
54 cfg!(target_feature = $feature)
55 }
56
57 fn vector_length(&self) -> usize {
58 32
59 }
60
61 fn check_volatile(&self) -> bool {
62 $cpuid_name::get()
63 }
64 }
65 };
66}
67
68define_x86_feature!(Sha, cpuid_sha, "sha");
69define_x86_feature!(Avx2, cpuid_avx2, "avx2");
70define_x86_feature!(Avx512F, cpuid_avx512f, "avx512f");
71define_x86_feature!(Avx512VL, cpuid_avx512vl, "avx512vl");
72
73#[cfg(test)]
74mod tests {
75 #[cfg_attr(not(target_arch = "x86_64"), expect(unused_imports))]
76 use super::*;
77
78 macro_rules! write_test {
79 ($test_name:ident, $name:tt, $checker:expr) => {
80 #[test]
81 fn $test_name() {
82 if !cfg!(target_feature = $name) {
83 assert_eq!($checker.check(), std::arch::is_x86_feature_detected!($name));
84 } else {
85 assert!($checker.check_volatile());
86 assert!($checker.check());
87 }
88 }
89 };
90 }
91
92 write_test!(test_sha, "sha", Sha);
93 write_test!(test_avx2, "avx2", Avx2);
94 write_test!(test_avx512f, "avx512f", Avx512F);
95 write_test!(test_avx512vl, "avx512vl", Avx512VL);
96}