#![allow(clippy::not_unsafe_ptr_arg_deref)]
pub mod annot;
pub mod archive;
pub mod band_writer;
pub mod barcode;
pub mod bidi;
pub mod bitmap;
pub mod buffer;
pub mod buffered_io;
pub mod cbz;
pub mod color;
pub mod colorspace;
pub mod compat;
pub mod compress;
pub mod context;
pub mod convenience;
pub mod cookie;
pub mod cpdf;
pub mod data_locality;
pub mod deskew;
pub mod device;
pub mod display_list;
pub mod document;
pub mod draw_device;
pub mod enhanced;
pub mod epub;
pub mod ffi_safety;
pub mod filter;
pub mod font;
pub mod font_info;
pub mod form;
pub mod geometry;
pub mod glyph;
pub mod glyph_cache;
pub mod gpu;
pub mod hashmap_util;
pub mod heap;
pub mod hints;
pub mod hyphen;
pub mod image;
pub mod image_ops;
pub mod json;
pub mod link;
pub mod lockfree;
pub mod log;
pub mod memory_profiler;
pub mod mmap;
pub mod ocr;
pub mod office;
pub mod outline;
pub mod output;
pub mod path;
pub mod pdf_3d;
pub mod pdf_clean;
pub mod pdf_cmap;
pub mod pdf_conformance;
pub mod pdf_event;
pub mod pdf_font;
pub mod pdf_image_rewriter;
pub mod pdf_interpret;
pub mod pdf_javascript;
pub mod pdf_layer;
pub mod pdf_name_table;
mod pdf_native_conversion;
pub mod pdf_object;
pub mod pdf_page;
pub mod pdf_parse;
pub mod pdf_portfolio;
pub mod pdf_recolor;
pub mod pdf_redact;
pub mod pdf_resource;
pub mod pdf_signature;
pub mod pdf_writer;
pub mod pdf_xref;
pub mod pdf_zugferd;
pub mod pixmap;
pub mod pool;
pub mod separation;
pub mod shade;
pub mod simd_util;
pub mod stext;
pub mod store;
pub mod story;
pub mod stream;
pub mod string_util;
pub mod struct_layout;
pub mod svg;
pub mod table_detect;
pub mod text;
pub mod tile_render;
pub mod transition;
pub mod tree;
pub mod util;
pub mod write_pixmap;
pub mod writer;
pub mod xml;
pub mod xps;
mod safe_helpers;
use std::collections::HashMap;
use std::sync::{
Arc, Mutex,
atomic::{AtomicU64, Ordering},
};
static HANDLE_COUNTER: AtomicU64 = AtomicU64::new(1);
pub type Handle = u64;
pub fn new_handle() -> Handle {
HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst)
}
#[derive(Debug, Default, Clone, Copy)]
pub struct HandleStoreStats {
pub total_created: u64,
pub total_destroyed: u64,
pub current_count: u64,
pub peak_count: u64,
}
pub struct HandleStore<T> {
store: Mutex<HashMap<Handle, Arc<Mutex<T>>>>,
stats: Mutex<HandleStoreStats>,
}
impl<T> HandleStore<T> {
pub fn new() -> Self {
Self {
store: Mutex::new(HashMap::new()),
stats: Mutex::new(HandleStoreStats::default()),
}
}
#[must_use = "handle must be stored and later passed to remove() to avoid resource leaks"]
pub fn insert(&self, value: T) -> Handle {
let handle = new_handle();
let mut store = self.store.lock().unwrap();
store.insert(handle, Arc::new(Mutex::new(value)));
if let Ok(mut stats) = self.stats.lock() {
stats.total_created += 1;
stats.current_count += 1;
if stats.current_count > stats.peak_count {
stats.peak_count = stats.current_count;
}
}
handle
}
pub fn get(&self, handle: Handle) -> Option<Arc<Mutex<T>>> {
let store = self.store.lock().unwrap();
store.get(&handle).cloned()
}
pub fn remove(&self, handle: Handle) -> Option<Arc<Mutex<T>>> {
let mut store = self.store.lock().unwrap();
let result = store.remove(&handle);
if result.is_some() {
if let Ok(mut stats) = self.stats.lock() {
stats.total_destroyed += 1;
stats.current_count = stats.current_count.saturating_sub(1);
}
}
result
}
#[must_use = "returned handle should be used or the keep call is unnecessary"]
pub fn keep(&self, handle: Handle) -> Handle {
handle
}
pub fn stats(&self) -> HandleStoreStats {
self.stats.lock().map(|s| *s).unwrap_or_default()
}
pub fn len(&self) -> usize {
self.store.lock().map(|s| s.len()).unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get_live_handles(&self) -> Vec<Handle> {
self.store
.lock()
.map(|s| s.keys().copied().collect())
.unwrap_or_default()
}
}
impl<T> Default for HandleStore<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for HandleStore<T> {
fn drop(&mut self) {
if let Ok(store) = self.store.lock() {
let count = store.len();
if count > 0 {
#[cfg(debug_assertions)]
eprintln!(
"[HandleStore] Warning: {} unreleased handles at drop time",
count
);
}
}
}
}
use std::sync::LazyLock;
pub static CONTEXTS: LazyLock<HandleStore<context::Context>> = LazyLock::new(HandleStore::new);
pub static BUFFERS: LazyLock<HandleStore<buffer::Buffer>> = LazyLock::new(HandleStore::new);
pub static STREAMS: LazyLock<HandleStore<stream::Stream>> = LazyLock::new(HandleStore::new);
pub static PIXMAPS: LazyLock<HandleStore<pixmap::Pixmap>> = LazyLock::new(HandleStore::new);
pub static DOCUMENTS: LazyLock<HandleStore<document::Document>> = LazyLock::new(HandleStore::new);