use std::sync::{Arc, RwLock};
struct CacheEntry<G> {
graph: Arc<G>,
generation: u64,
}
pub struct GenerationCache<G> {
inner: RwLock<Option<CacheEntry<G>>>,
}
impl<G> GenerationCache<G> {
pub fn new() -> Self {
GenerationCache {
inner: RwLock::new(None),
}
}
pub fn get_or_build<F, E>(&self, generation: u64, build: F) -> Result<Arc<G>, E>
where
F: FnOnce() -> Result<G, E>,
{
{
let guard = self.inner.read().unwrap();
if let Some(entry) = guard.as_ref()
&& entry.generation == generation
{
return Ok(Arc::clone(&entry.graph));
}
}
let graph = Arc::new(build()?);
*self.inner.write().unwrap() = Some(CacheEntry {
graph: Arc::clone(&graph),
generation,
});
Ok(graph)
}
pub fn invalidate(&self) {
*self.inner.write().unwrap() = None;
}
pub fn current_generation(&self) -> Option<u64> {
self.inner.read().unwrap().as_ref().map(|e| e.generation)
}
}
impl<G> Default for GenerationCache<G> {
fn default() -> Self {
Self::new()
}
}