#[cfg(target_arch = "x86_64")]
pub mod x86_64;
#[cfg(target_arch = "aarch64")]
pub mod aarch64;
#[cfg(target_arch = "wasm32")]
pub mod wasm32;
pub mod detector;
use crate::core::protocol::ProtocolType;
use crate::error::{DetectorError, Result};
#[derive(Debug, Clone, PartialEq)]
pub struct SimdDetectionResult {
pub protocol: ProtocolType,
pub confidence: f32,
pub match_positions: Vec<usize>,
pub instruction_set: SimdInstructionSet,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimdInstructionSet {
None,
SSE2,
SSE41,
AVX2,
AVX512,
NEON,
WasmSimd,
}
pub trait SimdDetector: Send + Sync {
fn detect_http2(&self, data: &[u8]) -> Result<SimdDetectionResult>;
fn detect_quic(&self, data: &[u8]) -> Result<SimdDetectionResult>;
fn detect_grpc(&self, data: &[u8]) -> Result<SimdDetectionResult>;
fn detect_websocket(&self, data: &[u8]) -> Result<SimdDetectionResult>;
fn detect_tls(&self, data: &[u8]) -> Result<SimdDetectionResult>;
fn detect_multiple(&self, data: &[u8], protocols: &[ProtocolType]) -> Result<Vec<SimdDetectionResult>>;
fn instruction_set(&self) -> SimdInstructionSet;
fn supports_protocol(&self, protocol: ProtocolType) -> bool;
}
pub fn create_best_detector() -> Box<dyn SimdDetector> {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
return Box::new(x86_64::Avx512Detector::new());
} else if is_x86_feature_detected!("avx2") {
return Box::new(x86_64::Avx2Detector::new());
} else if is_x86_feature_detected!("sse2") {
return Box::new(x86_64::Sse2Detector::new());
}
}
#[cfg(target_arch = "aarch64")]
{
if std::arch::is_aarch64_feature_detected!("neon") {
return Box::new(aarch64::AArch64SimdDetector::new());
}
}
#[cfg(target_arch = "wasm32")]
{
return Box::new(wasm32::WasmSimdDetector::new());
}
Box::new(detector::GenericSimdDetector::new())
}
pub fn detect_simd_support() -> SimdInstructionSet {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
return SimdInstructionSet::AVX512;
} else if is_x86_feature_detected!("avx2") {
return SimdInstructionSet::AVX2;
} else if is_x86_feature_detected!("sse2") {
return SimdInstructionSet::SSE2;
}
}
#[cfg(target_arch = "aarch64")]
{
if std::arch::is_aarch64_feature_detected!("neon") {
return SimdInstructionSet::NEON;
}
}
#[cfg(target_arch = "wasm32")]
{
return SimdInstructionSet::WasmSimd;
}
SimdInstructionSet::None
}
pub fn simd_pattern_match(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
let detector = create_best_detector();
generic_pattern_match(haystack, needle)
}
fn generic_pattern_match(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
let mut positions = Vec::new();
if needle.is_empty() || haystack.len() < needle.len() {
return positions;
}
for i in 0..=haystack.len() - needle.len() {
if haystack[i..i + needle.len()] == *needle {
positions.push(i);
}
}
positions
}
pub fn simd_count_bytes(data: &[u8], byte: u8) -> usize {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
unsafe {
return x86_64::avx2_count_bytes(data, byte);
}
} else if is_x86_feature_detected!("sse2") {
unsafe {
return x86_64::sse2_count_bytes(data, byte);
}
}
}
data.iter().filter(|&&b| b == byte).count()
}
pub fn simd_find_byte(data: &[u8], byte: u8) -> Option<usize> {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
unsafe {
return x86_64::avx2_find_byte(data, byte);
}
} else if is_x86_feature_detected!("sse2") {
unsafe {
return x86_64::sse2_find_byte(data, byte);
}
}
}
data.iter().position(|&b| b == byte)
}