use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use dashmap::DashMap;
use tree_sitter::{Language, Parser, Tree};
use crate::parser::ParserError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ContentHash(u64);
impl ContentHash {
#[must_use]
pub fn of(source: &[u8]) -> Self {
let mut hasher = DefaultHasher::new();
source.hash(&mut hasher);
Self(hasher.finish())
}
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
}
#[derive(Default, Clone)]
pub struct ParseCache {
entries: Arc<DashMap<(String, ContentHash), Arc<Tree>>>,
}
impl ParseCache {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn parse(
&self,
language_name: &str,
language: &Language,
source: &[u8],
) -> Result<Arc<Tree>, ParserError> {
let key = (language_name.to_owned(), ContentHash::of(source));
if let Some(existing) = self.entries.get(&key) {
return Ok(existing.clone());
}
let mut parser = Parser::new();
parser
.set_language(language)
.map_err(|_| ParserError::UnknownExtension(language_name.to_owned()))?;
let Some(tree) = parser.parse(source, None) else {
return Err(ParserError::UnknownExtension(language_name.to_owned()));
};
let arc = Arc::new(tree);
self.entries.insert(key, arc.clone());
Ok(arc)
}
pub fn clear(&self) {
self.entries.clear();
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl std::fmt::Debug for ParseCache {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParseCache")
.field("entries", &self.entries.len())
.finish()
}
}