use std::ffi::NulError;
use std::fmt;
use std::io;
use std::num::TryFromIntError;
use std::ptr::NonNull;
use mupdf_sys::*;
#[derive(Debug, Clone)]
pub struct MuPdfError {
pub code: i32,
pub message: String,
}
impl fmt::Display for MuPdfError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"MuPDF error, code: {}, message: {}",
self.code, &self.message
)
}
}
impl std::error::Error for MuPdfError {}
pub unsafe fn ffi_error(ptr: NonNull<mupdf_error_t>) -> MuPdfError {
use std::ffi::CStr;
let err = unsafe { *ptr.as_ptr() };
let code = err.type_;
let c_msg = err.message;
let c_str = unsafe { CStr::from_ptr(c_msg) };
let message = c_str.to_string_lossy().to_string();
unsafe { mupdf_drop_error(ptr.as_ptr()) };
MuPdfError { code, message }
}
macro_rules! ffi_try {
($func:ident($($arg:expr),+)) => ({
use std::ptr;
let mut err = ptr::null_mut();
let res = $func($($arg),+, (&mut err) as *mut *mut ::mupdf_sys::mupdf_error_t);
::core::ptr::NonNull::new(err)
.map_or(Ok(res), |err| Err(
// SAFETY: We're trusting the FFI call to provide us with a valid ptr if it is not
// null.
$crate::Error::MuPdf($crate::ffi_error(err))
))
});
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Io(io::Error),
InvalidLanguage(String),
InvalidPdfDocument,
MuPdf(MuPdfError),
Nul(NulError),
IntConversion(TryFromIntError),
InvalidUtf8,
UnexpectedNullPtr,
UnknownEnumVariant,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Io(err) => err.fmt(f),
Error::InvalidLanguage(lang) => write!(f, "invalid language {lang}"),
Error::InvalidPdfDocument => write!(f, "invalid pdf document"),
Error::MuPdf(err) => err.fmt(f),
Error::Nul(err) => err.fmt(f),
Error::IntConversion(err) => err.fmt(f),
Error::InvalidUtf8 => f.write_str("string contained invalid utf-8"),
Error::UnexpectedNullPtr => write!(
f,
"An FFI function call returned a null ptr when we expected a non-null ptr"
),
Error::UnknownEnumVariant => write!(f, "unknown enum variant provided"),
}
}
}
impl std::error::Error for Error {}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::Io(err)
}
}
impl From<MuPdfError> for Error {
fn from(err: MuPdfError) -> Self {
Self::MuPdf(err)
}
}
impl From<NulError> for Error {
fn from(err: NulError) -> Self {
Self::Nul(err)
}
}
impl From<TryFromIntError> for Error {
fn from(value: TryFromIntError) -> Self {
Self::IntConversion(value)
}
}