use crate::{SnapshotLock, SnapshotLockReadGuard, SnapshotLockWriteGuard};
use arc_swap::ArcSwap;
use async_lock::{RwLock, RwLockWriteGuard};
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub type AsyncSnapshotLock<T> = SnapshotLock<T, RwLock<(T, usize)>>;
impl<T: Clone> SnapshotLock<T, RwLock<(T, usize)>> {
pub fn new_async(inner: T) -> Self {
Self {
inner: RwLock::new((inner.clone(), 0)),
latest: ArcSwap::new(Arc::new(inner)),
latest_version: AtomicUsize::new(0),
}
}
pub async fn write(&self) -> SnapshotLockWriteGuard<'_, T, RwLockWriteGuard<'_, (T, usize)>> {
let mut guard = self.inner.write().await;
guard.1 += 1; SnapshotLockWriteGuard(guard, PhantomData)
}
pub fn read(&self) -> SnapshotLockReadGuard<T> {
if let Some(read) = self.inner.try_read() {
let (data, version) = read.deref();
if self.latest_version.swap(*version, Ordering::Acquire) < *version {
self.latest.store(Arc::new(data.clone()));
}
}
SnapshotLockReadGuard(arc_swap::Guard::into_inner(self.latest.load()))
}
}