use std::ffi::{CString, c_char};
use std::ptr;
use vectorscan_rs_sys as hs;
use crate::vectorscan::error::{AsResult, Error, extract_compile_error};
pub trait VectorscanDatabase: Send + Sync + std::fmt::Debug {
fn as_ptr(&self) -> *mut hs::hs_database_t;
}
#[derive(Debug)]
pub struct LiteralDatabase {
db: *mut hs::hs_database_t,
}
unsafe impl Send for LiteralDatabase {}
unsafe impl Sync for LiteralDatabase {}
impl LiteralDatabase {
pub fn new(patterns: &[&str], flags: &[u32]) -> Result<Self, Error> {
debug_assert_eq!(patterns.len(), flags.len());
let patterns_ptr: Vec<*const c_char> = patterns
.iter()
.map(|s| s.as_ptr() as *const c_char)
.collect();
let patterns_len: Vec<usize> = patterns.iter().map(|s| s.len()).collect();
let ids: Vec<u32> = (0..patterns.len() as u32).collect();
let mut db: *mut hs::hs_database_t = ptr::null_mut();
let mut compile_error: *mut hs::hs_compile_error_t = ptr::null_mut();
unsafe {
let status = hs::hs_compile_lit_multi(
patterns_ptr.as_ptr(),
flags.as_ptr(),
ids.as_ptr(),
patterns_len.as_ptr(),
patterns.len() as u32,
hs::HS_MODE_BLOCK,
ptr::null_mut(),
&mut db,
&mut compile_error,
);
if status != hs::HS_SUCCESS as i32 {
return if !compile_error.is_null() {
Err(extract_compile_error(compile_error))
} else {
status.ok().map(|_| unreachable!())
};
}
}
Ok(LiteralDatabase { db })
}
}
impl VectorscanDatabase for LiteralDatabase {
fn as_ptr(&self) -> *mut hs::hs_database_t {
self.db
}
}
impl Drop for LiteralDatabase {
fn drop(&mut self) {
unsafe {
hs::hs_free_database(self.db);
}
}
}
#[derive(Debug)]
pub struct RegexDatabase {
db: *mut hs::hs_database_t,
}
unsafe impl Send for RegexDatabase {}
unsafe impl Sync for RegexDatabase {}
impl RegexDatabase {
pub fn new(patterns: &[&str], flags: &[u32]) -> Result<Self, Error> {
debug_assert_eq!(patterns.len(), flags.len());
let c_patterns: Vec<CString> = patterns
.iter()
.map(|s| CString::new(*s).expect("pattern must not contain NUL bytes"))
.collect();
let c_pattern_ptrs: Vec<*const c_char> = c_patterns.iter().map(|cs| cs.as_ptr()).collect();
let ids: Vec<u32> = (0..patterns.len() as u32).collect();
let mut db: *mut hs::hs_database_t = ptr::null_mut();
let mut compile_error: *mut hs::hs_compile_error_t = ptr::null_mut();
unsafe {
let status = hs::hs_compile_multi(
c_pattern_ptrs.as_ptr(),
flags.as_ptr(),
ids.as_ptr(),
patterns.len() as u32,
hs::HS_MODE_BLOCK,
ptr::null_mut(),
&mut db,
&mut compile_error,
);
if status != hs::HS_SUCCESS as i32 {
return if !compile_error.is_null() {
Err(extract_compile_error(compile_error))
} else {
status.ok().map(|_| unreachable!())
};
}
}
Ok(RegexDatabase { db })
}
}
impl VectorscanDatabase for RegexDatabase {
fn as_ptr(&self) -> *mut hs::hs_database_t {
self.db
}
}
impl Drop for RegexDatabase {
fn drop(&mut self) {
unsafe {
hs::hs_free_database(self.db);
}
}
}