use std::sync::Arc;
use arc_swap::ArcSwap;
use imbl::HashMap;
type PtrMap = HashMap<String, Arc<str>, foldhash::fast::RandomState>;
#[derive(Debug)]
pub(crate) struct PointerSnapshot {
pub(crate) generation: u64,
map: PtrMap,
}
impl PointerSnapshot {
fn get(&self, key: &str) -> Option<Arc<str>> {
self.map.get(key).cloned()
}
}
#[derive(Clone)]
pub(crate) struct PointerCache {
inner: Arc<ArcSwap<PointerSnapshot>>,
}
impl PointerCache {
pub(crate) fn from_entries(entries: impl IntoIterator<Item = (String, String)>) -> Self {
let map: PtrMap = entries
.into_iter()
.map(|(k, v)| (k, Arc::from(v.as_str())))
.collect();
Self {
inner: Arc::new(ArcSwap::from_pointee(PointerSnapshot {
generation: 0,
map,
})),
}
}
pub(crate) fn get(&self, key: &str) -> Option<Arc<str>> {
self.inner.load().get(key)
}
pub(crate) fn generation(&self) -> u64 {
self.inner.load().generation
}
pub(crate) fn insert(&self, key: &str, loc: &str) {
self.mutate(|m| {
m.insert(key.to_string(), Arc::from(loc));
});
}
pub(crate) fn remove(&self, key: &str) {
self.mutate(|m| {
m.remove(key);
});
}
fn mutate(&self, f: impl FnOnce(&mut PtrMap)) {
let cur = self.inner.load();
let mut map = cur.map.clone();
f(&mut map);
self.inner.store(Arc::new(PointerSnapshot {
generation: cur.generation + 1,
map,
}));
}
}
impl std::fmt::Debug for PointerCache {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let snap = self.inner.load();
f.debug_struct("PointerCache")
.field("generation", &snap.generation)
.field("entries", &snap.map.len())
.finish()
}
}