use crate::crdt::causal::VClock;
use crate::crdt::delta::DeltaCrdt;
use crate::crdt::replica::{generate_replica_id, ReplicaId};
use crate::crdt::Merge;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RGADelta<T> {
pub nodes: Vec<RgaNode<T>>,
pub timestamp: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RgaId {
pub timestamp: u64,
pub replica: ReplicaId,
}
impl RgaId {
fn new(timestamp: u64, replica: ReplicaId) -> Self {
Self { timestamp, replica }
}
}
impl Ord for RgaId {
fn cmp(&self, other: &Self) -> Ordering {
match self.timestamp.cmp(&other.timestamp) {
Ordering::Equal => self.replica.cmp(&other.replica),
ord => ord,
}
}
}
impl PartialOrd for RgaId {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RgaNode<T> {
pub id: RgaId,
pub value: T,
pub deleted: bool,
pub parent: Option<RgaId>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RGA<T> {
nodes: Vec<RgaNode<T>>,
timestamp: u64,
replica_id: ReplicaId,
}
impl<T: Clone + PartialEq> RGA<T> {
pub fn new(replica_id: ReplicaId) -> Self {
Self {
nodes: Vec::new(),
timestamp: 0,
replica_id,
}
}
pub fn new_random() -> Self {
Self::new(generate_replica_id())
}
pub fn append(&mut self, value: T) {
self.timestamp += 1;
let id = RgaId::new(self.timestamp, self.replica_id);
let parent = self.last_visible_id();
self.nodes.push(RgaNode {
id,
value,
deleted: false,
parent,
});
}
pub fn insert_before(&mut self, index: usize, value: T) {
if index == 0 {
self.timestamp += 1;
let id = RgaId::new(self.timestamp, self.replica_id);
self.nodes.push(RgaNode {
id,
value,
deleted: false,
parent: None,
});
} else {
self.insert_after(index - 1, value);
}
}
pub fn insert_after(&mut self, index: usize, value: T) {
let parent_id = self.visible_id_at(index);
self.timestamp += 1;
let id = RgaId::new(self.timestamp, self.replica_id);
self.nodes.push(RgaNode {
id,
value,
deleted: false,
parent: parent_id,
});
}
pub fn remove(&mut self, index: usize) {
if let Some(id) = self.visible_id_at(index) {
if let Some(node) = self.nodes.iter_mut().find(|n| n.id == id) {
node.deleted = true;
}
}
}
pub fn get(&self, index: usize) -> Option<&T> {
self.visible_nodes().nth(index).map(|n| &n.value)
}
pub fn len(&self) -> usize {
self.visible_nodes().count()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn to_vec(&self) -> Vec<T> {
self.visible_nodes().map(|n| n.value.clone()).collect()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.visible_nodes().map(|n| &n.value)
}
fn visible_nodes(&self) -> impl Iterator<Item = &RgaNode<T>> {
self.sorted_nodes()
.into_iter()
.filter(|n| !n.deleted)
}
fn sorted_nodes(&self) -> Vec<&RgaNode<T>> {
let mut children_map: HashMap<Option<RgaId>, Vec<&RgaNode<T>>> = HashMap::new();
for node in &self.nodes {
children_map.entry(node.parent).or_default().push(node);
}
for children in children_map.values_mut() {
children.sort_by(|a, b| b.id.cmp(&a.id));
}
let mut result: Vec<&RgaNode<T>> = Vec::new();
let mut stack: Vec<&RgaNode<T>> = Vec::new();
if let Some(heads) = children_map.get(&None) {
for node in heads.iter().rev() {
stack.push(node);
}
}
while let Some(node) = stack.pop() {
result.push(node);
if let Some(children) = children_map.get(&Some(node.id)) {
for child in children.iter().rev() {
stack.push(child);
}
}
}
result
}
fn last_visible_id(&self) -> Option<RgaId> {
self.sorted_nodes()
.into_iter()
.filter(|n| !n.deleted)
.last()
.map(|n| n.id)
}
fn visible_id_at(&self, index: usize) -> Option<RgaId> {
self.visible_nodes().nth(index).map(|n| n.id)
}
}
impl<T: Clone + PartialEq> Merge for RGA<T> {
fn merge(&mut self, other: &Self) {
self.timestamp = self.timestamp.max(other.timestamp);
for other_node in &other.nodes {
let exists = self.nodes.iter().any(|n| n.id == other_node.id);
if !exists {
self.nodes.push(other_node.clone());
} else {
if let Some(my_node) = self.nodes.iter_mut().find(|n| n.id == other_node.id) {
if other_node.deleted {
my_node.deleted = true;
}
}
}
}
}
}
impl<T: Clone + PartialEq + Serialize + DeserializeOwned + Send + 'static> DeltaCrdt for RGA<T> {
type Delta = RGADelta<T>;
fn delta_since(&self, since: &VClock) -> Option<Self::Delta> {
let current = self.version();
if since.dominates(¤t) {
return None;
}
Some(RGADelta {
nodes: self.nodes.clone(),
timestamp: self.timestamp,
})
}
fn apply_delta(&mut self, delta: &Self::Delta) {
self.timestamp = self.timestamp.max(delta.timestamp);
for delta_node in &delta.nodes {
let exists = self.nodes.iter().any(|n| n.id == delta_node.id);
if !exists {
self.nodes.push(delta_node.clone());
} else if let Some(my_node) = self.nodes.iter_mut().find(|n| n.id == delta_node.id) {
if delta_node.deleted {
my_node.deleted = true;
}
}
}
}
fn version(&self) -> VClock {
let mut clock = VClock::new();
for node in &self.nodes {
let current = clock.get(node.id.replica);
if node.id.timestamp > current {
for _ in current..node.id.timestamp {
clock.increment(node.id.replica);
}
}
}
clock
}
}
impl<T: Clone + PartialEq> Default for RGA<T> {
fn default() -> Self {
Self::new_random()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rga_append() {
let mut seq: RGA<String> = RGA::new(1);
seq.append("a".to_string());
seq.append("b".to_string());
assert_eq!(seq.to_vec(), vec!["a", "b"]);
}
#[test]
fn test_rga_insert_before() {
let mut seq: RGA<String> = RGA::new(1);
seq.append("b".to_string());
seq.insert_before(0, "a".to_string());
assert_eq!(seq.to_vec(), vec!["a", "b"]);
}
#[test]
fn test_rga_remove() {
let mut seq: RGA<String> = RGA::new(1);
seq.append("a".to_string());
seq.append("b".to_string());
seq.remove(0);
assert_eq!(seq.to_vec(), vec!["b"]);
}
#[test]
fn test_rga_concurrent_append() {
let mut a: RGA<String> = RGA::new(1);
let mut b: RGA<String> = RGA::new(2);
a.append("from-a".to_string());
b.append("from-b".to_string());
a.merge(&b);
b.merge(&a);
assert_eq!(a.to_vec(), b.to_vec());
}
}