use std::sync::Arc;
use crate::rule::builder;
use vyre_foundation::extension::RuleConditionExt;
use vyre_foundation::ir::{BufferDecl, Program};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum RuleCondition {
PatternExists {
pattern_id: u32,
},
PatternCountGt {
pattern_id: u32,
threshold: u32,
},
PatternCountGte {
pattern_id: u32,
threshold: u32,
},
FileSizeLt(u64),
FileSizeLte(u64),
FileSizeGt(u64),
FileSizeGte(u64),
FileSizeEq(u64),
FileSizeNe(u64),
LiteralTrue,
LiteralFalse,
RegexMatch {
field: Arc<str>,
pattern: Arc<str>,
},
SubstringMatch {
haystack: Arc<str>,
needle: Arc<str>,
},
PrefixMatch {
value: Arc<str>,
prefix: Arc<str>,
},
SuffixMatch {
value: Arc<str>,
suffix: Arc<str>,
},
RangeMatch {
value: u64,
min: u64,
max: u64,
},
SetMembership {
value: Arc<str>,
set: smallvec::SmallVec<[Arc<str>; 4]>,
},
FieldInSet {
field: Arc<str>,
set: smallvec::SmallVec<[Arc<str>; 4]>,
},
Opaque(Arc<dyn RuleConditionExt>),
}
impl PartialEq for RuleCondition {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::PatternExists { pattern_id: a }, Self::PatternExists { pattern_id: b }) => {
a == b
}
(
Self::PatternCountGt {
pattern_id: a,
threshold: ta,
},
Self::PatternCountGt {
pattern_id: b,
threshold: tb,
},
) => a == b && ta == tb,
(
Self::PatternCountGte {
pattern_id: a,
threshold: ta,
},
Self::PatternCountGte {
pattern_id: b,
threshold: tb,
},
) => a == b && ta == tb,
(Self::FileSizeLt(a), Self::FileSizeLt(b)) => a == b,
(Self::FileSizeLte(a), Self::FileSizeLte(b)) => a == b,
(Self::FileSizeGt(a), Self::FileSizeGt(b)) => a == b,
(Self::FileSizeGte(a), Self::FileSizeGte(b)) => a == b,
(Self::FileSizeEq(a), Self::FileSizeEq(b)) => a == b,
(Self::FileSizeNe(a), Self::FileSizeNe(b)) => a == b,
(Self::LiteralTrue, Self::LiteralTrue) => true,
(Self::LiteralFalse, Self::LiteralFalse) => true,
(
Self::RegexMatch {
field: af,
pattern: ap,
},
Self::RegexMatch {
field: bf,
pattern: bp,
},
) => af == bf && ap == bp,
(
Self::SubstringMatch {
haystack: ah,
needle: an,
},
Self::SubstringMatch {
haystack: bh,
needle: bn,
},
) => ah == bh && an == bn,
(
Self::PrefixMatch {
value: av,
prefix: ap,
},
Self::PrefixMatch {
value: bv,
prefix: bp,
},
) => av == bv && ap == bp,
(
Self::SuffixMatch {
value: av,
suffix: as_,
},
Self::SuffixMatch {
value: bv,
suffix: bs,
},
) => av == bv && as_ == bs,
(
Self::RangeMatch {
value: av,
min: amin,
max: amax,
},
Self::RangeMatch {
value: bv,
min: bmin,
max: bmax,
},
) => av == bv && amin == bmin && amax == bmax,
(
Self::SetMembership {
value: av,
set: aset,
},
Self::SetMembership {
value: bv,
set: bset,
},
) => av == bv && aset == bset,
(
Self::FieldInSet {
field: af,
set: aset,
},
Self::FieldInSet {
field: bf,
set: bset,
},
) => af == bf && aset == bset,
(Self::Opaque(a), Self::Opaque(b)) => a.extension_id() == b.extension_id(),
_ => false,
}
}
}
impl Eq for RuleCondition {}
impl RuleCondition {
#[must_use]
pub fn required_extension_buffers(&self) -> Vec<BufferDecl> {
match self {
Self::Opaque(ext) => ext.required_buffers(),
_ => Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum RuleFormula {
Condition(RuleCondition),
And(Box<RuleFormula>, Box<RuleFormula>),
Or(Box<RuleFormula>, Box<RuleFormula>),
Not(Box<RuleFormula>),
}
impl RuleFormula {
#[must_use]
pub fn condition(condition: RuleCondition) -> Self {
Self::Condition(condition)
}
#[must_use]
pub fn and(left: Self, right: Self) -> Self {
Self::And(Box::new(left), Box::new(right))
}
#[must_use]
pub fn or(left: Self, right: Self) -> Self {
Self::Or(Box::new(left), Box::new(right))
}
#[must_use]
pub fn not_formula(formula: Self) -> Self {
Self::Not(Box::new(formula))
}
#[must_use]
#[allow(clippy::should_implement_trait)]
pub fn not(formula: Self) -> Self {
Self::not_formula(formula)
}
#[must_use]
pub fn to_program(&self) -> Result<Program, builder::RuleBuildError> {
builder::build_rule_program(&[(self.clone(), 0)])
}
pub fn try_to_program(&self) -> Result<Program, builder::RuleBuildError> {
self.to_program()
}
}