use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, RwLock, RwLockWriteGuard};
pub(crate) struct LiveStore<S> {
inner: RwLock<Arc<S>>,
epoch: AtomicU64,
}
impl<S> LiveStore<S> {
pub(crate) fn new(value: Arc<S>) -> Self {
Self {
inner: RwLock::new(value),
epoch: AtomicU64::new(1),
}
}
pub(crate) fn load_full(&self) -> Arc<S> {
Arc::clone(&*self.inner.read().unwrap_or_else(|p| p.into_inner()))
}
pub(crate) fn load_full_with_epoch(&self) -> (Arc<S>, u64) {
let guard = self.inner.read().unwrap_or_else(|p| p.into_inner());
let snapshot = Arc::clone(&*guard);
let epoch = self.epoch.load(Ordering::Acquire);
(snapshot, epoch)
}
pub(crate) fn store(&self, value: Arc<S>) {
let mut guard = self.inner.write().unwrap_or_else(|p| p.into_inner());
*guard = value;
self.epoch.fetch_add(1, Ordering::Release);
}
}
impl<S: Clone> LiveStore<S> {
pub(crate) fn write(&self) -> WriteHandle<'_, S> {
let guard = self.inner.write().unwrap_or_else(|p| p.into_inner());
WriteHandle {
guard,
epoch: &self.epoch,
}
}
}
pub(crate) struct WriteHandle<'a, S> {
guard: RwLockWriteGuard<'a, Arc<S>>,
epoch: &'a AtomicU64,
}
impl<S: Clone> WriteHandle<'_, S> {
pub(crate) fn as_mut(&mut self) -> &mut S {
Arc::make_mut(&mut *self.guard)
}
pub(crate) fn snapshot(&self) -> Arc<S> {
Arc::clone(&*self.guard)
}
}
impl<S> Drop for WriteHandle<'_, S> {
fn drop(&mut self) {
self.epoch.fetch_add(1, Ordering::Release);
}
}