use std::ops::{Deref, DerefMut};
use matrix_sdk_base::event_cache::store::{
EventCacheStoreLock, EventCacheStoreLockGuard, EventCacheStoreLockState,
};
use tokio::sync::{Mutex, RwLock, RwLockWriteGuard};
use super::super::Result;
pub struct StateLock<S> {
locked_state: RwLock<S>,
state_lock_upgrade_mutex: Mutex<()>,
}
impl<S> StateLock<S> {
pub fn new_inner(state: S) -> Self {
Self { locked_state: RwLock::new(state), state_lock_upgrade_mutex: Mutex::new(()) }
}
pub async fn read<'a>(&'a self) -> Result<StateLockReadGuard<'a, S>>
where
S: Store,
StateLockWriteGuard<'a, S>: Reload,
{
let _state_lock_upgrade_guard = self.state_lock_upgrade_mutex.lock().await;
let state_guard = self.locked_state.read().await;
match state_guard.store().lock().await? {
EventCacheStoreLockState::Clean(store_guard) => {
Ok(StateLockReadGuard { state: state_guard, store: store_guard })
}
EventCacheStoreLockState::Dirty(store_guard) => {
drop(state_guard);
let state_guard = self.locked_state.write().await;
let mut guard = StateLockWriteGuard { state: state_guard, store: store_guard };
guard.reload().await?;
EventCacheStoreLockGuard::clear_dirty(&guard.store);
let guard = guard.downgrade();
Ok(guard)
}
}
}
pub async fn write<'a>(&'a self) -> Result<StateLockWriteGuard<'a, S>>
where
S: Store,
StateLockWriteGuard<'a, S>: Reload,
{
let state_guard = self.locked_state.write().await;
match state_guard.store().lock().await? {
EventCacheStoreLockState::Clean(store_guard) => {
Ok(StateLockWriteGuard { state: state_guard, store: store_guard })
}
EventCacheStoreLockState::Dirty(store_guard) => {
let mut guard = StateLockWriteGuard { state: state_guard, store: store_guard };
guard.reload().await?;
EventCacheStoreLockGuard::clear_dirty(&guard.store);
Ok(guard)
}
}
}
}
pub struct StateLockReadGuard<'a, S> {
pub state: tokio::sync::RwLockReadGuard<'a, S>,
pub store: EventCacheStoreLockGuard,
}
impl<'a, S> Deref for StateLockReadGuard<'a, S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.state
}
}
pub struct StateLockWriteGuard<'a, S> {
pub state: RwLockWriteGuard<'a, S>,
pub store: EventCacheStoreLockGuard,
}
impl<'a, S> Deref for StateLockWriteGuard<'a, S> {
type Target = S;
fn deref(&self) -> &Self::Target {
&self.state
}
}
impl<'a, S> DerefMut for StateLockWriteGuard<'a, S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state
}
}
impl<'a, S> StateLockWriteGuard<'a, S> {
fn downgrade(self) -> StateLockReadGuard<'a, S> {
StateLockReadGuard { state: self.state.downgrade(), store: self.store }
}
}
pub trait Store {
fn store(&self) -> &EventCacheStoreLock;
}
pub trait Reload {
async fn reload(&mut self) -> Result<()>;
}