use std::cmp::Ordering;
use super::ac_scan::AcResult;
use super::Params;
use crate::compiler::variable::Variable;
#[derive(Debug)]
pub(crate) struct VariableEvaluation<'a> {
pub(crate) var: &'a Variable,
params: Params,
pub(crate) matches: Vec<Match>,
next_offset: Option<usize>,
has_been_found: bool,
}
pub type Match = std::ops::Range<usize>;
impl<'a> VariableEvaluation<'a> {
pub fn new(var: &'a Variable, params: Params, ac_result: AcResult) -> Self {
let mut this = Self {
var,
params,
matches: Vec::new(),
next_offset: Some(0),
has_been_found: false,
};
match ac_result {
AcResult::Unknown => this,
AcResult::NotFound => {
this.next_offset = None;
this
}
AcResult::Matches(matches) => {
this.matches = matches;
this.next_offset = None;
this.has_been_found = !this.matches.is_empty();
this
}
}
}
pub fn find(&mut self, mem: &[u8]) -> bool {
if self.has_been_found || !self.matches.is_empty() {
true
} else {
self.get_next_match(mem).is_some()
}
}
pub fn find_match_occurence(&mut self, mem: &[u8], occurence_number: usize) -> Option<Match> {
while self.matches.len() <= occurence_number {
let _r = self.get_next_match(mem)?;
}
self.matches.get(occurence_number).cloned()
}
pub fn count_matches(&mut self, mem: &[u8]) -> u64 {
loop {
if self.get_next_match(mem).is_none() {
break;
}
}
self.matches.len() as u64
}
pub fn count_matches_in(&mut self, mem: &[u8], from: usize, to: usize) -> u64 {
if from >= mem.len() {
return 0;
}
let mut count = 0;
for mat in &self.matches {
if mat.start > to {
return count;
} else if mat.start >= from {
count += 1;
}
}
while let Some(mat) = self.get_next_match(mem) {
if mat.start > to {
return count;
} else if mat.start >= from {
count += 1;
}
}
count
}
pub fn find_at(&mut self, mem: &[u8], offset: usize) -> bool {
if offset >= mem.len() {
return false;
}
for mat in &self.matches {
match mat.start.cmp(&offset) {
Ordering::Less => (),
Ordering::Equal => return true,
Ordering::Greater => return false,
}
}
while let Some(mat) = self.get_next_match(mem) {
match mat.start.cmp(&offset) {
Ordering::Less => (),
Ordering::Equal => return true,
Ordering::Greater => return false,
}
}
false
}
pub fn find_in(&mut self, mem: &[u8], from: usize, to: usize) -> bool {
if from >= mem.len() {
return false;
}
for mat in &self.matches {
if mat.start > to {
return false;
} else if mat.start >= from {
return true;
}
}
while let Some(mat) = self.get_next_match(mem) {
if mat.start > to {
return false;
} else if mat.start >= from {
return true;
}
}
false
}
pub fn compute_all_matches(&mut self, mem: &[u8]) {
while self.get_next_match(mem).is_some() {}
}
fn get_next_match(&mut self, mem: &[u8]) -> Option<Match> {
if self.matches.len() >= self.params.string_max_nb_matches {
return None;
}
let offset = match self.next_offset {
None => return None,
Some(v) => v,
};
let mat = self.var.find_next_match_at(mem, offset);
match &mat {
None => {
self.next_offset = None;
}
Some(mat) => {
self.matches.push(mat.clone());
if mat.start + 1 < mem.len() {
self.next_offset = Some(mat.start + 1);
} else {
self.next_offset = None;
}
}
}
mat
}
}
#[cfg(test)]
mod tests {
use boreal_parser::{VariableDeclaration, VariableDeclarationValue, VariableModifiers};
use crate::compiler::variable::compile_variable;
use crate::test_helpers::test_type_traits_non_clonable;
use super::*;
#[test]
fn test_types_traits() {
test_type_traits_non_clonable(VariableEvaluation {
var: &compile_variable(VariableDeclaration {
name: "a".to_owned(),
value: VariableDeclarationValue::Bytes(Vec::new()),
modifiers: VariableModifiers::default(),
span: 0..1,
})
.unwrap(),
params: Params {
string_max_nb_matches: 100,
},
matches: Vec::new(),
next_offset: None,
has_been_found: false,
});
}
}