use std::ffi::CStr;
use std::fmt;
use thiserror::Error;
use vectorscan_rs_sys as hs;
#[derive(Debug, Error)]
pub enum Error {
#[error("Error originating from Vectorscan API: {0} (code {1})")]
Vectorscan(VectorscanErrorCode, i32),
#[error("Pattern compilation failed: {0} (index {1})")]
VectorscanCompile(String, i32),
}
#[derive(Debug, PartialEq, Eq)]
pub enum VectorscanErrorCode {
Invalid,
Nomem,
ScanTerminated,
CompileError,
DbVersionError,
DbPlatformError,
DbModeError,
BadAlign,
BadAlloc,
ScratchInUse,
ArchError,
InsufficientSpace,
UnknownError,
UnknownErrorCode,
}
impl fmt::Display for VectorscanErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Invalid => write!(f, "invalid parameter"),
Self::Nomem => write!(f, "out of memory"),
Self::ScanTerminated => write!(f, "scan terminated by callback"),
Self::CompileError => write!(f, "compilation error"),
Self::DbVersionError => write!(f, "database version mismatch"),
Self::DbPlatformError => write!(f, "database platform mismatch"),
Self::DbModeError => write!(f, "database mode mismatch"),
Self::BadAlign => write!(f, "bad alignment"),
Self::BadAlloc => write!(f, "allocator returned misaligned memory"),
Self::ScratchInUse => write!(f, "scratch space in use"),
Self::ArchError => write!(f, "unsupported CPU architecture"),
Self::InsufficientSpace => write!(f, "insufficient space"),
Self::UnknownError => write!(f, "unknown internal error"),
Self::UnknownErrorCode => write!(f, "unrecognized error code"),
}
}
}
impl From<hs::hs_error_t> for VectorscanErrorCode {
fn from(value: hs::hs_error_t) -> Self {
match value {
hs::HS_INVALID => Self::Invalid,
hs::HS_NOMEM => Self::Nomem,
hs::HS_SCAN_TERMINATED => Self::ScanTerminated,
hs::HS_COMPILER_ERROR => Self::CompileError,
hs::HS_DB_VERSION_ERROR => Self::DbVersionError,
hs::HS_DB_PLATFORM_ERROR => Self::DbPlatformError,
hs::HS_DB_MODE_ERROR => Self::DbModeError,
hs::HS_BAD_ALIGN => Self::BadAlign,
hs::HS_BAD_ALLOC => Self::BadAlloc,
hs::HS_SCRATCH_IN_USE => Self::ScratchInUse,
hs::HS_ARCH_ERROR => Self::ArchError,
hs::HS_INSUFFICIENT_SPACE => Self::InsufficientSpace,
hs::HS_UNKNOWN_ERROR => Self::UnknownError,
_ => Self::UnknownErrorCode,
}
}
}
impl From<hs::hs_error_t> for Error {
fn from(value: hs::hs_error_t) -> Self {
Self::Vectorscan(value.into(), value)
}
}
pub trait AsResult: Sized {
fn ok(self) -> Result<(), Error>;
}
impl AsResult for hs::hs_error_t {
fn ok(self) -> Result<(), Error> {
if self == hs::HS_SUCCESS as hs::hs_error_t {
Ok(())
} else {
Err(self.into())
}
}
}
pub(crate) unsafe fn extract_compile_error(compile_error: *mut hs::hs_compile_error_t) -> Error {
unsafe {
let message = if (*compile_error).message.is_null() {
"unknown compile error".to_string()
} else {
CStr::from_ptr((*compile_error).message)
.to_string_lossy()
.into_owned()
};
let expression = (*compile_error).expression;
hs::hs_free_compile_error(compile_error);
Error::VectorscanCompile(message, expression)
}
}