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;
pub const MULTILINE: u32 = 1 << 9;
pub const DOTALL: u32 = 1 << 10;
#[repr(C)]
pub struct Regex {
_opaque: [u8; 0],
}
#[repr(C)]
pub struct Slate {
_opaque: [u8; 0],
}
#[repr(C)]
pub struct Munch {
_opaque: [u8; 0],
}
#[repr(C)]
pub struct MunchPattern {
pub pattern: *const u8,
pub len: usize,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct MunchRefusal {
pub pattern: u32,
pub why: u32,
}
pub const MUNCH_SYNTAX: u32 = 0;
pub const MUNCH_STATES: u32 = 1;
pub const MUNCH_WORD_CONTEXT: u32 = 2;
pub const MUNCH_BUFFER_ANCHOR: u32 = 3;
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct MunchToken {
pub len: usize,
pub count: usize,
}
pub const MUNCH_LONGEST: u32 = 0;
pub const MUNCH_SHORTEST: u32 = 1;
#[repr(C)]
pub struct SlatePattern {
pub pattern: *const u8,
pub len: usize,
pub flags: u32,
}
#[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,
}
}
}
#[derive(Clone, Copy)]
#[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,
}
}
}
pub unsafe fn borrowed<'a>(text: &Text) -> &'a [u8] {
if text.ptr.is_null() || text.len == 0 {
return &[];
}
unsafe { std::slice::from_raw_parts(text.ptr, text.len) }
}
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_pattern_windows(re: *mut Regex) -> i32;
pub fn irgx_pattern_earliest(re: *mut Regex) -> i32;
pub fn irgx_is_match_in(
re: *mut Regex,
text: *const u8,
len: usize,
from: usize,
to: usize,
) -> i32;
pub fn irgx_find_all_in(
re: *mut Regex,
text: *const u8,
len: usize,
from: usize,
to: 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_slate_compile(
patterns: *const SlatePattern,
count: usize,
refused: *mut usize,
out: *mut *mut Slate,
) -> i32;
pub fn irgx_slate_free(slate: *mut Slate);
pub fn irgx_slate_is_match(slate: *mut Slate, text: *const u8, len: usize) -> i32;
pub fn irgx_slate_which(
slate: *mut Slate,
text: *const u8,
len: usize,
out: *mut u32,
cap: usize,
written: *mut usize,
) -> i32;
pub fn irgx_munch_compile(
patterns: *const MunchPattern,
count: usize,
flags: u32,
out: *mut *mut Munch,
) -> i32;
pub fn irgx_munch_free(munch: *mut Munch);
pub fn irgx_munch_len(munch: *const Munch) -> usize;
pub fn irgx_munch_declined(
munch: *const Munch,
out: *mut MunchRefusal,
cap: usize,
written: *mut usize,
) -> i32;
pub fn irgx_munch_scan(
munch: *mut Munch,
text: *const u8,
len: usize,
at: usize,
allow: *const u32,
nallow: usize,
pick: u32,
tok: *mut MunchToken,
out: *mut u32,
cap: 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,
})
}