use {
libc::c_int,
pcre2_sys::{
PCRE2_ERROR_BADDATA, PCRE2_ERROR_NOMEMORY, pcre2_get_error_message_8,
},
};
#[derive(Clone)]
pub struct Error {
kind: ErrorKind,
code: c_int,
offset: Option<usize>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ErrorKind {
Compile,
JIT,
Match,
Info,
Option,
}
impl Error {
pub(crate) fn compile(code: c_int, offset: usize) -> Error {
Error { kind: ErrorKind::Compile, code, offset: Some(offset) }
}
pub(crate) fn jit(code: c_int) -> Error {
Error { kind: ErrorKind::JIT, code, offset: None }
}
pub(crate) fn matching(code: c_int) -> Error {
Error { kind: ErrorKind::Match, code, offset: None }
}
pub(crate) fn info(code: c_int) -> Error {
Error { kind: ErrorKind::Info, code, offset: None }
}
pub(crate) fn option(code: c_int) -> Error {
Error { kind: ErrorKind::Option, code, offset: None }
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn code(&self) -> c_int {
self.code
}
pub fn offset(&self) -> Option<usize> {
self.offset
}
fn error_message(&self) -> String {
let mut buf = [0u8; 240];
let rc = unsafe {
pcre2_get_error_message_8(self.code, buf.as_mut_ptr(), buf.len())
};
assert!(rc != PCRE2_ERROR_BADDATA, "used an invalid error code");
assert!(rc != PCRE2_ERROR_NOMEMORY, "buffer size too small");
assert!(rc >= 0, "expected non-negative but got {}", rc);
String::from_utf8(buf[..rc as usize].to_vec()).expect("valid UTF-8")
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
"pcre2 error"
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let msg = self.error_message();
match self.kind {
ErrorKind::Compile => match self.offset {
None => {
write!(f, "PCRE2: error compiling pattern: {}", msg)
}
Some(offset) => {
write!(
f,
"PCRE2: error compiling pattern at offset {}: {}",
offset, msg
)
}
},
ErrorKind::JIT => {
write!(f, "PCRE2: error JIT compiling pattern: {}", msg)
}
ErrorKind::Match => {
write!(f, "PCRE2: error matching: {}", msg)
}
ErrorKind::Info => {
write!(f, "PCRE2: error getting info: {}", msg)
}
ErrorKind::Option => {
write!(f, "PCRE2: error setting option: {}", msg)
}
}
}
}
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Error")
.field("kind", &self.kind)
.field("code", &self.code)
.field("offset", &self.offset)
.field("message", &self.error_message())
.finish()
}
}