use std::ffi::{c_char, c_void};
use std::sync::Arc;
use vectorscan_rs_sys as hs;
use crate::vectorscan::database::{LiteralDatabase, RegexDatabase, VectorscanDatabase};
use crate::vectorscan::error::{AsResult, Error};
#[cfg(target_os = "macos")]
use crate::vectorscan::init_allocator;
use crate::vectorscan::scratch::Scratch;
#[derive(Debug, Clone)]
pub struct VectorscanScanner {
db: Arc<dyn VectorscanDatabase>,
scratch: Scratch,
}
impl VectorscanScanner {
pub fn new(db: Arc<dyn VectorscanDatabase>) -> Result<Self, Error> {
#[cfg(target_os = "macos")]
init_allocator();
let scratch = unsafe { Scratch::new(db.as_ptr())? };
Ok(Self { db, scratch })
}
pub fn new_literal(patterns: &[&str], flags: &[u32]) -> Result<Self, Error> {
let db = Arc::new(LiteralDatabase::new(patterns, flags)?);
Self::new(db)
}
pub fn new_regex(patterns: &[&str], flags: &[u32]) -> Result<Self, Error> {
let db = Arc::new(RegexDatabase::new(patterns, flags)?);
Self::new(db)
}
pub fn scan<F>(&self, haystack: &[u8], mut on_match: F) -> Result<(), Error>
where
F: FnMut(usize),
{
let scratch = self.scratch.try_clone()?;
let ctx = &mut on_match as *mut F as *mut c_void;
unsafe {
let status = hs::hs_scan(
self.db.as_ptr(),
haystack.as_ptr() as *const c_char,
haystack.len() as u32,
0,
scratch.as_ptr(),
Some(match_callback::<F>),
ctx,
);
status.ok()
}
}
}
extern "C" fn match_callback<F>(id: u32, _from: u64, _to: u64, _flags: u32, ctx: *mut c_void) -> i32
where
F: FnMut(usize),
{
let on_match = unsafe { &mut *(ctx as *mut F) };
on_match(id as usize);
0
}