use crate::bytecode::Program;
use crate::pattern::{
CompiledPattern, PatternMapping, RuleEntry, RuleMatch, MAX_CACHED_POSITIONS, MAX_RULE_STRINGS,
};
#[derive(Debug, Clone, Copy)]
pub struct IndexConfig {
pub max_strings: usize,
pub max_positions: usize,
}
impl IndexConfig {
pub fn fingerprint_tier() -> Self { Self { max_strings: 8, max_positions: 1 } }
pub fn behavioral_tier() -> Self { Self { max_strings: 32, max_positions: 16 } }
pub fn forensic_tier() -> Self { Self { max_strings: 256, max_positions: 256 } }
}
#[derive(Debug, Clone)]
pub struct CompiledRuleIndex {
pub(crate) rules: Vec<RuleEntry>,
pub(crate) patterns: Vec<CompiledPattern>,
pub(crate) mapping: PatternMapping,
pub(crate) programs: Vec<Program>,
pub(crate) pattern_set: warpstate::PatternSet,
pub(crate) max_cached_positions: usize,
pub(crate) max_strings_per_rule: usize,
}
impl CompiledRuleIndex {
pub fn build(
rules: Vec<RuleEntry>,
patterns: Vec<CompiledPattern>,
mapping: PatternMapping,
programs: Vec<Program>,
pattern_set: warpstate::PatternSet,
) -> Self {
debug_assert_eq!(
programs.len(),
rules.len(),
"CompiledRuleIndex requires one program per rule"
);
for (i, program) in programs.iter().enumerate() {
debug_assert!(
program.validate().is_ok(),
"program {i} failed validation: {:?}",
program.validate().err()
);
}
Self {
rules,
patterns,
mapping,
programs,
pattern_set,
max_cached_positions: MAX_CACHED_POSITIONS,
max_strings_per_rule: MAX_RULE_STRINGS,
}
}
pub fn with_config(mut self, config: IndexConfig) -> Self {
self.max_cached_positions = config.max_positions;
self.max_strings_per_rule = config.max_strings;
self
}
pub fn max_cached_positions(&self) -> usize { self.max_cached_positions }
pub fn max_strings_per_rule(&self) -> usize { self.max_strings_per_rule }
pub fn rule_count(&self) -> usize { self.rules.len() }
pub fn rules(&self) -> &[RuleEntry] { &self.rules }
pub fn patterns(&self) -> &[CompiledPattern] { &self.patterns }
pub fn mapping(&self) -> &PatternMapping { &self.mapping }
pub fn programs(&self) -> &[Program] { &self.programs }
pub fn pattern_set(&self) -> &warpstate::PatternSet { &self.pattern_set }
pub(crate) fn materialize_matches(&self, hits: &[bool]) -> Vec<RuleMatch> {
hits.iter()
.enumerate()
.filter(|(_, hit)| **hit)
.map(|(rule_id, _)| RuleMatch {
rule_name: self.rules[rule_id].name.clone(),
tags: self.rules[rule_id].tags.clone(),
})
.collect()
}
}