use parking_lot::{ReentrantMutex, ReentrantMutexGuard};
use std::sync::{LazyLock, Mutex, OnceLock, atomic::AtomicBool};
use crate::{PdfiumError, c_api::pdfium_bindings::Pdfium, error::PdfiumResult};
static PDFIUM: OnceLock<ReentrantMutex<PdfiumResult<Box<Pdfium>>>> = OnceLock::new();
static LIBRARY_LOCATION: LazyLock<Mutex<String>> = LazyLock::new(|| Mutex::new(String::from(".")));
static SKIA_RENDERER: AtomicBool = AtomicBool::new(false);
fn load_pdfium() -> &'static ReentrantMutex<PdfiumResult<Box<Pdfium>>> {
PDFIUM.get_or_init(|| {
let directory = LIBRARY_LOCATION
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.to_string();
let use_skia = SKIA_RENDERER.load(std::sync::atomic::Ordering::Relaxed);
let pdfium = Pdfium::load_from_directory(&directory).or_else(|_| Pdfium::load());
if let Ok(pdfium) = &pdfium {
pdfium.init(use_skia);
}
ReentrantMutex::new(pdfium)
})
}
pub struct PdfiumGuard {
_guard: ReentrantMutexGuard<'static, PdfiumResult<Box<Pdfium>>>,
pdfium: *const Box<Pdfium>,
}
impl PdfiumGuard {
fn new(guard: ReentrantMutexGuard<'static, PdfiumResult<Box<Pdfium>>>) -> PdfiumResult<Self> {
match guard.as_ref() {
Ok(p) => Ok(PdfiumGuard {
pdfium: p as *const Box<Pdfium>,
_guard: guard,
}),
Err(e) => Err(match e {
PdfiumError::LibraryError(msg) => PdfiumError::LibraryError(msg.to_string()),
_ => PdfiumError::Unknown,
}),
}
}
}
impl std::ops::Deref for PdfiumGuard {
type Target = Pdfium;
fn deref(&self) -> &Self::Target {
unsafe { &(*self.pdfium) }
}
}
pub fn try_lib() -> PdfiumResult<PdfiumGuard> {
let mutex = load_pdfium();
let guard = mutex.lock();
PdfiumGuard::new(guard)
}
pub fn lib() -> PdfiumGuard {
try_lib().unwrap()
}
pub fn set_library_location(location: &str) {
let mut guard = LIBRARY_LOCATION
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
*guard = location.to_string();
}
pub fn set_use_skia(use_skia: bool) {
SKIA_RENDERER.store(use_skia, std::sync::atomic::Ordering::Relaxed);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pdfium_library_loading() {
let lib = try_lib();
assert!(lib.is_ok());
}
}