use std::{collections::HashMap, sync::LazyLock};
use omp_core::{CowBytes, Str};
use parking_lot::Mutex;
use crate::imagefmt::{self, ImageDimensions};
#[derive(Clone)]
pub struct InternedImage {
pub(crate) id: u32,
pub(crate) png: CowBytes<'static>,
pub(crate) dimensions: ImageDimensions,
}
#[derive(Default)]
struct Registry {
by_source: HashMap<Str, Option<InternedImage>>,
by_id: HashMap<u32, CowBytes<'static>>,
allocated: u32,
}
static IMAGES: LazyLock<Mutex<Registry>> = LazyLock::new(|| Mutex::new(Registry::default()));
pub fn intern(source: &str) -> Option<InternedImage> {
let mut registry = IMAGES.lock();
if let Some(cached) = registry.by_source.get(source) {
return cached.clone();
}
let interned = load(source, registry.allocated);
if interned.is_some() {
registry.allocated += 1;
}
registry
.by_source
.insert(Str::from(source), interned.clone());
if let Some(entry) = &interned {
registry.by_id.insert(entry.id, entry.png.clone());
}
interned
}
pub fn bytes(id: u32) -> Option<CowBytes<'static>> {
let registry = IMAGES.lock();
registry.by_id.get(&id).cloned()
}
fn load(source: &str, allocated: u32) -> Option<InternedImage> {
let id = 0x00ff_ffff_u32.checked_sub(allocated)?;
let png = std::fs::read(source).ok()?;
if !png.starts_with(b"\x89PNG\r\n\x1a\n") {
return None;
}
let dimensions = imagefmt::dimensions(&png)?;
Some(InternedImage { id, png: CowBytes::from(png), dimensions })
}