use ruma::{OwnedTransactionId, TransactionId};
#[derive(Debug)]
pub struct LazyTransactionId {
txn_id: Option<OwnedTransactionId>,
}
impl LazyTransactionId {
pub fn new() -> Self {
Self { txn_id: None }
}
pub fn get_or_create(&mut self) -> &TransactionId {
self.txn_id.get_or_insert_with(TransactionId::new)
}
pub fn get(&self) -> Option<&TransactionId> {
self.txn_id.as_deref()
}
}
#[cfg(test)]
impl LazyTransactionId {
pub fn from_owned(owned: OwnedTransactionId) -> Self {
Self { txn_id: Some(owned) }
}
}
pub trait StickyData {
type Request;
fn apply(&self, request: &mut Self::Request);
fn on_commit(&mut self) {
}
}
#[derive(Debug)]
pub struct SlidingSyncStickyManager<D: StickyData> {
data: D,
invalidated: bool,
txn_id: Option<OwnedTransactionId>,
}
impl<D: StickyData> SlidingSyncStickyManager<D> {
pub fn new(data: D) -> Self {
Self { data, txn_id: None, invalidated: true }
}
pub fn data_mut(&mut self) -> &mut D {
self.invalidated = true;
&mut self.data
}
pub fn data(&self) -> &D {
&self.data
}
pub fn maybe_apply(&mut self, req: &mut D::Request, txn_id: &mut LazyTransactionId) {
if self.invalidated {
let txn_id = txn_id.get_or_create();
self.txn_id = Some(txn_id.to_owned());
self.data.apply(req);
}
}
pub fn maybe_commit(&mut self, txn_id: &TransactionId) {
if self.invalidated && self.txn_id.as_deref() == Some(txn_id) {
self.invalidated = false;
self.data.on_commit();
}
}
#[cfg(test)]
pub fn is_invalidated(&self) -> bool {
self.invalidated
}
}
#[cfg(test)]
mod tests {
use super::{LazyTransactionId, SlidingSyncStickyManager, StickyData};
struct EmptyStickyData(u8);
impl StickyData for EmptyStickyData {
type Request = bool;
fn apply(&self, req: &mut Self::Request) {
*req = true;
}
fn on_commit(&mut self) {
self.0 += 1;
}
}
#[test]
fn test_sticky_parameters_api_non_invalidated_no_effect() {
let mut sticky = SlidingSyncStickyManager::new(EmptyStickyData(0));
assert!(sticky.is_invalidated());
let mut applied = false;
let mut txn_id = LazyTransactionId::new();
sticky.maybe_apply(&mut applied, &mut txn_id);
assert!(applied);
assert!(sticky.is_invalidated());
assert!(txn_id.get().is_some(), "a transaction id was lazily generated");
sticky.maybe_commit("tid456".into());
assert_eq!(sticky.data.0, 0);
assert!(sticky.is_invalidated());
sticky.maybe_commit(txn_id.get().unwrap());
assert_eq!(sticky.data.0, 1);
assert!(!sticky.is_invalidated());
let mut txn_id = LazyTransactionId::new();
let mut applied = false;
sticky.maybe_apply(&mut applied, &mut txn_id);
assert!(!applied);
assert!(!sticky.is_invalidated());
assert!(txn_id.get().is_none());
}
}