use std::ffi::{CStr, c_char};
use std::sync::LazyLock;
pub const ABI_VERSION: u32 = 2;
pub const MATCH: i32 = 1;
pub const STALE: i32 = -1;
pub const OOM: i32 = -2;
pub const INVALID: i32 = -4;
pub const AT_NONE: i32 = 0;
pub const AT_FILE: i32 = 1;
pub const AT_PATTERN: i32 = 2;
pub const FIXED: u32 = 1 << 0;
pub const IGNORE_CASE: u32 = 1 << 1;
pub const WORD: u32 = 1 << 2;
pub const SMART_CASE: u32 = 1 << 5;
pub const NO_UNICODE: u32 = 1 << 6;
pub const PCRE: u32 = 1 << 8;
#[repr(C)]
pub struct Regex {
_opaque: [u8; 0],
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(C)]
pub struct Span {
pub start: i64,
pub end: i64,
}
impl Span {
pub fn range(self) -> Option<(usize, usize)> {
if self.start < 0 || self.end < 0 {
return None;
}
Some((self.start as usize, self.end as usize))
}
}
#[repr(C)]
pub struct Fault {
pub struct_size: u32,
pub status: i32,
pub at_space: i32,
pub name: *const c_char,
pub path: *const u8,
pub path_len: usize,
pub at: u64,
}
impl Default for Fault {
fn default() -> Self {
Self {
struct_size: size_of::<Self>() as u32,
status: 0,
at_space: AT_NONE,
name: std::ptr::null(),
path: std::ptr::null(),
path_len: 0,
at: 0,
}
}
}
#[repr(C)]
pub struct Text {
pub ptr: *const u8,
pub len: usize,
}
impl Default for Text {
fn default() -> Self {
Self {
ptr: std::ptr::null(),
len: 0,
}
}
}
unsafe extern "C" {
pub fn irgx_abi_version() -> u32;
pub fn irgx_version() -> *const c_char;
pub fn irgx_pcre2_version() -> *const c_char;
pub fn irgx_status_message(code: i32) -> *const c_char;
pub fn irgx_last_fault(out: *mut Fault) -> i32;
pub fn irgx_compile(pattern: *const u8, len: usize, flags: u32, out: *mut *mut Regex) -> i32;
pub fn irgx_free(re: *mut Regex);
pub fn irgx_is_match(re: *mut Regex, text: *const u8, len: usize) -> i32;
pub fn irgx_find_all(
re: *mut Regex,
text: *const u8,
len: usize,
out: *mut Span,
cap: usize,
written: *mut usize,
) -> i32;
pub fn irgx_captures(
re: *mut Regex,
text: *const u8,
len: usize,
from: usize,
out: *mut Span,
cap: usize,
written: *mut usize,
) -> i32;
pub fn irgx_group_count(re: *mut Regex, out: *mut u32) -> i32;
pub fn irgx_group_name(re: *mut Regex, index: u32, out: *mut Text) -> i32;
}
fn borrow(raw: *const c_char) -> &'static str {
if raw.is_null() {
return "";
}
unsafe { CStr::from_ptr(raw) }.to_str().unwrap_or("")
}
pub fn engine_version() -> &'static str {
borrow(unsafe { irgx_version() })
}
pub fn pcre2_version() -> &'static str {
borrow(unsafe { irgx_pcre2_version() })
}
pub fn status_message(code: i32) -> &'static str {
borrow(unsafe { irgx_status_message(code) })
}
static LINKED_ABI: LazyLock<u32> = LazyLock::new(|| {
unsafe { irgx_abi_version() }
});
pub fn abi_ok() -> Result<(), crate::Error> {
let found = *LINKED_ABI;
if found == ABI_VERSION {
return Ok(());
}
Err(crate::Error::Abi {
expected: ABI_VERSION,
found,
})
}