use crate::util::hash128;
use kurbo::Affine;
use pdf_syntax::object::{Array, Dict, MaybeRef, Name, Null, ObjRef, Object, Stream};
use std::any::Any;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::{Arc, Mutex};
type CacheMap = HashMap<u128, Option<Box<dyn Any + Send + Sync>>>;
#[derive(Clone)]
pub(crate) struct Cache(Arc<Mutex<CacheMap>>);
impl Default for Cache {
fn default() -> Self {
Self::new()
}
}
impl Cache {
pub(crate) fn new() -> Self {
Self(Arc::new(Mutex::new(HashMap::new())))
}
pub(crate) fn get_or_insert_with<T: Clone + Send + Sync + 'static>(
&self,
id: u128,
f: impl FnOnce() -> Option<T>,
) -> Option<T> {
let mut locked = self.0.lock().unwrap();
match locked.entry(id) {
Entry::Occupied(o) => o
.get()
.as_ref()
.and_then(|val| val.downcast_ref::<T>().cloned()),
Entry::Vacant(_) => {
drop(locked);
let val = f();
self.0.lock().unwrap().insert(
id,
val.clone()
.map(|val| Box::new(val) as Box<dyn Any + Send + Sync>),
);
val
}
}
}
}
pub trait CacheKey {
fn cache_key(&self) -> u128;
}
impl<T: CacheKey, U: CacheKey> CacheKey for (T, U) {
fn cache_key(&self) -> u128 {
hash128(&(self.0.cache_key(), self.1.cache_key()))
}
}
impl CacheKey for Dict<'_> {
fn cache_key(&self) -> u128 {
hash128(self.data())
}
}
impl CacheKey for Stream<'_> {
fn cache_key(&self) -> u128 {
self.dict().cache_key()
}
}
impl CacheKey for Null {
fn cache_key(&self) -> u128 {
hash128(self)
}
}
impl CacheKey for bool {
fn cache_key(&self) -> u128 {
hash128(self)
}
}
impl CacheKey for pdf_syntax::object::Number {
fn cache_key(&self) -> u128 {
hash128(&self.as_f64().to_bits())
}
}
impl CacheKey for pdf_syntax::object::String {
fn cache_key(&self) -> u128 {
hash128(self.as_ref())
}
}
impl CacheKey for Name {
fn cache_key(&self) -> u128 {
hash128(self)
}
}
impl CacheKey for Array<'_> {
fn cache_key(&self) -> u128 {
hash128(self.data())
}
}
impl CacheKey for Object<'_> {
fn cache_key(&self) -> u128 {
match self {
Object::Null(n) => n.cache_key(),
Object::Boolean(b) => b.cache_key(),
Object::Number(n) => n.cache_key(),
Object::String(s) => s.cache_key(),
Object::Name(n) => n.cache_key(),
Object::Dict(d) => d.cache_key(),
Object::Array(a) => a.cache_key(),
Object::Stream(s) => s.cache_key(),
}
}
}
impl CacheKey for ObjRef {
fn cache_key(&self) -> u128 {
hash128(self)
}
}
impl<T: CacheKey> CacheKey for MaybeRef<T> {
fn cache_key(&self) -> u128 {
match self {
Self::Ref(r) => r.cache_key(),
Self::NotRef(o) => o.cache_key(),
}
}
}
impl CacheKey for Affine {
fn cache_key(&self) -> u128 {
let c = self.as_coeffs();
hash128(&[
c[0].to_bits(),
c[1].to_bits(),
c[2].to_bits(),
c[3].to_bits(),
c[4].to_bits(),
c[5].to_bits(),
])
}
}
impl CacheKey for u128 {
fn cache_key(&self) -> u128 {
hash128(self)
}
}