#[cfg(test)]
#[path = "../../tests/cache/value.rs"]
mod tests;
use std::sync::Arc;
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(any(feature = "client", all(test, feature = "server")))] {
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::sync::Weak;
use arc_swap::ArcSwap;
use crate::cache::common::CacheError;
}
}
#[cfg(any(feature = "client", all(test, feature = "server")))]
pub(crate) struct SharedValue<T: Clone + Send + Sync> {
state: Arc<ArcSwap<T>>,
shared: Arc<T>,
local: Arc<T>,
_not_sync: PhantomData<UnsafeCell<()>>,
}
#[cfg(any(feature = "client", all(test, feature = "server")))]
impl<T: Clone + Send + Sync> SharedValue<T> {
#[inline]
pub(crate) fn new(value: T) -> Self {
let arc = Arc::new(value);
SharedValue {
state: Arc::new(ArcSwap::from(arc.clone())),
shared: arc.clone(),
local: arc,
_not_sync: PhantomData,
}
}
#[inline]
pub(crate) fn get(&mut self) -> &T {
self.refresh();
&self.local
}
#[inline]
pub(crate) fn get_mut(&mut self) -> &mut T {
self.refresh();
Arc::make_mut(&mut self.local)
}
#[inline]
pub(crate) fn set(&mut self, value: T) {
let arc = Arc::new(value);
self.shared = arc.clone();
self.local = arc.clone();
self.state.store(arc);
}
#[inline]
pub(crate) fn create_sibling(&self) -> SharedValue<T> {
let current = self.state.load_full();
SharedValue {
state: Arc::clone(&self.state),
shared: current.clone(),
local: current,
_not_sync: PhantomData,
}
}
#[inline]
pub(crate) fn create_cache(&self) -> CachedValue<T> {
let current = self.state.load_full();
CachedValue {
source: Arc::downgrade(&self.state),
shared: current.clone(),
local: current,
_not_sync: PhantomData,
}
}
#[inline]
fn refresh(&mut self) {
let current = self.state.load();
if !Arc::ptr_eq(&self.shared, ¤t) {
self.shared = Arc::clone(¤t);
self.local = Arc::clone(¤t);
}
}
}
#[cfg(any(feature = "client", all(test, feature = "server")))]
pub(crate) struct CachedValue<T: Clone + Send + Sync> {
source: Weak<ArcSwap<T>>,
shared: Arc<T>,
local: Arc<T>,
_not_sync: PhantomData<UnsafeCell<()>>,
}
#[cfg(any(feature = "client", all(test, feature = "server")))]
impl<T: Clone + Send + Sync> CachedValue<T> {
#[inline]
pub(crate) fn get_mut(&mut self) -> Result<&mut T, CacheError> {
self.refresh()?;
Ok(Arc::make_mut(&mut self.local))
}
#[inline]
pub(crate) fn derive<R, F>(&self, f: F) -> Result<DerivedValue<R>, CacheError>
where
T: 'static,
R: 'static,
F: Fn(&T) -> R + Send + Sync + 'static,
{
let state = self.source.upgrade().ok_or(CacheError::SourceDropped)?;
Ok(DerivedValue {
read: Arc::new(move || {
let guard = state.load();
f(&guard)
}),
})
}
#[inline]
pub(crate) fn create_sibling(&self) -> Result<CachedValue<T>, CacheError> {
let source = self.source.upgrade().ok_or(CacheError::SourceDropped)?;
let current = source.load_full();
Ok(CachedValue {
source: self.source.clone(),
shared: current.clone(),
local: current,
_not_sync: PhantomData,
})
}
#[inline]
fn refresh(&mut self) -> Result<(), CacheError> {
let source = self.source.upgrade().ok_or(CacheError::SourceDropped)?;
let current = source.load();
if !Arc::ptr_eq(&self.shared, ¤t) {
self.shared = Arc::clone(¤t);
self.local = Arc::clone(¤t);
}
Ok(())
}
}
pub struct DerivedValue<R> {
read: Arc<dyn Fn() -> R + Send + Sync>,
}
impl<R> DerivedValue<R> {
#[cfg(any(feature = "server", test))]
#[inline]
pub(crate) fn constant(value: R) -> Self
where
R: Clone + Send + Sync + 'static,
{
Self {
read: Arc::new(move || value.clone()),
}
}
#[inline]
pub fn get(&self) -> R {
(self.read)()
}
}
impl<R> Clone for DerivedValue<R> {
#[inline]
fn clone(&self) -> Self {
Self {
read: Arc::clone(&self.read),
}
}
}