use std::path::Path;
use std::sync::Arc;
pub fn read_php_source(path: impl AsRef<Path>) -> std::io::Result<String> {
let bytes = std::fs::read(path)?;
Ok(match String::from_utf8(bytes) {
Ok(text) => text,
Err(e) => String::from_utf8_lossy(e.as_bytes()).into_owned(),
})
}
pub trait SourceProvider: Send + Sync {
fn read(&self, path: &str) -> Option<Arc<str>>;
fn prefetch(&self, _paths: &[String]) {}
fn clear_prefetch(&self) {}
}
#[derive(Default)]
pub struct FsSourceProvider {
prefetched: parking_lot::Mutex<rustc_hash::FxHashMap<String, Option<Arc<str>>>>,
}
impl FsSourceProvider {
pub fn new() -> Self {
Self::default()
}
}
impl SourceProvider for FsSourceProvider {
fn read(&self, path: &str) -> Option<Arc<str>> {
if let Some(text) = self.prefetched.lock().remove(path) {
return text;
}
read_php_source(path).ok().map(Arc::from)
}
fn prefetch(&self, paths: &[String]) {
use rayon::prelude::*;
let fetched: Vec<(String, Option<Arc<str>>)> = paths
.par_iter()
.map(|path| (path.clone(), read_php_source(path).ok().map(Arc::from)))
.collect();
self.prefetched.lock().extend(fetched);
}
fn clear_prefetch(&self) {
self.prefetched.lock().clear();
}
}