use std::hash::{DefaultHasher, Hash, Hasher}; use scc::HashMap; use serde::de::{SeqAccess, Visitor}; use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; use crate::config::RenderConfig; use crate::post::PostMetadata; #[derive(Serialize, Deserialize, Clone)] pub struct CacheValue { pub metadata: PostMetadata, pub rendered: String, pub mtime: u64, config_hash: u64, } #[derive(Default, Clone)] pub struct Cache(HashMap); impl Cache { pub fn from_map(cache: HashMap) -> Self { Self(cache) } pub async fn lookup( &self, name: &str, mtime: u64, config: &RenderConfig, ) -> Option { match self.0.get_async(name).await { Some(entry) => { let cached = entry.get(); if mtime <= cached.mtime && { let mut hasher = DefaultHasher::new(); config.hash(&mut hasher); hasher.finish() } == cached.config_hash { Some(cached.clone()) } else { let _ = entry.remove(); None } } None => None, } } pub async fn lookup_metadata(&self, name: &str, mtime: u64) -> Option { match self.0.get_async(name).await { Some(entry) => { let cached = entry.get(); if mtime <= cached.mtime { Some(cached.metadata.clone()) } else { let _ = entry.remove(); None } } None => None, } } pub async fn insert( &self, name: String, metadata: PostMetadata, mtime: u64, rendered: String, config: &RenderConfig, ) -> Result<(), (String, (PostMetadata, String))> { let mut hasher = DefaultHasher::new(); config.hash(&mut hasher); let hash = hasher.finish(); let value = CacheValue { metadata, rendered, mtime, config_hash: hash, }; if self .0 .update_async(&name, |_, _| value.clone()) .await .is_none() { self.0 .insert_async(name, value) .await .map_err(|x| (x.0, (x.1.metadata, x.1.rendered))) } else { Ok(()) } } pub async fn remove(&self, name: &str) -> Option<(String, CacheValue)> { self.0.remove_async(name).await } #[inline(always)] pub fn into_inner(self) -> HashMap { self.0 } } impl Serialize for Cache { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let cache = self.clone().into_inner(); let mut seq = serializer.serialize_seq(Some(cache.len()))?; let mut entry = cache.first_entry(); while let Some(occupied) = entry { let key = occupied.key().clone(); let value = occupied.get().clone(); seq.serialize_element(&(key, value))?; entry = occupied.next(); } seq.end() } } impl<'de> Deserialize<'de> for Cache { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct CoolVisitor; impl<'de> Visitor<'de> for CoolVisitor { type Value = Cache; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "meow") } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let cache = match seq.size_hint() { Some(size) => HashMap::with_capacity(size), None => HashMap::new(), }; while let Some((key, value)) = seq.next_element::<(String, CacheValue)>()? { cache.insert(key, value).ok(); } Ok(Cache::from_map(cache)) } } deserializer.deserialize_seq(CoolVisitor) } }