use std::collections::HashMap;
use std::sync::{Arc, Mutex, MutexGuard};
use crate::Problem;
use crate::fonts::FontFile;
use crate::parse::{self, File};
use crate::scene::{Files, ImageFile};
#[derive(Clone, Default)]
pub struct Parses(Arc<Mutex<HashMap<String, Arc<File>>>>);
impl Parses {
fn lock(&self) -> MutexGuard<'_, HashMap<String, Arc<File>>> {
self.0
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
pub fn holds(&self, path: &str) -> bool {
self.lock().contains_key(path)
}
pub fn forget(&self, path: &str) {
self.lock().remove(path);
}
}
pub struct Remembering<F> {
pub files: F,
parses: Parses,
}
impl<F> Remembering<F> {
pub fn new(files: F) -> Remembering<F> {
Remembering::with(files, &Parses::default())
}
pub fn with(files: F, parses: &Parses) -> Remembering<F> {
Remembering {
files,
parses: parses.clone(),
}
}
}
impl<F: Files> Files for Remembering<F> {
fn bytes(&self, path: &str) -> Option<Vec<u8>> {
self.files.bytes(path)
}
fn list(&self, path: &str) -> Option<Vec<String>> {
self.files.list(path)
}
fn read(&self, path: &str) -> Option<String> {
self.files.read(path)
}
fn parse(&self, path: &str, source: &str) -> Result<Arc<File>, Problem> {
let fresh = parse::parse(source)?;
let mut last = self.parses.lock();
let file = Arc::new(match last.get(path) {
Some(last) => super::matched(fresh, last),
None => fresh,
});
last.insert(path.to_string(), file.clone());
Ok(file)
}
fn image(&self, path: &str) -> Option<Result<Arc<ImageFile>, String>> {
self.files.image(path)
}
fn font(&self, path: &str) -> Option<Result<Arc<FontFile>, String>> {
self.files.font(path)
}
}