vsec 0.0.1

Detect secrets and in Rust codebases
Documentation
//! Runtime CPU feature detection for SIMD dispatch.
//!
//! This module provides runtime detection of CPU SIMD capabilities
//! and caches the results for efficient dispatch.

/// SIMD instruction set level available on the current CPU.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimdLevel {
    /// No SIMD support, use scalar fallback
    Scalar,
    /// SSE4.2 available (128-bit vectors) - x86_64 only
    Sse42,
    /// AVX2 available (256-bit vectors) - x86_64 only
    Avx2,
    /// AVX-512 available (512-bit vectors) - x86_64 only
    Avx512,
    /// ARM NEON available (128-bit vectors) - aarch64 only
    Neon,
}

/// Detected CPU features for SIMD dispatch.
#[derive(Debug, Clone, Copy)]
pub struct CpuFeatures {
    /// Highest SIMD level available
    pub level: SimdLevel,
    /// AVX2 support (256-bit integer operations)
    pub has_avx2: bool,
    /// AVX-512F support (foundation)
    pub has_avx512f: bool,
    /// AVX-512BW support (byte/word operations)
    pub has_avx512bw: bool,
    /// SSE4.2 support
    pub has_sse42: bool,
    /// ARM NEON support
    pub has_neon: bool,
}

impl CpuFeatures {
    /// Detect CPU features at runtime.
    #[inline]
    pub fn detect() -> Self {
        #[cfg(target_arch = "x86_64")]
        {
            let has_avx512f = is_x86_feature_detected!("avx512f");
            let has_avx512bw = is_x86_feature_detected!("avx512bw");
            let has_avx2 = is_x86_feature_detected!("avx2");
            let has_sse42 = is_x86_feature_detected!("sse4.2");

            let level = if has_avx512bw && has_avx512f {
                SimdLevel::Avx512
            } else if has_avx2 {
                SimdLevel::Avx2
            } else if has_sse42 {
                SimdLevel::Sse42
            } else {
                SimdLevel::Scalar
            };

            Self {
                level,
                has_avx2,
                has_avx512f,
                has_avx512bw,
                has_sse42,
                has_neon: false,
            }
        }

        #[cfg(target_arch = "aarch64")]
        {
            // NEON is mandatory on AArch64, but we still check for consistency
            let has_neon = std::arch::is_aarch64_feature_detected!("neon");

            Self {
                level: if has_neon {
                    SimdLevel::Neon
                } else {
                    SimdLevel::Scalar
                },
                has_avx2: false,
                has_avx512f: false,
                has_avx512bw: false,
                has_sse42: false,
                has_neon,
            }
        }

        #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
        {
            Self {
                level: SimdLevel::Scalar,
                has_avx2: false,
                has_avx512f: false,
                has_avx512bw: false,
                has_sse42: false,
                has_neon: false,
            }
        }
    }
}

// Cached CPU features - detected once per thread
thread_local! {
    static CPU_FEATURES: CpuFeatures = CpuFeatures::detect();
}

/// Get the detected CPU features (cached per-thread for fast access).
#[inline]
pub fn cpu_features() -> CpuFeatures {
    CPU_FEATURES.with(|f| *f)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_detect_features() {
        let features = CpuFeatures::detect();
        // Should always succeed and return a valid level
        assert!(matches!(
            features.level,
            SimdLevel::Scalar
                | SimdLevel::Sse42
                | SimdLevel::Avx2
                | SimdLevel::Avx512
                | SimdLevel::Neon
        ));
    }

    #[test]
    fn test_cpu_features_cached() {
        let f1 = cpu_features();
        let f2 = cpu_features();
        // Same thread should get same features
        assert_eq!(f1.level, f2.level);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn test_x86_features_consistent() {
        let features = cpu_features();
        // AVX-512 implies AVX2
        if features.has_avx512bw {
            assert!(features.has_avx2);
        }
        // AVX2 implies SSE4.2
        if features.has_avx2 {
            assert!(features.has_sse42);
        }
    }

    #[test]
    #[cfg(target_arch = "aarch64")]
    fn test_aarch64_has_neon() {
        let features = cpu_features();
        // NEON is mandatory on AArch64
        assert!(features.has_neon);
        assert_eq!(features.level, SimdLevel::Neon);
    }
}