use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use crate::{MatchScope, core::cached_rule::CachedScopeRule};
use super::enums::{MatchCondition, MatchType};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Pattern {
pub pattern: String,
pub match_type: MatchType,
pub version_template: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct KeyedPattern {
pub key: String, pub pattern: Pattern, }
impl From<(String, Pattern)> for KeyedPattern {
fn from((key, pattern): (String, Pattern)) -> Self {
KeyedPattern { key, pattern }
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct MatchRuleSet {
pub condition: MatchCondition, pub list_patterns: Vec<Pattern>, pub keyed_patterns: Vec<KeyedPattern>, }
impl MatchRuleSet {
pub fn new() -> Self {
Self::default()
}
pub fn add_list_pattern(&mut self, pattern: Pattern) {
self.list_patterns.push(pattern);
}
pub fn add_keyed_pattern(&mut self, keyed_pattern: KeyedPattern) {
self.keyed_patterns.push(keyed_pattern);
}
pub fn with_condition(condition: MatchCondition) -> Self {
Self {
condition,
list_patterns: Vec::new(),
keyed_patterns: Vec::new(),
}
}
pub fn from_cached(scope: &MatchScope, cached: CachedScopeRule) -> Self {
let mut rule_set = Self::with_condition(cached.condition);
match scope {
MatchScope::Url | MatchScope::Html | MatchScope::Script | MatchScope::ScriptSrc => {
if let Some(patterns) = cached.list_patterns {
rule_set.list_patterns = patterns;
}
}
MatchScope::Header | MatchScope::Cookie | MatchScope::Meta | MatchScope::Js=> {
if let Some(keyed) = cached.keyed_patterns {
rule_set.keyed_patterns = keyed.into_iter()
.flat_map(|(k, v)| v.into_iter().map(move |p| KeyedPattern::from((k.clone(), p))))
.collect();
}
}
}
rule_set
}
pub fn to_cached(&self, scope: &MatchScope) -> CachedScopeRule {
let mut cached = CachedScopeRule {
condition: self.condition.clone(),
list_patterns: None,
keyed_patterns: None,
};
match scope {
MatchScope::Url | MatchScope::Html | MatchScope::Script | MatchScope::ScriptSrc => {
if !self.list_patterns.is_empty() {
cached.list_patterns = Some(self.list_patterns.clone());
}
}
MatchScope::Header | MatchScope::Cookie | MatchScope::Meta | MatchScope::Js => {
if !self.keyed_patterns.is_empty() {
let mut keyed: FxHashMap<String, Vec<Pattern>> = FxHashMap::default();
for kp in &self.keyed_patterns {
keyed.entry(kp.key.clone())
.or_default()
.push(kp.pattern.clone());
}
cached.keyed_patterns = Some(keyed);
}
}
}
cached
}
}