use core::fmt;
use core::iter::FromIterator;
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::{CmRDT, Dot, Identifier, OrdDot, VClock};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct List<T, A: Ord> {
seq: BTreeMap<Identifier<OrdDot<A>>, T>,
clock: VClock<A>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Op<T, A: Ord> {
Insert {
id: Identifier<OrdDot<A>>,
val: T,
},
Delete {
id: Identifier<OrdDot<A>>,
dot: Dot<A>,
},
}
impl<T, A: Ord + Clone + Eq> Op<T, A> {
pub fn id(&self) -> &Identifier<OrdDot<A>> {
match self {
Op::Insert { id, .. } | Op::Delete { id, .. } => id,
}
}
pub fn dot(&self) -> Dot<A> {
match self {
Op::Insert { id, .. } => id.value().clone().into(),
Op::Delete { dot, .. } => dot.clone(),
}
}
}
impl<T, A: Ord> Default for List<T, A> {
fn default() -> Self {
Self {
seq: Default::default(),
clock: Default::default(),
}
}
}
impl<T, A: Ord + Clone> List<T, A> {
pub fn new() -> Self {
Self::default()
}
pub fn insert_index(&self, mut ix: usize, val: T, actor: A) -> Op<T, A> {
ix = ix.min(self.seq.len());
let (prev, next) = match ix.checked_sub(1) {
Some(indices_to_drop) => {
let mut indices = self.seq.keys().skip(indices_to_drop);
(indices.next(), indices.next())
}
None => {
let mut indices = self.seq.keys();
(None, indices.next())
}
};
let dot = self.clock.inc(actor);
let id = Identifier::between(prev, next, dot.into());
Op::Insert { id, val }
}
pub fn append(&self, c: T, actor: A) -> Op<T, A> {
let ix = self.seq.len();
self.insert_index(ix, c, actor)
}
pub fn delete_index(&self, ix: usize, actor: A) -> Option<Op<T, A>> {
self.seq.keys().nth(ix).cloned().map(|id| {
let dot = self.clock.inc(actor);
Op::Delete { id, dot }
})
}
pub fn len(&self) -> usize {
self.seq.len()
}
pub fn is_empty(&self) -> bool {
self.seq.is_empty()
}
pub fn read<'a, C: FromIterator<&'a T>>(&'a self) -> C {
self.seq.values().collect()
}
pub fn read_into<C: FromIterator<T>>(self) -> C {
self.seq.into_values().collect()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.seq.values()
}
pub fn iter_entries(&self) -> impl Iterator<Item = (&Identifier<OrdDot<A>>, &T)> {
self.seq.iter()
}
pub fn position(&self, ix: usize) -> Option<&T> {
self.iter().nth(ix)
}
pub fn position_entry(&self, id: &Identifier<OrdDot<A>>) -> Option<usize> {
self.iter_entries()
.enumerate()
.find_map(|(ix, (ident, _))| if ident == id { Some(ix) } else { None })
}
pub fn get(&self, id: &Identifier<OrdDot<A>>) -> Option<&T> {
self.seq.get(id)
}
pub fn first(&self) -> Option<&T> {
self.first_entry().map(|(_, val)| val)
}
pub fn first_entry(&self) -> Option<(&Identifier<OrdDot<A>>, &T)> {
self.seq.iter().next()
}
pub fn last(&self) -> Option<&T> {
self.last_entry().map(|(_, val)| val)
}
pub fn last_entry(&self) -> Option<(&Identifier<OrdDot<A>>, &T)> {
self.seq.iter().next_back()
}
fn insert(&mut self, id: Identifier<OrdDot<A>>, val: T) {
self.seq.entry(id).or_insert(val);
}
fn delete(&mut self, id: &Identifier<OrdDot<A>>) {
self.seq.remove(id);
}
}
impl<T, A: Ord + Clone + fmt::Debug> CmRDT for List<T, A> {
type Op = Op<T, A>;
type Validation = crate::DotRange<A>;
fn validate_op(&self, op: &Self::Op) -> Result<(), Self::Validation> {
self.clock.validate_op(&op.dot())
}
fn apply(&mut self, op: Self::Op) {
let op_dot = op.dot();
if op_dot.counter <= self.clock.get(&op_dot.actor) {
return;
}
self.clock.apply(op_dot);
match op {
Op::Insert { id, val } => self.insert(id, val),
Op::Delete { id, .. } => self.delete(&id),
}
}
}
impl<T, A: Ord> IntoIterator for List<T, A> {
type Item = T;
type IntoIter = std::collections::btree_map::IntoValues<Identifier<OrdDot<A>>, T>;
fn into_iter(self) -> Self::IntoIter {
self.seq.into_values()
}
}