use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone, Default)]
pub struct GCounter {
counts: HashMap<String, u64>,
}
impl GCounter {
pub fn new() -> Self {
Self::default()
}
pub fn increment(&mut self, host_id: &str, amount: u64) {
*self.counts.entry(host_id.to_string()).or_insert(0) += amount;
}
pub fn value(&self) -> u64 {
self.counts.values().sum()
}
pub fn merge(&mut self, other: &GCounter) {
for (host, count) in &other.counts {
let entry = self.counts.entry(host.clone()).or_insert(0);
*entry = (*entry).max(*count);
}
}
pub fn host_count(&self, host_id: &str) -> u64 {
self.counts.get(host_id).copied().unwrap_or(0)
}
}
#[derive(Debug, Clone)]
pub struct LwwRegister<T: Clone> {
value: T,
timestamp: u64,
writer: String,
}
impl<T: Clone + Default> Default for LwwRegister<T> {
fn default() -> Self {
Self {
value: T::default(),
timestamp: 0,
writer: String::new(),
}
}
}
impl<T: Clone> LwwRegister<T> {
pub fn new(value: T, timestamp: u64, writer: impl Into<String>) -> Self {
Self {
value,
timestamp,
writer: writer.into(),
}
}
pub fn update(&mut self, value: T, timestamp: u64, writer: impl Into<String>) {
if timestamp > self.timestamp {
self.value = value;
self.timestamp = timestamp;
self.writer = writer.into();
}
}
pub fn value(&self) -> &T {
&self.value
}
pub fn timestamp(&self) -> u64 {
self.timestamp
}
pub fn merge(&mut self, other: &LwwRegister<T>) {
if other.timestamp > self.timestamp {
self.value = other.value.clone();
self.timestamp = other.timestamp;
self.writer = other.writer.clone();
}
}
}
#[derive(Debug, Clone)]
pub struct OrSet<T: Clone + Eq + std::hash::Hash> {
elements: HashMap<T, HashSet<String>>,
tombstones: HashMap<T, HashSet<String>>,
}
impl<T: Clone + Eq + std::hash::Hash> Default for OrSet<T> {
fn default() -> Self {
Self {
elements: HashMap::new(),
tombstones: HashMap::new(),
}
}
}
impl<T: Clone + Eq + std::hash::Hash> OrSet<T> {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, element: T, tag: String) {
self.elements.entry(element).or_default().insert(tag);
}
pub fn remove(&mut self, element: &T) {
if let Some(tags) = self.elements.get(element) {
let tombstone_entry = self.tombstones.entry(element.clone()).or_default();
for tag in tags {
tombstone_entry.insert(tag.clone());
}
}
}
pub fn contains(&self, element: &T) -> bool {
if let Some(tags) = self.elements.get(element) {
let tombstones = self.tombstones.get(element);
tags.iter()
.any(|tag| tombstones.map_or(true, |ts| !ts.contains(tag)))
} else {
false
}
}
pub fn elements(&self) -> Vec<&T> {
self.elements.keys().filter(|e| self.contains(e)).collect()
}
pub fn merge(&mut self, other: &OrSet<T>) {
for (elem, tags) in &other.elements {
let entry = self.elements.entry(elem.clone()).or_default();
entry.extend(tags.iter().cloned());
}
for (elem, tags) in &other.tombstones {
let entry = self.tombstones.entry(elem.clone()).or_default();
entry.extend(tags.iter().cloned());
}
}
}