use arc_swap::ArcSwap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use crate::CachedReader;
pub struct GenSwap<T> {
data: ArcSwap<T>,
generation: AtomicU64,
}
impl<T> GenSwap<T> {
#[inline]
pub fn new(initial: T) -> Self {
Self {
data: ArcSwap::from_pointee(initial),
generation: AtomicU64::new(0),
}
}
#[inline]
pub fn new_from_arc(initial: Arc<T>) -> Self {
Self {
data: ArcSwap::from(initial),
generation: AtomicU64::new(0),
}
}
#[inline]
pub fn update(&self, new_value: T) {
self.update_arc(Arc::new(new_value));
}
#[inline]
pub fn update_arc(&self, new_value: Arc<T>) {
self.data.store(new_value);
self.generation.fetch_add(1, Ordering::Release);
}
pub fn rcu<F>(&self, mut f: F)
where
F: FnMut(&T) -> T,
{
self.data.rcu(|current| {
let new_value = f(&**current);
Arc::new(new_value)
});
self.generation.fetch_add(1, Ordering::Release);
}
#[inline]
pub fn generation(&self) -> u64 {
self.generation.load(Ordering::Acquire)
}
#[inline]
pub fn load(&self) -> arc_swap::Guard<Arc<T>> {
self.data.load()
}
#[inline]
pub fn load_full(&self) -> Arc<T> {
self.data.load_full()
}
#[inline]
pub fn reader(self: &Arc<Self>) -> CachedReader<T> {
CachedReader::new(Arc::clone(self))
}
}
unsafe impl<T: Send + Sync> Send for GenSwap<T> {}
unsafe impl<T: Send + Sync> Sync for GenSwap<T> {}
impl<T> Default for GenSwap<T>
where
T: Default,
{
fn default() -> Self {
Self::new(T::default())
}
}
impl<T> From<T> for GenSwap<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}