use std::fmt::{self, Debug}; use dashmap::DashMap; use tracing::{info_span, instrument}; use super::{query, Content, ContentVersion, Dir, Query, VPath, VPathBuf}; pub struct Blake3ContentVersionCache { salt: Vec, inner: T, cache: DashMap, } impl Blake3ContentVersionCache { pub fn new(salt: Vec, inner: T) -> Self { Self { salt, inner, cache: DashMap::new(), } } } impl Blake3ContentVersionCache where T: Dir, { #[instrument(name = "Blake3ContentVersionCache::content_version", skip(self))] fn content_version(&self, path: &VPath) -> Option { self.cache.get(path).map(|x| x.clone()).or_else(|| { let _span = info_span!("cache_miss").entered(); let version = query::(&self.inner, path).map(|content| { let mut hasher = blake3::Hasher::new(); hasher.update(&self.salt); hasher.update(&content.bytes()); let hash = hasher.finalize().to_hex(); ContentVersion { string: format!("b3-{}", &hash[0..8]), } }); if let Some(version) = &version { self.cache.insert(path.to_owned(), version.clone()); } version }) } } impl Dir for Blake3ContentVersionCache where T: Dir, { fn query(&self, path: &VPath, query: &mut Query) { query.try_provide(|| self.content_version(path)); self.inner.query(path, query); } } impl fmt::Debug for Blake3ContentVersionCache where T: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Blake3ContentVersionCache({:?})", self.inner) } }