use std::hash::Hash;
use crate::bounds::{Key, Value};
use crate::clock::Timestamp;
use crate::entry::Entry;
use super::ReplicatedMap;
impl<K: Key + Hash, V: Value> ReplicatedMap<K, V> {
pub fn get_mut<F: FnOnce(Option<&mut V>)>(&self, k: &K, callback: F) {
let now = self.engine.clock_now();
let mut updated: Option<Entry<Timestamp, V>> = None;
let mut guard = self.engine.map.write();
guard.with_mut(k, |maybe_entry| {
if let Some(entry) = maybe_entry {
callback(entry.value_mut());
entry.stamp = now;
updated = Some(entry.clone());
} else {
callback(None);
}
});
if let Some(entry) = guard.get(k) {
let projected = entry.project();
self.engine.projection.write().insert(k.clone(), projected);
}
drop(guard);
if let Some(value) = updated {
self.engine.broadcast_update(k.clone(), value);
}
}
fn mutate_live<F: FnOnce(&mut V)>(&self, k: &K, callback: F) -> bool {
let now = self.engine.clock_now();
let mut updated: Option<Entry<Timestamp, V>> = None;
let mut guard = self.engine.map.write();
guard.with_mut(k, |maybe_entry| {
if let Some(entry) = maybe_entry {
if let Some(value) = entry.value_mut() {
callback(value);
entry.stamp = now;
updated = Some(entry.clone());
}
}
});
if updated.is_some() {
if let Some(entry) = guard.get(k) {
let projected = entry.project();
self.engine.projection.write().insert(k.clone(), projected);
}
}
drop(guard);
if let Some(value) = updated {
self.engine.broadcast_update(k.clone(), value);
true
} else {
false
}
}
#[must_use]
pub fn update<F: FnOnce(&mut V)>(&self, k: &K, f: F) -> bool {
self.mutate_live(k, f)
}
pub fn upsert<F: FnOnce(&mut V)>(&self, k: K, default: V, f: F) {
if !self.mutate_live(&k, f) {
self.insert(k, default);
}
}
pub fn get_or_insert_with<F: FnOnce() -> V>(&self, k: &K, f: F) -> V {
if let Some(value) = self.get(k) {
return value.clone();
}
let value = f();
self.insert(k.clone(), value.clone());
value
}
}