use crate::{error::HyperscanFlagsError, hs};
use std::{
ops,
os::raw::{c_uint, c_ulonglong},
};
pub(crate) trait BitSet:
Copy+ops::BitOr<Output=Self>+ops::BitOrAssign+ops::BitAnd<Output=Self>+ops::BitAndAssign
{
fn nonzero(&self) -> bool;
#[inline]
fn contains(&self, other: &Self) -> bool { (*self & *other).nonzero() }
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Flags(u32);
impl Flags {
pub const ALLOWEMPTY: Self = Self(hs::HS_FLAG_ALLOWEMPTY as u32);
pub const CASELESS: Self = Self(hs::HS_FLAG_CASELESS as u32);
pub const COMBINATION: Self = Self(hs::HS_FLAG_COMBINATION as u32);
pub const DOTALL: Self = Self(hs::HS_FLAG_DOTALL as u32);
pub const MULTILINE: Self = Self(hs::HS_FLAG_MULTILINE as u32);
pub const PREFILTER: Self = Self(hs::HS_FLAG_PREFILTER as u32);
pub const QUIET: Self = Self(hs::HS_FLAG_QUIET as u32);
pub const SINGLEMATCH: Self = Self(hs::HS_FLAG_SINGLEMATCH as u32);
pub const SOM_LEFTMOST: Self = Self(hs::HS_FLAG_SOM_LEFTMOST as u32);
pub const UCP: Self = Self(hs::HS_FLAG_UCP as u32);
pub const UTF8: Self = Self(hs::HS_FLAG_UTF8 as u32);
#[inline(always)]
pub(crate) const fn into_native(self) -> c_uint { self.0 as c_uint }
}
impl BitSet for Flags {
#[inline]
fn nonzero(&self) -> bool { self.0 != 0 }
}
impl ops::BitOr for Flags {
type Output = Self;
fn bitor(self, other: Self) -> Self { Self(self.0.bitor(other.0)) }
}
impl ops::BitOrAssign for Flags {
fn bitor_assign(&mut self, rhs: Self) {
use ops::BitOr;
*self = self.bitor(rhs);
}
}
impl ops::BitAnd for Flags {
type Output = Self;
fn bitand(self, other: Self) -> Self { Self(self.0.bitand(other.0)) }
}
impl ops::BitAndAssign for Flags {
fn bitand_assign(&mut self, rhs: Self) {
use ops::BitAnd;
*self = self.bitand(rhs);
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Mode(u32);
static_assertions::const_assert_eq!(hs::HS_MODE_BLOCK, hs::HS_MODE_NOSTREAM);
impl Mode {
pub const BLOCK: Self = Self(hs::HS_MODE_BLOCK as u32);
pub const NOSTREAM: Self = Self(hs::HS_MODE_NOSTREAM as u32);
pub const SOM_HORIZON_LARGE: Self = Self(hs::HS_MODE_SOM_HORIZON_LARGE);
pub const SOM_HORIZON_MEDIUM: Self = Self(hs::HS_MODE_SOM_HORIZON_MEDIUM);
pub const SOM_HORIZON_SMALL: Self = Self(hs::HS_MODE_SOM_HORIZON_SMALL);
pub const STREAM: Self = Self(hs::HS_MODE_STREAM as u32);
pub const VECTORED: Self = Self(hs::HS_MODE_VECTORED as u32);
#[inline]
fn check_db_type(&self) -> bool {
self.contains(&Self::NOSTREAM) || self.contains(&Self::STREAM) || self.contains(&Self::VECTORED)
}
#[inline]
pub fn validate_db_type(&self) -> Result<(), HyperscanFlagsError> {
if self.check_db_type() {
Ok(())
} else {
Err(HyperscanFlagsError::InvalidDbMode)
}
}
#[inline]
fn any_som_horizon_mode_was_selected(&self) -> bool {
self.contains(&Self::SOM_HORIZON_LARGE)
|| self.contains(&Self::SOM_HORIZON_MEDIUM)
|| self.contains(&Self::SOM_HORIZON_SMALL)
}
#[inline]
pub fn validate_against_flags(&self, flags: &Flags) -> Result<(), HyperscanFlagsError> {
if flags.contains(&Flags::SOM_LEFTMOST)
&& !self.any_som_horizon_mode_was_selected()
&& self.contains(&Self::STREAM)
{
Err(HyperscanFlagsError::SomHorizonModeRequired)
} else {
Ok(())
}
}
#[inline(always)]
pub(crate) const fn into_native(self) -> c_uint { self.0 as c_uint }
}
impl BitSet for Mode {
#[inline]
fn nonzero(&self) -> bool { self.0 != 0 }
}
impl ops::BitOr for Mode {
type Output = Self;
fn bitor(self, other: Self) -> Self { Self(self.0.bitor(other.0)) }
}
impl ops::BitOrAssign for Mode {
fn bitor_assign(&mut self, rhs: Self) {
use ops::BitOr;
*self = self.bitor(rhs);
}
}
impl ops::BitAnd for Mode {
type Output = Self;
fn bitand(self, other: Self) -> Self { Self(self.0.bitand(other.0)) }
}
impl ops::BitAndAssign for Mode {
fn bitand_assign(&mut self, rhs: Self) {
use ops::BitAnd;
*self = self.bitand(rhs);
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct CpuFeatures(u8);
impl CpuFeatures {
pub const AVX2: Self = Self(hs::HS_CPU_FEATURES_AVX2);
pub const AVX512: Self = Self(hs::HS_CPU_FEATURES_AVX512);
pub const AVX512VBMI: Self = Self(hs::HS_CPU_FEATURES_AVX512VBMI);
#[inline(always)]
pub(crate) const fn into_native(self) -> c_ulonglong { self.0 as c_ulonglong }
#[inline(always)]
pub(crate) const fn from_native(x: c_ulonglong) -> Self { Self(x as u8) }
}
impl BitSet for CpuFeatures {
#[inline]
fn nonzero(&self) -> bool { self.0 != 0 }
}
impl ops::BitOr for CpuFeatures {
type Output = Self;
fn bitor(self, other: Self) -> Self { Self(self.0.bitor(other.0)) }
}
impl ops::BitOrAssign for CpuFeatures {
fn bitor_assign(&mut self, rhs: Self) {
use ops::BitOr;
*self = self.bitor(rhs);
}
}
impl ops::BitAnd for CpuFeatures {
type Output = Self;
fn bitand(self, other: Self) -> Self { Self(self.0.bitand(other.0)) }
}
impl ops::BitAndAssign for CpuFeatures {
fn bitand_assign(&mut self, rhs: Self) {
use ops::BitAnd;
*self = self.bitand(rhs);
}
}
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
num_enum::FromPrimitive,
num_enum::IntoPrimitive,
)]
#[repr(u8)]
pub enum TuneFamily {
#[num_enum(default)]
Generic = hs::HS_TUNE_FAMILY_GENERIC,
SandyBridge = hs::HS_TUNE_FAMILY_SNB,
IvyBridge = hs::HS_TUNE_FAMILY_IVB,
Haswell = hs::HS_TUNE_FAMILY_HSW,
Silvermont = hs::HS_TUNE_FAMILY_SLM,
Broadwell = hs::HS_TUNE_FAMILY_BDW,
Skylake = hs::HS_TUNE_FAMILY_SKL,
SkylakeServer = hs::HS_TUNE_FAMILY_SKX,
Goldmont = hs::HS_TUNE_FAMILY_GLM,
Icelake = hs::HS_TUNE_FAMILY_ICL,
IcelakeServer = hs::HS_TUNE_FAMILY_ICX,
}
impl TuneFamily {
#[inline(always)]
pub(crate) fn into_native(self) -> c_uint {
let x: u8 = self.into();
x as c_uint
}
#[inline(always)]
pub(crate) fn from_native(x: c_uint) -> Self { (x as u8).into() }
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ScanFlags(c_uint);
impl ScanFlags {
#[inline(always)]
pub const fn from_native(x: c_uint) -> Self { Self(x) }
#[inline(always)]
pub const fn into_native(self) -> c_uint { self.0 }
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ExtFlags(u8);
impl ExtFlags {
pub const EDIT_DISTANCE: Self = Self(hs::HS_EXT_FLAG_EDIT_DISTANCE);
pub const HAMMING_DISTANCE: Self = Self(hs::HS_EXT_FLAG_HAMMING_DISTANCE);
pub const MAX_OFFSET: Self = Self(hs::HS_EXT_FLAG_MAX_OFFSET);
pub const MIN_LENGTH: Self = Self(hs::HS_EXT_FLAG_MIN_LENGTH);
pub const MIN_OFFSET: Self = Self(hs::HS_EXT_FLAG_MIN_OFFSET);
#[inline]
pub fn has_edit_distance(&self) -> bool { self.contains(&Self::EDIT_DISTANCE) }
#[inline]
pub fn has_hamming_distance(&self) -> bool { self.contains(&Self::HAMMING_DISTANCE) }
#[inline]
pub fn has_max_offset(&self) -> bool { self.contains(&Self::MAX_OFFSET) }
#[inline]
pub fn has_min_length(&self) -> bool { self.contains(&Self::MIN_LENGTH) }
#[inline]
pub fn has_min_offset(&self) -> bool { self.contains(&Self::MIN_OFFSET) }
#[inline(always)]
pub(crate) const fn into_native(self) -> c_ulonglong { self.0 as c_ulonglong }
#[inline(always)]
pub(crate) const fn from_native(x: c_ulonglong) -> Self { Self(x as u8) }
}
impl BitSet for ExtFlags {
#[inline]
fn nonzero(&self) -> bool { self.0 != 0 }
}
impl ops::BitOr for ExtFlags {
type Output = Self;
fn bitor(self, other: Self) -> Self { Self(self.0.bitor(other.0)) }
}
impl ops::BitOrAssign for ExtFlags {
fn bitor_assign(&mut self, rhs: Self) {
use ops::BitOr;
*self = self.bitor(rhs);
}
}
impl ops::BitAnd for ExtFlags {
type Output = Self;
fn bitand(self, other: Self) -> Self { Self(self.0.bitand(other.0)) }
}
impl ops::BitAndAssign for ExtFlags {
fn bitand_assign(&mut self, rhs: Self) {
use ops::BitAnd;
*self = self.bitand(rhs);
}
}