scrypt_opt/
features.rs

1/// A feature that can be checked at runtime.
2pub trait Feature {
3    /// The name of the feature.
4    fn name(&self) -> &'static str;
5
6    /// Whether the feature is required for the crate to work.
7    fn required(&self) -> bool;
8
9    /// The length of the vector in bytes.
10    fn vector_length(&self) -> usize;
11
12    /// Checks if the feature is supported.
13    fn check(&self) -> bool {
14        if self.required() {
15            return true;
16        }
17
18        self.check_volatile()
19    }
20
21    /// Checks if the feature is supported at runtime.
22    fn check_volatile(&self) -> bool;
23}
24
25/// Iterates over all features.
26#[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(&Avx2);
31        f(&Avx512F);
32        f(&Avx512VL);
33    }
34}
35
36macro_rules! define_x86_feature {
37    ($name:ident, $cpuid_name:ident, $feature:tt) => {
38        #[cfg(target_arch = "x86_64")]
39        cpufeatures::new!($cpuid_name, $feature);
40
41        #[cfg(target_arch = "x86_64")]
42        #[derive(Default)]
43        #[doc = concat!("X86 ", stringify!($feature), " feature.")]
44        pub struct $name;
45
46        #[cfg(target_arch = "x86_64")]
47        impl Feature for $name {
48            fn name(&self) -> &'static str {
49                stringify!($feature)
50            }
51
52            fn required(&self) -> bool {
53                cfg!(target_feature = $feature)
54            }
55
56            fn vector_length(&self) -> usize {
57                32
58            }
59
60            fn check_volatile(&self) -> bool {
61                $cpuid_name::get()
62            }
63        }
64    };
65}
66
67define_x86_feature!(Avx2, cpuid_avx2, "avx2");
68define_x86_feature!(Avx512F, cpuid_avx512f, "avx512f");
69define_x86_feature!(Avx512VL, cpuid_avx512vl, "avx512vl");
70
71#[cfg(test)]
72mod tests {
73    #[cfg_attr(not(target_arch = "x86_64"), expect(unused_imports))]
74    use super::*;
75
76    #[test]
77    #[cfg(target_arch = "x86_64")]
78    fn test_avx2() {
79        if !cfg!(target_feature = "avx2") {
80            assert_eq!(Avx2.check(), std::arch::is_x86_feature_detected!("avx2"));
81        } else {
82            assert!(Avx2.check());
83        }
84    }
85
86    #[test]
87    #[cfg(target_arch = "x86_64")]
88    fn test_avx512f() {
89        if !cfg!(target_feature = "avx512f") {
90            assert_eq!(
91                Avx512F.check(),
92                std::arch::is_x86_feature_detected!("avx512f")
93            );
94        } else {
95            assert!(Avx512F.check());
96        }
97    }
98
99    #[test]
100    #[cfg(target_arch = "x86_64")]
101    fn test_avx512vl() {
102        if !cfg!(target_feature = "avx512vl") {
103            assert_eq!(
104                Avx512VL.check(),
105                std::arch::is_x86_feature_detected!("avx512vl")
106            );
107        } else {
108            assert!(Avx512VL.check());
109        }
110    }
111}